## Automatically generated incremental diff
## From:   linux-2.2.15-pre9
## To:     linux-2.2.15-pre10
## Robot:  $Id: make-incremental-diff,v 1.7 2001/12/04 05:19:54 hpa Exp $

diff -urN linux-2.2.15-pre9/Documentation/video4linux/CQcam.txt linux/Documentation/video4linux/CQcam.txt
--- linux-2.2.15-pre9/Documentation/video4linux/CQcam.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/video4linux/CQcam.txt	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,414 @@
+c-qcam - Connectix Color QuickCam video4linux kernel driver
+
+Copyright (C) 1999  Dave Forrest  <drf5n@virginia.edu>
+                    released under GNU GPL.
+
+1999-12-08 Dave Forrest, written with kernel version 2.2.12 in mind
+
+
+Table of Contents
+
+1.0 Introduction
+2.0 Compilation, Installation, and Configuration
+3.0 Troubleshooting
+4.0 Future Work / current work arounds
+9.0 Sample Program, v4lgrab
+10.0 Other Information
+
+
+1.0 Introduction
+
+  The file ../drivers/char/c-qcam.c is a device driver for the
+Logitech (nee Connectix) parallel port interface color CCD camera.
+This is a fairly inexpensive device for capturing images.  Logitech
+does not currently provide information for developers, but many people
+have engineered several solutions for non-Microsoft use of the Color
+Quickcam.
+
+1.1 Motivation
+
+  I spent a number of hours trying to get my camera to work, and I
+hope this document saves you some time.  My camera will not work with
+the 2.2.13 kernel as distributed, but with a few patches to the
+module, I was able to grab some frames. See 4.0, Future Work.
+
+
+
+2.0 Compilation, Installation, and Configuration
+
+  The c-qcam depends on parallel port support, video4linux, and the
+Color Quickcam.  It is also nice to have the parallel port readback
+support enabled. I enabled these as modules during the kernel
+configuration.  The appropriate flags are:
+
+    CONFIG_PRINTER       M    for lp.o, parport.o parport_pc.o modules
+    CONFIG_PNP_PARPORT   M for autoprobe.o IEEE1284 readback module
+    CONFIG_PRINTER_READBACK M for parport_probe.o IEEE1284 readback module
+    CONFIG_VIDEO_DEV     M    for videodev.o video4linux module
+    CONFIG_VIDEO_CQCAM   M    for c-qcam.o  Color Quickcam module 
+
+  With these flags, the kernel should compile and install the modules.
+To record and monitor the compilation, I use:
+
+ (make dep; \
+  make zlilo ; \
+  make modules; \
+  make modules_install ; 
+  depmod -a ) &>log &
+ less log  # then a capital 'F' to watch the progress
+  
+But that is my personal preference.
+
+2.2 Configuration
+ 
+  The configuration requires module configuration and device
+configuration.  I like kmod or kerneld process with the
+/etc/modules.conf file so the modules can automatically load/unload as
+they are used.  The video devices could already exist, be generated
+using MAKEDEV, or need to be created.  The following sections detail
+these procedures.
+
+
+2.1 Module Configuration  
+
+  Using modules requires a bit of work to install and pass the
+parameters.  Do read ../modules.txt, and understand that entries
+in /etc/modules.conf of:
+
+   alias parport_lowlevel parport_pc
+   alias parport_pc io=0x378 irq=none
+   alias char-major-81 videodev
+   alias char-major-81-0 c-qcam
+
+will cause the kmod/kerneld/modprobe to do certain things.  If you are
+using kmod or kerneld, then a request for a 'char-major-81-0' will cause
+the 'c-qcam' module to load.  If you have other video sources with
+modules, you might want to assign the different minor numbers to
+different modules.
+
+2.2 Device Configuration
+
+  At this point, we need to ensure that the device files exist.
+Video4linux used the /dev/video* files, and we want to attach the
+Quickcam to one of these.
+
+   ls -lad /dev/video*  # should produce a list of the video devices
+
+If the video devices do not exist, you can create them with:
+
+  su
+  cd /dev
+  for ii in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
+    mknod video$ii c 81 $ii   # char-major-81-[0-16]
+    chown root.root video$ii  # owned by root
+    chmod 600 video$ii        # read/writable by root only
+  done
+
+  Lots of people connect video0 to video and bttv, but you might want
+your c-qcam to mean something more:
+
+   ln -s video0 c-qcam  # make /dev/c-qcam a working file
+   ln -s c-qcam video   # make /dev/c-qcam your default video source
+
+  But these are conveniences.  The important part is to make the proper
+special character files with the right major and minor numbers.  All
+of the special device files are listed in ../devices.txt.  If you
+would like the c-qcam readable by non-root users, you will need to
+change the permissions.
+
+3.0 Troubleshooting
+
+  If the sample program below, v4lgrab, gives you output then
+everything is working.
+
+    v4lgrab | wc # should give you a count of characters
+
+  Otherwise, you have some problem.
+
+  The c-qcam is IEEE1284 compatible, so if you are using the proc file
+system (CONFIG_PROC_FS), the parallel printer support
+(CONFIG_PRINTER), the IEEE 1284 sytem,(CONFIG_PRINTER_READBACK), you
+should be able to read some identification from your quickcam with
+
+         modprobe -v parport
+         modprobe -v parport_probe
+         cat /proc/parport/PORTNUMBER/autoprobe
+Returns:
+  CLASS:MEDIA;
+  MODEL:Color QuickCam 2.0;
+  MANUFACTURER:Connectix;
+
+  A good response to this indicates that your color quickcam is alive
+and well.  A common problem is that the current driver does not
+reliably detect a c-qcam, even though one is attached.  In this case,
+
+     modprobe -v c-qcam     
+or
+     insmod -v c-qcam
+
+  Returns a message saying "Device or resource busy"  Development is
+currently underway, but a workaround is to patch the module to skip
+the detection code and attach to a defined port.  Check the
+video4linux mailing list and archive for more current information.
+
+3.1 Checklist:
+
+  Can you get an image?
+            v4lgrab >qcam.ppm ; wc qcam.ppm ; xv qcam.ppm
+
+  Is a working c-qcam connected to the port? 
+            grep ^ /proc/parport/?/autoprobe
+
+  Do the /dev/video* files exist?  
+            ls -lad /dev/video
+
+  Is the c-qcam module loaded?     
+            modprobe -v c-qcam ; lsmod
+
+  Does the camera work with alternate programs? cqcam, etc?
+
+
+
+
+4.0 Future Work / current workarounds
+
+  It is hoped that this section will soon become obsolete, but if it
+isn't, you might try patching the c-qcam module to add a parport=xxx
+option as in the bw-qcam module so you can specify the parallel port:
+
+       insmod -v c-qcam parport=0  
+
+And bypass the detection code, see ../../drivers/char/c-qcam.c and
+look for the 'qc_detect' code and call.
+
+  Note that there is work in progress to change the video4linux API,
+this work is documented at the video4linux2 site listed below.
+
+
+9.0 --- A sample program using v4lgrabber, 
+
+This program is a simple image grabber that will copy a frame from the
+first video device, /dev/video0 to standard output in portable pixmap
+format (.ppm)  Using this like: 'v4lgrab | convert - c-qcam.jpg'
+produced this picture of me at 
+    http://mug.sys.virginia.edu/~drf5n/extras/c-qcam.jpg
+
+-------------------- 8< ---------------- 8< -----------------------------
+
+/* Simple Video4Linux image grabber. */
+/*
+ *	Video4Linux Driver Test/Example Framegrabbing Program
+ *
+ *	Compile with:
+ *		gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
+ *      Use as:
+ *              v4lgrab >image.ppm
+ *
+ *	Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>  
+ *      Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c 
+ *      with minor modifications (Dave Forrest, drf5n@virginia.edu).
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#include <linux/types.h>
+#include <linux/videodev.h>
+
+#define FILE "/dev/video0"
+
+/* Stole this from tvset.c */
+
+#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b)                   \
+{                                                                       \
+        switch (format)                                                 \
+        {                                                               \
+                case VIDEO_PALETTE_GREY:                                \
+                        switch (depth)                                  \
+                        {                                               \
+                                case 4:                                 \
+                                case 6:                                 \
+                                case 8:                                 \
+                                        (r) = (g) = (b) = (*buf++ << 8);\
+                                        break;                          \
+                                                                        \
+                                case 16:                                \
+                                        (r) = (g) = (b) =               \
+                                                *((unsigned short *) buf);      \
+                                        buf += 2;                       \
+                                        break;                          \
+                        }                                               \
+                        break;                                          \
+                                                                        \
+                                                                        \
+                case VIDEO_PALETTE_RGB565:                              \
+                {                                                       \
+                        unsigned short tmp = *(unsigned short *)buf;    \
+                        (r) = tmp&0xF800;                               \
+                        (g) = (tmp<<5)&0xFC00;                          \
+                        (b) = (tmp<<11)&0xF800;                         \
+                        buf += 2;                                       \
+                }                                                       \
+                break;                                                  \
+                                                                        \
+                case VIDEO_PALETTE_RGB555:                              \
+                        (r) = (buf[0]&0xF8)<<8;                         \
+                        (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8;    \
+                        (b) = ((buf[1] << 2 ) & 0xF8)<<8;               \
+                        buf += 2;                                       \
+                        break;                                          \
+                                                                        \
+                case VIDEO_PALETTE_RGB24:                               \
+                        (r) = buf[0] << 8; (g) = buf[1] << 8;           \
+                        (b) = buf[2] << 8;                              \
+                        buf += 3;                                       \
+                        break;                                          \
+                                                                        \
+                default:                                                \
+                        fprintf(stderr,                                 \
+                                "Format %d not yet supported\n",        \
+                                format);                                \
+        }                                                               \
+}                                               
+
+int get_brightness_adj(unsigned char *image, long size, int *brightness) {
+  long i, tot = 0;
+  for (i=0;i<size*3;i++)
+    tot += image[i];
+  *brightness = (128 - tot/(size*3))/3;
+  return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
+}
+
+int main(int argc, char ** argv)
+{
+  int fd = open(FILE, O_RDONLY), f;
+  struct video_capability cap;
+  struct video_window win;
+  struct video_picture vpic;
+
+  unsigned char *buffer, *src;
+  int bpp = 24, r, g, b;
+  unsigned int i, src_depth;
+
+  if (fd < 0) {
+    perror(FILE);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
+    perror("VIDIOGCAP");
+    fprintf(stderr, "(" FILE " not a video4linux device?)\n");
+    close(fd);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
+    perror("VIDIOCGWIN");
+    close(fd);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
+    perror("VIDIOCGPICT");
+    close(fd);
+    exit(1);
+  }
+
+  if (cap.type & VID_TYPE_MONOCHROME) {
+    vpic.depth=8;
+    vpic.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
+    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+      vpic.depth=6;
+      if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+        vpic.depth=4;
+        if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+          fprintf(stderr, "Unable to find a supported capture format.\n");
+          close(fd);
+          exit(1);
+        }
+      }
+    }
+  } else {
+    vpic.depth=24;
+    vpic.palette=VIDEO_PALETTE_RGB24;
+    
+    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+      vpic.palette=VIDEO_PALETTE_RGB565;
+      vpic.depth=16;
+      
+      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+        vpic.palette=VIDEO_PALETTE_RGB555;
+        vpic.depth=15;
+        
+        if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+          fprintf(stderr, "Unable to find a supported capture format.\n");
+          return -1;
+        }
+      }
+    }
+  }
+  
+  buffer = malloc(win.width * win.height * bpp);
+  if (!buffer) {
+    fprintf(stderr, "Out of memory.\n");
+    exit(1);
+  }
+  
+  do {
+    int newbright;
+    read(fd, buffer, win.width * win.height * bpp);
+    f = get_brightness_adj(buffer, win.width * win.height, &newbright);
+    if (f) {
+      vpic.brightness += (newbright << 8);
+      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+        perror("VIDIOSPICT");
+        break;
+      }
+    }
+  } while (f);
+
+  fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
+
+  src = buffer;
+
+  for (i = 0; i < win.width * win.height; i++) {
+    READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
+    fputc(r>>8, stdout);
+    fputc(g>>8, stdout);
+    fputc(b>>8, stdout);
+  }
+    
+  close(fd);
+  return 0;
+}
+-------------------- 8< ---------------- 8< -----------------------------
+
+
+10.0 --- Other Information
+
+Use the ../../Maintainers file, particularly the  VIDEO FOR LINUX and PARALLEL
+PORT SUPPORT sections
+
+The video4linux page:
+  http://roadrunner.swansea.linux.org.uk/v4l.shtml
+
+The video4linux2 page:
+  http://millennium.diads.com/bdirks/v4l2.htm
+
+Some web pages about the quickcams:
+   http://www.dkfz-heidelberg.de/Macromol/wedemann/mini-HOWTO-cqcam.html
+
+   http://www.crynwr.com/qcpc/            QuickCam Third-Party Drivers
+   http://www.crynwr.com/qcpc/re.html     Some Reverse Engineering
+   http://cse.unl.edu/~cluening/gqcam/    v4l client
+   http://phobos.illtel.denver.co.us/pub/qcread/ doesn't use v4l
+   ftp://ftp.cs.unm.edu/pub/chris/quickcam/   Has lots of drivers
+   http://www.cs.duke.edu/~reynolds/quickcam/ Has lots of information
+
+
diff -urN linux-2.2.15-pre9/Makefile linux/Makefile
--- linux-2.2.15-pre9/Makefile	Mon Dec  3 21:59:48 2001
+++ linux/Makefile	Mon Dec  3 21:59:54 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 15
-EXTRAVERSION = pre9
+EXTRAVERSION = pre10
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -200,6 +200,10 @@
 
 ifeq ($(CONFIG_IRDA),y)
 DRIVERS := $(DRIVERS) drivers/net/irda/irda_drivers.a
+endif
+
+ifeq ($(CONFIG_I2O),y)
+DRIVERS := $(DRIVERS) drivers/i2o/i2o.a
 endif
 
 ifeq ($(CONFIG_PHONE),y)
diff -urN linux-2.2.15-pre9/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.2.15-pre9/arch/i386/config.in	Mon Dec  3 21:59:48 2001
+++ linux/arch/i386/config.in	Mon Dec  3 21:59:54 2001
@@ -138,6 +138,8 @@
 fi
 endmenu
 
+source drivers/i2o/Config.in
+
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
   comment 'Network device support'
diff -urN linux-2.2.15-pre9/arch/s390/boot/Makefile linux/arch/s390/boot/Makefile
--- linux-2.2.15-pre9/arch/s390/boot/Makefile	Mon Dec  3 21:59:48 2001
+++ linux/arch/s390/boot/Makefile	Mon Dec  3 21:59:54 2001
@@ -26,6 +26,7 @@
 image: $(CONFIGURE) $(TOPDIR)/vmlinux \
 	iplfba.boot ipleckd.boot 
 	$(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
+	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aU] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
 
 listing: ../../../vmlinux
 	$(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing
diff -urN linux-2.2.15-pre9/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c
--- linux-2.2.15-pre9/arch/s390/kernel/s390_ksyms.c	Mon Dec  3 21:59:48 2001
+++ linux/arch/s390/kernel/s390_ksyms.c	Mon Dec  3 21:59:54 2001
@@ -7,20 +7,60 @@
 #include <linux/module.h>
 #include <asm/irq.h>
 #include <asm/string.h>
+#include <asm/checksum.h>
 
+/*
+ * I/O subsystem
+ */
+EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(do_IO);
+EXPORT_SYMBOL(resume_IO);
+EXPORT_SYMBOL(ioinfo);
 EXPORT_SYMBOL(get_dev_info_by_irq);
 EXPORT_SYMBOL(get_dev_info_by_devno);
 EXPORT_SYMBOL(get_irq_by_devno);
 EXPORT_SYMBOL(get_devno_by_irq);
 EXPORT_SYMBOL(get_irq_first);
 EXPORT_SYMBOL(get_irq_next);
-EXPORT_SYMBOL(halt_IO);
-EXPORT_SYMBOL(resume_IO);
-EXPORT_SYMBOL(do_IO);
-EXPORT_SYMBOL(memset);
+
+/*
+ * memory management
+ */
 EXPORT_SYMBOL(init_mm);
 EXPORT_SYMBOL(_oi_bitmap);
 EXPORT_SYMBOL(_ni_bitmap);
 EXPORT_SYMBOL(_zb_findmap);
+
+/*
+ * string functions
+ */
+EXPORT_SYMBOL_NOVERS(memcmp);
+EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(strchr);
+EXPORT_SYMBOL_NOVERS(strcmp);
+EXPORT_SYMBOL_NOVERS(strncat);
+EXPORT_SYMBOL_NOVERS(strncmp);
+EXPORT_SYMBOL_NOVERS(strncpy);
+EXPORT_SYMBOL_NOVERS(strnlen);
+EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strpbrk);
+
+/*
+ * misc.
+ */
+#ifdef __SMP__
+#include <asm/smplock.h>
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(kernel_flag);
+#endif
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(ioinfo);
+EXPORT_SYMBOL(synchronize_bh);
+EXPORT_SYMBOL(csum_fold);
+
+
diff -urN linux-2.2.15-pre9/drivers/Makefile linux/drivers/Makefile
--- linux-2.2.15-pre9/drivers/Makefile	Tue Jan  4 10:12:13 2000
+++ linux/drivers/Makefile	Mon Dec  3 21:59:54 2001
@@ -10,7 +10,7 @@
 SUB_DIRS     := block char net misc sound
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp \
-				macintosh video dio zorro fc4 usb telephony
+				macintosh video dio zorro fc4 usb telephony i2o
 
 ifdef CONFIG_DIO
 SUB_DIRS += dio
@@ -118,6 +118,16 @@
   MOD_SUB_DIRS += telephony
   endif
 endif
+
+ifeq ($(CONFIG_I2O),y)
+SUB_DIRS += i2o
+MOD_SUB_DIRS += i2o
+else
+  ifeq ($(CONFIG_I2O),m)
+  MOD_SUB_DIRS += i2o
+  endif
+endif
+
 
 
 # When MOD_LIST_NAME is set, make will try to add $(MOD_SUB_DIRS).o to
diff -urN linux-2.2.15-pre9/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux-2.2.15-pre9/drivers/block/genhd.c	Tue Jan  4 10:12:14 2000
+++ linux/drivers/block/genhd.c	Mon Dec  3 21:59:54 2001
@@ -59,6 +59,7 @@
 
 extern int chr_dev_init(void);
 extern int blk_dev_init(void);
+extern int i2o_init(void);
 #ifdef CONFIG_BLK_DEV_DAC960
 extern void DAC960_Initialize(void);
 #endif
@@ -1464,6 +1465,9 @@
 	chr_dev_init();
 	blk_dev_init();
 	sti();
+#ifdef CONFIG_I2O
+	i2o_init();
+#endif
 #ifdef CONFIG_BLK_DEV_DAC960
 	DAC960_Initialize();
 #endif
diff -urN linux-2.2.15-pre9/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c
--- linux-2.2.15-pre9/drivers/cdrom/aztcd.c	Mon Aug 24 13:02:43 1998
+++ linux/drivers/cdrom/aztcd.c	Mon Dec  3 21:59:54 2001
@@ -1732,10 +1732,9 @@
 	               { printk("aztcd: no AZTECH CD-ROM drive found\n");
                          return -EIO;
 	               } 
-	            for (count = 0; count < AZT_TIMEOUT; count++); 
-	               { count=count*2;          /* delay a bit */
-	                 count=count/2;
-	               }                        
+	            
+	            for (count = 0; count < AZT_TIMEOUT; count++);
+	            
 	            if ((st=getAztStatus())==-1)
 	               { printk("aztcd: Drive Status Error Status=%x\n",st);
                          return -EIO;
diff -urN linux-2.2.15-pre9/drivers/char/bttv.c linux/drivers/char/bttv.c
--- linux-2.2.15-pre9/drivers/char/bttv.c	Tue Jan  4 10:12:14 2000
+++ linux/drivers/char/bttv.c	Mon Dec  3 21:59:54 2001
@@ -1455,6 +1455,7 @@
 {
 	unsigned int *ro, *re;
 	unsigned int *vbuf;
+	unsigned long flags;
 	
 	if(btv->fbuffer==NULL)
 	{
@@ -1506,6 +1507,9 @@
 	re=ro+2048;
         make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
 	/* bt848_set_risc_jmps(btv); */
+	
+	save_flags(flags);
+	cli();
         btv->frame_stat[mp->frame] = GBUFFER_GRABBING;
         if (btv->grabbing) {
 		btv->gfmt_next=palette2fmt[mp->format];
@@ -1529,6 +1533,7 @@
 		}
 		btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
         }
+        restore_flags(flags);
 	btor(3, BT848_CAP_CTL);
 	btor(3, BT848_GPIO_DMA_CTL);
 	/* interruptible_sleep_on(&btv->capq); */
diff -urN linux-2.2.15-pre9/drivers/char/buz.c linux/drivers/char/buz.c
--- linux-2.2.15-pre9/drivers/char/buz.c	Tue Jan  4 10:12:14 2000
+++ linux/drivers/char/buz.c	Mon Dec  3 21:59:54 2001
@@ -3167,13 +3167,17 @@
 			mdelay(10);
 			zr36060_reset(zr);
 			mdelay(10);
-			zr36060_sleep(zr, 1);
-			mdelay(10);
+//			zr36060_sleep(zr, 1);
+//			mdelay(10);
 	
 			/* display codec revision */
 			if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
 				printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
 			       zr->name, zr36060_read_8(zr, 0x023));
+			}
+			else if ((rev=zr36060_read_8(zr, 0x022)) == 0xA2) {
+				printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n",
+			       zr->name, zr36060_read_8(zr, 0x023));
 			} else {
 				printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev);
 				kfree((void *) zr->stat_com);
@@ -3205,8 +3209,8 @@
 			udelay(3000);
 			zr36060_reset(zr);
 			udelay(3000);
-			zr36060_sleep(zr, 1);
-			udelay(3000);
+//			zr36060_sleep(zr, 1);
+//			udelay(3000);
 
 			/* display codec revision */
 			if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
diff -urN linux-2.2.15-pre9/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c
--- linux-2.2.15-pre9/drivers/char/c-qcam.c	Mon Aug  9 12:04:39 1999
+++ linux/drivers/char/c-qcam.c	Mon Dec  3 21:59:54 2001
@@ -2,6 +2,18 @@
  *	Video4Linux Colour QuickCam driver
  *	Copyright 1997-1998 Philip Blundell <philb@gnu.org>
  *
+ *    Module parameters:
+ *
+ *	parport=0         -- parport0 becomes qcam1
+ *	parport=auto      -- probe all parports (default)
+ *	parport=2,0,1     -- parports 2,0,1 are tried in that order
+ *
+ * The parport parameter controls which parports will be scanned.
+ * Scanning all parports causes some printers to print a garbage page.
+ *       -- March 14, 1999  Billy Donahue <billy@escape.com> 
+ *      
+ *      detect=heartbeat  -- watches for changes in the status register
+ *      detect=none       -- do no detection, assume a camera      
  */
 
 #include <linux/module.h>
@@ -30,6 +42,9 @@
 	unsigned int bidirectional;
 };
 
+/* cameras maximum */
+#define MAX_CAMS 4
+
 /* The three possible QuickCam modes */
 #define QC_MILLIONS	0x18
 #define QC_BILLIONS	0x10
@@ -40,6 +55,22 @@
 #define QC_DECIMATION_2		2
 #define QC_DECIMATION_4		4
 
+/* several possible detection modes */
+enum DetectionModes {NONE, HEARTBEAT};  
+
+#ifdef MODULE
+MODULE_DESCRIPTION("Connectix Color Quickcam for video4linux");
+MODULE_PARM_DESC(parport,"parport=<auto|n[,n]...> for port detection method \n\
+detect=<none|heartbeat>  # for camera detection method");
+
+static char *parport[MAX_CAMS] = { NULL, };
+static char *detect  = { NULL, };
+MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "s");
+MODULE_PARM(detect,  "s");
+#endif
+
+
+
 static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
 {
 	/* note: the QC specs refer to the PCAck pin by voltage, not
@@ -153,25 +184,34 @@
 	return qcam_read_data(qcam);
 }
 
-static int qc_detect(struct qcam_device *qcam)
+static int qc_detect(struct qcam_device *qcam, enum DetectionModes detectmode)
 {
 	unsigned int stat, ostat, i, count = 0;
 
 	parport_write_control(qcam->pport, 0xc);
 
-	/* look for a heartbeat */
-	ostat = stat = parport_read_status(qcam->pport);
-	for (i=0; i<250; i++) 
-	{
-		mdelay(1);
-		stat = parport_read_status(qcam->pport);
-		if (ostat != stat) 
-		{
-			if (++count >= 3) return 1;
-			ostat = stat;
+	switch (detectmode) {
+	case HEARTBEAT: {	/* look for a heartbeat */
+	  ostat = stat = parport_read_status(qcam->pport);
+	  for (i=0; i<250; i++) 
+	    {
+	      mdelay(1);
+	      stat = parport_read_status(qcam->pport);
+	      if (ostat != stat) 
+		{
+		  if (++count >= 3) return 1;
+		  ostat = stat;
 		}
+	    }
+	  break;
+	}
+	case NONE: {
+	  return 1;
+	}
+	default : {
+	  printk(KERN_ERR "c-qcam/qc_detect: bad detectmode\n");
+	}
 	}
-
 	/* no (or flatline) camera, give up */
 	return 0;
 }
@@ -671,11 +711,10 @@
 	return q;
 }
 
-#define MAX_CAMS 4
 static struct qcam_device *qcams[MAX_CAMS];
 static unsigned int num_cams = 0;
 
-int init_cqcam(struct parport *port)
+int init_cqcam(struct parport *port, int detectmode)
 {
 	struct qcam_device *qcam;
 
@@ -693,7 +732,7 @@
 
 	qc_reset(qcam);
 	
-	if (qc_detect(qcam)==0)
+	if (qc_detect(qcam, detectmode)==0)
 	{
 		parport_release(qcam->pdev);
 		parport_unregister_device(qcam->pdev);
@@ -730,14 +769,54 @@
 #define BANNER "Connectix Colour Quickcam driver v0.02\n"
 
 #ifdef MODULE
+
 int init_module(void)
 {
+	int n;
 	struct parport *port;
+	enum DetectionModes detectmode = HEARTBEAT;
 
 	printk(BANNER);
 
+        if(detect != NULL )  { /* a detect=xx parameter */
+	  if ( strncmp(detect,"none",4) == 0)
+		      detectmode=NONE;
+	  else if (strncmp(detect,"heartbeat",9) == 0)
+			   detectmode=HEARTBEAT;
+	  else { 
+	    printk(KERN_ERR
+		   "c-qcam: bad detection mode \"detect=%s\"\n",
+		   detect);
+	    
+	  }
+
+	} 
+
+
+	if(parport[0] && strncmp(parport[0], "auto", 4)){
+		/* user gave parport parameters */
+		for(n=0; parport[n] && n<MAX_CAMS; n++){
+			char *ep;
+			unsigned long r;
+			r = simple_strtoul(parport[n], &ep, 0);
+			if(ep == parport[n]){
+				printk(KERN_ERR
+					"c-qcam: bad port specifier \"%s\"\n",
+					parport[n]);
+				continue;
+			}
+			for (port=parport_enumerate(); port; port=port->next){
+				if(r!=port->number)
+					continue;
+				init_cqcam(port,detectmode);
+				break;
+			}
+		}
+		return (num_cams)?0:-ENODEV;
+	} 
+	/* no parameter or "auto" */
 	for (port = parport_enumerate(); port; port=port->next)
-		init_cqcam(port);
+		init_cqcam(port,detectmode);
 
 	return (num_cams)?0:-ENODEV;
 }
@@ -756,7 +835,7 @@
 	printk(BANNER);
 
 	for (port = parport_enumerate(); port; port=port->next)
-		init_cqcam(port);
+		init_cqcam(port,HEARTBEAT);
 	return 0;
 }
 #endif
diff -urN linux-2.2.15-pre9/drivers/char/console.c linux/drivers/char/console.c
--- linux-2.2.15-pre9/drivers/char/console.c	Mon Dec  3 21:59:48 2001
+++ linux/drivers/char/console.c	Mon Dec  3 21:59:54 2001
@@ -506,6 +506,9 @@
 {
     if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
 	return;
+	
+    disable_bh(CONSOLE_BH);
+    
     if (deccm) {
 	if (currcons == sel_cons)
 		clear_selection();
@@ -514,6 +517,8 @@
 	    sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
     } else
 	hide_cursor(currcons);
+	
+    enable_bh(CONSOLE_BH);
 }
 
 static void set_origin(int currcons)
@@ -1812,11 +1817,12 @@
 	himask = hi_font_mask;
 	charmask = himask ? 0x1ff : 0xff;
 
+	disable_bh(CONSOLE_BH);
+
 	/* undraw cursor first */
 	if (IS_FG)
 		hide_cursor(currcons);
 
-	disable_bh(CONSOLE_BH);
 	while (!tty->stopped && count) {
 		enable_bh(CONSOLE_BH);
 		if (from_user)
diff -urN linux-2.2.15-pre9/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- linux-2.2.15-pre9/drivers/char/n_tty.c	Mon Dec  3 21:59:48 2001
+++ linux/drivers/char/n_tty.c	Mon Dec  3 21:59:54 2001
@@ -62,8 +62,6 @@
 #define TTY_THRESHOLD_THROTTLE		128 /* now based on remaining room */
 #define TTY_THRESHOLD_UNTHROTTLE 	128
 
-static spinlock_t __attribute((unused)) tty_put_lock = SPIN_LOCK_UNLOCKED;
-
 static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
 {
 	unsigned long flags;
@@ -71,13 +69,13 @@
 	 *	The problem of stomping on the buffers ends here.
 	 *	Why didn't anyone see this one comming? --AJK
 	*/
-	spin_lock_irqsave(&tty_put_lock, flags);
+	spin_lock_irqsave(&tty->read_lock, flags);
 	if (tty->read_cnt < N_TTY_BUF_SIZE) {
 		tty->read_buf[tty->read_head] = c;
 		tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
 		tty->read_cnt++;
 	}
-	spin_unlock_irqrestore(&tty_put_lock, flags);
+	spin_unlock_irqrestore(&tty->read_lock, flags);
 }
 
 /* 
@@ -100,7 +98,11 @@
  */
 static void reset_buffer_flags(struct tty_struct *tty)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&tty->read_lock, flags);
 	tty->read_head = tty->read_tail = tty->read_cnt = 0;
+	spin_unlock_irqrestore(&tty->read_lock, flags);
 	tty->canon_head = tty->canon_data = tty->erasing = 0;
 	memset(&tty->read_flags, 0, sizeof tty->read_flags);
 	check_unthrottle(tty);
@@ -128,14 +130,19 @@
  */
 ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
 {
-	if (tty->icanon) {
-		if (!tty->canon_data) return 0;
+	unsigned long flags;
+	ssize_t n = 0;
 
-		return (tty->canon_head > tty->read_tail) ?
+	spin_lock_irqsave(&tty->read_lock, flags);
+	if (!tty->icanon) {
+		n = tty->read_cnt;
+	} else if (tty->canon_data) {
+		n = (tty->canon_head > tty->read_tail) ?
 			tty->canon_head - tty->read_tail :
 			tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
 	}
-	return tty->read_cnt;
+	spin_unlock_irqrestore(&tty->read_lock, flags);
+	return n;
 }
 
 /*
@@ -297,6 +304,7 @@
 {
 	enum { ERASE, WERASE, KILL } kill_type;
 	int head, seen_alnums;
+	unsigned long flags;
 
 	if (tty->read_head == tty->canon_head) {
 		/* opost('\a', tty); */		/* what do you think? */
@@ -308,15 +316,19 @@
 		kill_type = WERASE;
 	else {
 		if (!L_ECHO(tty)) {
+			spin_lock_irqsave(&tty->read_lock, flags);
 			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
 					  (N_TTY_BUF_SIZE - 1));
 			tty->read_head = tty->canon_head;
+			spin_unlock_irqrestore(&tty->read_lock, flags);
 			return;
 		}
 		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
+			spin_lock_irqsave(&tty->read_lock, flags);
 			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
 					  (N_TTY_BUF_SIZE - 1));
 			tty->read_head = tty->canon_head;
+			spin_unlock_irqrestore(&tty->read_lock, flags);
 			finish_erasing(tty);
 			echo_char(KILL_CHAR(tty), tty);
 			/* Add a newline if ECHOK is on and ECHOKE is off. */
@@ -338,8 +350,10 @@
 			else if (seen_alnums)
 				break;
 		}
+		spin_lock_irqsave(&tty->read_lock, flags);
 		tty->read_head = head;
 		tty->read_cnt--;
+		spin_unlock_irqrestore(&tty->read_lock, flags);
 		if (L_ECHO(tty)) {
 			if (L_ECHOPRT(tty)) {
 				if (!tty->erasing) {
@@ -672,11 +686,13 @@
 	char *f, flags = TTY_NORMAL;
 	int	i;
 	char	buf[64];
+	unsigned long cpuflags;
 
 	if (!tty->read_buf)
 		return;
 
 	if (tty->real_raw) {
+		spin_lock_irqsave(&tty->read_lock, cpuflags);
 		i = MIN(count, MIN(N_TTY_BUF_SIZE - tty->read_cnt,
 				   N_TTY_BUF_SIZE - tty->read_head));
 		memcpy(tty->read_buf + tty->read_head, cp, i);
@@ -690,6 +706,7 @@
 		memcpy(tty->read_buf + tty->read_head, cp, i);
 		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
 		tty->read_cnt += i;
+		spin_unlock_irqrestore(&tty->read_lock, cpuflags);
 	} else {
 		for (i=count, p = cp, f = fp; i; i--, p++) {
 			if (f)
@@ -864,15 +881,20 @@
 {
 	int retval;
 	ssize_t n;
+	unsigned long flags;
 
 	retval = 0;
+	spin_lock_irqsave(&tty->read_lock, flags);
 	n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
+	spin_unlock_irqrestore(&tty->read_lock, flags);
 	if (n) {
 		mb();
 		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
 		n -= retval;
+		spin_lock_irqsave(&tty->read_lock, flags);
 		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
 		tty->read_cnt -= n;
+		spin_unlock_irqrestore(&tty->read_lock, flags);
 		*b += n;
 		*nr -= n;
 	}
@@ -889,6 +911,7 @@
 	ssize_t retval = 0;
 	ssize_t size;
 	long timeout;
+	unsigned long flags;
 
 do_it_again:
 
@@ -1007,9 +1030,11 @@
 				eol = test_and_clear_bit(tty->read_tail,
 						&tty->read_flags);
 				c = tty->read_buf[tty->read_tail];
+				spin_lock_irqsave(&tty->read_lock, flags);
 				tty->read_tail = ((tty->read_tail+1) &
 						  (N_TTY_BUF_SIZE-1));
 				tty->read_cnt--;
+				spin_unlock_irqrestore(&tty->read_lock, flags);
 
 				if (!eol || (c != __DISABLED_CHAR)) {
 					put_user(c, b++);
diff -urN linux-2.2.15-pre9/drivers/char/pty.c linux/drivers/char/pty.c
--- linux-2.2.15-pre9/drivers/char/pty.c	Sat Feb  6 17:28:37 1999
+++ linux/drivers/char/pty.c	Mon Dec  3 21:59:54 2001
@@ -168,7 +168,9 @@
 		}
 		up(&tty->flip.pty_sem);
 	} else {
-		c = MIN(count, to->ldisc.receive_room(to));
+		c = to->ldisc.receive_room(to);
+		if (c > count)
+			c = count;
 		to->ldisc.receive_buf(to, buf, 0, c);
 	}
 	
diff -urN linux-2.2.15-pre9/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.2.15-pre9/drivers/char/tty_io.c	Mon Dec  3 21:59:48 2001
+++ linux/drivers/char/tty_io.c	Mon Dec  3 21:59:54 2001
@@ -1943,6 +1943,7 @@
 	tty->tq_hangup.data = tty;
 	sema_init(&tty->atomic_read, 1);
 	sema_init(&tty->atomic_write, 1);
+	spin_lock_init(&tty->read_lock);
 }
 
 /*
diff -urN linux-2.2.15-pre9/drivers/i2o/Config.in linux/drivers/i2o/Config.in
--- linux-2.2.15-pre9/drivers/i2o/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/Config.in	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,10 @@
+mainmenu_option next_comment
+comment 'I2O device support'
+
+tristate 'I2O support' CONFIG_I2O
+
+dep_tristate '  I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O
+dep_tristate '  I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O
+dep_tristate '  I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O $CONFIG_SCSI
+
+endmenu
diff -urN linux-2.2.15-pre9/drivers/i2o/Makefile linux/drivers/i2o/Makefile
--- linux-2.2.15-pre9/drivers/i2o/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/Makefile	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,59 @@
+#
+# Makefile for the kernel I2O OSM.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+#
+# Note : at this point, these files are compiled on all systems.
+# In the future, some of these should be built conditionally.
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+
+L_TARGET := i2o.a
+L_OBJS   := 
+M_OBJS   :=
+
+ifeq ($(CONFIG_I2O_PCI),y)
+L_OBJS += i2o_pci.o
+else
+  ifeq ($(CONFIG_I2O_PCI),m)
+  MX_OBJS += i2o_pci.o
+  endif
+endif
+
+ifeq ($(CONFIG_I2O),y)
+LX_OBJS += i2o_core.o i2o_config.o
+else
+  ifeq ($(CONFIG_I2O),m)
+  MX_OBJS += i2o_core.o i2o_config.o
+  endif
+endif
+
+ifeq ($(CONFIG_I2O_BLOCK),y)
+LX_OBJS += i2o_block.o
+else
+  ifeq ($(CONFIG_I2O_BLOCK),m)
+  MX_OBJS += i2o_block.o
+  endif
+endif
+
+ifeq ($(CONFIG_I2O_SCSI),y)
+LX_OBJS += i2o_scsi.o
+else
+  ifeq ($(CONFIG_I2O_SCSI),m)
+  MX_OBJS += i2o_scsi.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
diff -urN linux-2.2.15-pre9/drivers/i2o/README linux/drivers/i2o/README
--- linux-2.2.15-pre9/drivers/i2o/README	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/README	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,98 @@
+
+	Linux I2O Support	(c) Copyright 1999 Red Hat Software
+					and others.
+
+	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.
+
+AUTHORS (so far)
+
+Alan Cox, Building Number Three Ltd.
+	Core code, SCSI and Block OSMs
+
+Steve Ralston, LSI Logic Corp.
+	Debugging SCSI and Block OSM
+
+Deepak Saxena, Intel Corp.
+	/proc interface, bug fixes
+	Ioctl interfaces for control
+	Debugging LAN OSM
+
+Philip Rumpf
+	Fixed assorted dumb SMP locking bugs
+
+Juha Sievanen, University of Helsinki Finland
+	LAN OSM code
+	/proc interface to LAN class
+	Bug fixes
+	Core code extensions
+
+Auvo Häkkinen, University of Helsinki Finland
+	LAN OSM code
+	/Proc interface to LAN class
+	Bug fixes
+	Core code extensions
+
+Taneli Vähäkangas, University of Helsinki Finland
+	Fixes to i2o_config
+
+CREDITS
+
+	This work was made possible by 
+
+Red Hat Software
+	Funding for the Building #3 part of the project
+
+Symbios Logic (Now LSI)
+	Host adapters, hints, known to work platforms when I hit
+	compatibility problems
+
+BoxHill Corporation
+	Loan of initial FibreChannel disk array used for development work.
+
+European Comission
+	Funding the work done by the University of Helsinki
+
+SysKonnect
+        Loan of FDDI and Gigabit Ethernet cards
+
+ASUSTeK
+        Loan of I2O motherboard 
+
+STATUS:
+
+o	The core setup works within limits.
+o	The scsi layer seems to almost work. I'm still chasing down the hang
+	bug.
+o	The block OSM is fairly minimal but does seem to work.
+o	LAN OSM works with FDDI and Ethernet cards.
+
+TO DO:
+
+General:
+o	Support multiple IOP's and tell them about each other
+o	Provide hidden address space if asked
+o	Long term message flow control
+o	PCI IOP's without interrupts are not supported yet
+o	Push FAIL handling into the core
+o	DDM control interfaces for module load etc
+o	Event handling
+
+Block:
+o	Real error handler
+o	Multiple major numbers
+o	Read ahead and cache handling stuff. Talk to Ingo and people
+o	Power management
+o	Finish Media changers
+
+SCSI:
+o	Find the right way to associate drives/luns/busses
+
+Lan:	Batch mode sends
+	Performance tuning
+	Event handling
+
+Tape:
+o	Anyone seen anything implementing this ?
diff -urN linux-2.2.15-pre9/drivers/i2o/README.ioctl linux/drivers/i2o/README.ioctl
--- linux-2.2.15-pre9/drivers/i2o/README.ioctl	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/README.ioctl	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,394 @@
+
+Linux I2O User Space Interface
+rev 0.3 - 04/20/99
+
+=============================================================================
+Originally written by Deepak Saxena(deepak@plexity.net)
+Currently maintained by Deepak Saxena(deepak@plexity.net)
+=============================================================================
+
+I. Introduction
+
+The Linux I2O subsystem provides a set of ioctl() commands that can be
+utilized by user space applications to communicate with IOPs and devices
+on individual IOPs. This document defines the specific ioctl() commands
+that are available to the user and provides examples of their uses.
+
+This document assumes the reader is familiar with or has access to the 
+I2O specification as no I2O message parameters are outlined.  For information 
+on the specification, see http://www.i2osig.org
+
+This document and the I2O user space interface are currently maintained
+by Deepak Saxena.  Please send all comments, errata, and bug fixes to
+deepak@plexity.net
+
+II. IOP Access
+
+Access to the I2O subsystem is provided through the device file named 
+/dev/i2octl.  This file is a character file with major number 10 and minor
+number 166.  It can be created through the following command:
+
+   mknod /dev/i2octl c 10 166
+
+III. Determining the IOP Count
+
+   SYNOPSIS 
+
+   ioctl(fd, I2OGETIOPS,  int *count);
+
+   u8 count[MAX_I2O_CONTROLLERS];
+
+   DESCRIPTION
+
+   This function returns the system's active IOP table.  count should
+   point to a buffer containing MAX_I2O_CONTROLLERS entries.  Upon 
+   returning, each entry will contain a non-zero value if the given
+   IOP unit is active, and NULL if it is inactive or non-existent.
+
+   RETURN VALUE.
+
+   Returns 0 if no errors occur, and -1 otherwise.  If an error occurs,
+   errno is set appropriately:
+
+     EFAULT   Invalid user space pointer was passed
+
+IV. Getting Hardware Resource Table
+
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt);
+
+      struct i2o_cmd_hrtlct
+      {
+         u32   iop;      /* IOP unit number */
+         void  *resbuf;  /* Buffer for result */
+         u32   *reslen;  /* Buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function returns the Hardware Resource Table of the IOP specified 
+   by hrt->iop in the buffer pointed to by hrt->resbuf. The actual size of 
+   the data is written into *(hrt->reslen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriately:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(hrt->reslen)
+  
+V. Getting Logical Configuration Table
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct);
+
+      struct i2o_cmd_hrtlct
+      {
+         u32   iop;      /* IOP unit number */
+         void  *resbuf;  /* Buffer for result */
+         u32   *reslen;  /* Buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function returns the Logical Configuration Table of the IOP specified
+   by lct->iop in the buffer pointed to by lct->resbuf. The actual size of 
+   the data is written into *(lct->reslen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriately:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(lct->reslen)
+
+VI. Settting Parameters
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops);
+
+      struct i2o_cmd_psetget
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device TID */
+         void  *opbuf;   /* Operation List buffer */
+         u32   oplen;    /* Operation List buffer length in bytes */
+         void  *resbuf;  /* Result List buffer */
+         u32   *reslen;  /* Result List buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts a UtilParamsSet message to the device identified
+   by ops->iop and ops->tid.  The operation list for the message is 
+   sent through the ops->opbuf buffer, and the result list is written
+   into the buffer pointed to by ops->resbuf.  The number of bytes 
+   written is placed into *(ops->reslen). 
+
+   RETURNS
+
+   The return value is the size in bytes of the data written into
+   ops->resbuf if no errors occur.  If an error occurs, -1 is returned 
+   and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+   A return value of 0 does not mean that the value was actually
+   changed properly on the IOP.  The user should check the result
+   list to determine the specific status of the transaction.
+
+VII. Getting Parameters
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops);
+
+      struct i2o_parm_setget
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device TID */
+         void  *opbuf;   /* Operation List buffer */
+         u32   oplen;    /* Operation List buffer length in bytes */
+         void  *resbuf;  /* Result List buffer */
+         u32   *reslen;  /* Result List buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts a UtilParamsGet message to the device identified
+   by ops->iop and ops->tid.  The operation list for the message is 
+   sent through the ops->opbuf buffer, and the result list is written
+   into the buffer pointed to by ops->resbuf.  The actual size of data
+   written is placed into *(ops->reslen).
+
+   RETURNS
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+   A return value of 0 does not mean that the value was actually
+   properly retreived.  The user should check the result list 
+   to determine the specific status of the transaction.
+
+VIII. Downloading Software
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;       /* IOP unit number */
+         u8    flags;     /* DownloadFlags field */
+         u8    sw_type;   /* Software type */
+         u32   sw_id;     /* Software ID */
+         void  *buf;      /* Pointer to software buffer */
+         u32   *swlen;    /* Length of software buffer */        
+         u32   *maxfrag;  /* Number of fragments */
+         u32   *curfrag;  /* Current fragment number */
+      };
+
+   DESCRIPTION
+
+   This function downloads a software fragment pointed by sw->buf
+   to the iop identified by sw->iop. The DownloadFlags, SwID, SwType
+   and SwSize fields of the ExecSwDownload message are filled in with
+   the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen).
+
+   The fragments _must_ be sent in order and be 8K in size. The last
+   fragment _may_ be shorter, however. The kernel will compute its
+   size based on information in the sw->swlen field.
+
+   Please note that SW transfers can take a long time.
+
+   RETURNS
+
+   This function returns 0 no errors occur. If an error occurs, -1 
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+IX. Uploading Software
+   
+   SYNOPSIS 
+
+   ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;      /* IOP unit number */
+         u8    flags; 	 /* UploadFlags */
+         u8    sw_type;  /* Software type */
+         u32   sw_id;    /* Software ID */
+         void  *buf;     /* Pointer to software buffer */
+         u32   *swlen;   /* Length of software buffer */        
+         u32   *maxfrag; /* Number of fragments */
+         u32   *curfrag; /* Current fragment number */
+      };
+
+   DESCRIPTION
+
+   This function uploads a software fragment from the IOP identified
+   by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields.
+   The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload
+   message are filled in with the values of sw->flags, sw->sw_id,
+   sw->sw_type and *(sw->swlen).
+
+   The fragments _must_ be requested in order and be 8K in size. The
+   user is responsible for allocating memory pointed by sw->buf. The
+   last fragment _may_ be shorter.
+
+   Please note that SW transfers can take a long time.
+
+   RETURNS
+
+   This function returns 0 if no errors occur.  If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+         
+X. Removing Software
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;      /* IOP unit number */
+         u8    flags; 	 /* RemoveFlags */
+         u8    sw_type;  /* Software type */
+         u32   sw_id;    /* Software ID */
+         void  *buf;     /* Unused */
+         u32   *swlen;   /* Length of the software data */        
+         u32   *maxfrag; /* Unused */
+         u32   *curfrag; /* Unused */
+      };
+
+   DESCRIPTION
+
+   This function removes software from the IOP identified by sw->iop.
+   The RemoveFlags, SwID, SwType and SwSize fields of the ExecSwRemove message 
+   are filled in with the values of sw->flags, sw->sw_id, sw->sw_type and 
+   *(sw->swlen). Give zero in *(sw->len) if the value is unknown. IOP uses 
+   *(sw->swlen) value to verify correct identication of the module to remove. 
+   The actual size of the module is written into *(sw->swlen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur.  If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+X. Validating Configuration
+
+   SYNOPSIS
+
+   ioctl(fd, I2OVALIDATE, int *iop);
+	u32 iop;
+
+   DESCRIPTION
+
+   This function posts an ExecConfigValidate message to the controller
+   identified by iop. This message indicates that the the current
+   configuration is accepted. The iop changes the status of suspect drivers 
+   to valid and may delete old drivers from its store.
+
+   RETURNS
+
+   This function returns 0 if no erro occur.  If an error occurs, -1 is
+   returned and errno is set appropriatly:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENXIO       Invalid IOP number
+
+XI. Configuration Dialog
+   
+   SYNOPSIS 
+ 
+   ioctl(fd, I2OHTML, struct i2o_html *htquery);
+      struct i2o_html
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device ID */
+         u32   page;     /* HTML page */
+         void  *resbuf;  /* Buffer for reply HTML page */
+         u32   *reslen;  /* Length in bytes of reply buffer */
+         void  *qbuf;    /* Pointer to HTTP query string */
+         u32   qlen;     /* Length in bytes of query string buffer */        
+      };
+
+   DESCRIPTION
+
+   This function posts an UtilConfigDialog message to the device identified
+   by htquery->iop and htquery->tid.  The requested HTML page number is 
+   provided by the htquery->page field, and the resultant data is stored 
+   in the buffer pointed to by htquery->resbuf.  If there is an HTTP query 
+   string that is to be sent to the device, it should be sent in the buffer
+   pointed to by htquery->qbuf.  If there is no query string, this field
+   should be set to NULL. The actual size of the reply received is written
+   into *(htquery->reslen).
+  
+   RETURNS
+
+   This function returns 0 if no error occur. If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+XII. Events
+
+    In the process of determining this.  Current idea is to have use
+    the select() interface to allow user apps to periodically poll
+    the /dev/i2octl device for events.  When select() notifies the user
+    that an event is available, the user would call read() to retrieve
+    a list of all the events that are pending for the specific device.
+
+=============================================================================
+Revision History
+=============================================================================
+
+Rev 0.1 - 04/01/99
+- Initial revision
+
+Rev 0.2 - 04/06/99
+- Changed return values to match UNIX ioctl() standard.  Only return values
+  are 0 and -1.  All errors are reported through errno.
+- Added summary of proposed possible event interfaces
+
+Rev 0.3 - 04/20/99
+- Changed all ioctls() to use pointers to user data instead of actual data
+- Updated error values to match the code
diff -urN linux-2.2.15-pre9/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- linux-2.2.15-pre9/drivers/i2o/i2o_block.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/i2o_block.c	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,1185 @@
+/*
+ *	I2O block device driver. 
+ *
+ *	(C) Copyright 1999   Red Hat Software
+ *	
+ *	Written by Alan Cox, Building Number Three 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 is a beta test release. Most of the good code was taken
+ *	from the nbd driver by Pavel Machek, who in turn took some of it
+ *	from loop.c. Isn't free software great for reusability 8)
+ *
+ *	Fixes:
+ *		Steve Ralston:	Multiple device handling error fixes,
+ *				Added a queue depth.
+ *		Alan Cox:	FC920 has an rmw bug. Dont or in the
+ *				end marker.
+ *				Removed queue walk, fixed for 64bitness.
+ *	To do:
+ *		Multiple majors
+ *		Serial number scanning to find duplicates for FC multipathing
+ *		Set the new max_sectors according to max message size
+ *		Use scatter gather chains for bigger I/O sizes
+ */
+
+#include <linux/major.h>
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/ioctl.h>
+#include <linux/i2o.h>
+#include <linux/blkdev.h>
+#include <linux/malloc.h>
+#include <linux/hdreg.h>
+
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+
+#define MAJOR_NR I2O_MAJOR
+
+#include <linux/blk.h>
+
+#define MAX_I2OB	16
+
+#define MAX_I2OB_DEPTH	32                
+#define MAX_I2OB_RETRIES 4
+
+/*
+ *	Some of these can be made smaller later
+ */
+
+static int i2ob_blksizes[MAX_I2OB<<4];
+static int i2ob_hardsizes[MAX_I2OB<<4];
+static int i2ob_sizes[MAX_I2OB<<4];
+static int i2ob_media_change_flag[MAX_I2OB];
+static u32 i2ob_max_sectors[MAX_I2OB<<4];
+
+static int i2ob_context;
+
+struct i2ob_device
+{
+	struct i2o_controller *controller;
+	struct i2o_device *i2odev;
+	int tid;
+	int flags;
+	int refcnt;
+	struct request *head, *tail;
+	int done_flag;
+};
+
+/*
+ *	FIXME:
+ *	We should cache align these to avoid ping-ponging lines on SMP
+ *	boxes under heavy I/O load...
+ */
+ 
+struct i2ob_request
+{
+	struct i2ob_request *next;
+	struct request *req;
+	int num;
+};
+
+
+/*
+ *	Each I2O disk is one of these.
+ */
+
+static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
+static int i2ob_devices = 0;
+static struct hd_struct i2ob[MAX_I2OB<<4];
+static struct gendisk i2ob_gendisk;	/* Declared later */
+
+static atomic_t queue_depth;		/* For flow control later on */
+static struct i2ob_request i2ob_queue[MAX_I2OB_DEPTH+1];
+static struct i2ob_request *i2ob_qhead;
+
+static struct timer_list i2ob_timer;
+static int i2ob_timer_started = 0;
+
+#define DEBUG( s )
+/* #define DEBUG( s ) printk( s ) 
+ */
+
+static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
+static void i2ob_end_request(struct request *);
+static void i2ob_request(struct request  * q);
+
+/*
+ * Dump messages.
+ */
+static void i2ob_dump_msg(struct i2ob_device *dev,u32 *msg,int size)
+{
+        int cnt;
+
+        printk(KERN_INFO "\n\ni2o message:\n");
+        for (cnt = 0; cnt<size; cnt++)
+        {
+                printk(KERN_INFO "m[%d]=%x\n",cnt,msg[cnt]);
+        }
+        printk(KERN_INFO "\n");
+}
+
+/*
+ *	Get a message
+ */
+
+static u32 i2ob_get(struct i2ob_device *dev)
+{
+	struct i2o_controller *c=dev->controller;
+   	return I2O_POST_READ32(c);
+}
+ 
+/*
+ *	Turn a Linux block request into an I2O block read/write.
+ */
+
+static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, u32 base, int unit)
+{
+	struct i2o_controller *c = dev->controller;
+	int tid = dev->tid;
+	unsigned long msg;
+	unsigned long mptr;
+	u64 offset;
+	struct request *req = ireq->req;
+	struct buffer_head *bh = req->bh;
+	int count = req->nr_sectors<<9;
+
+	/* Map the message to a virtual address */
+	msg = c->mem_offset + m;
+	
+	/*
+         * Build the message based on the request.
+	 */
+	writel(i2ob_context|(unit<<8), msg+8);
+	writel(ireq->num, msg+12);
+	writel(req->nr_sectors << 9, msg+20);
+	
+	/* This can be optimised later - just want to be sure its right for
+	   starters */
+	offset = ((u64)(req->sector+base)) << 9;
+	writel( offset & 0xFFFFFFFF, msg+24);
+	writel(offset>>32, msg+28);
+	mptr=msg+32;
+	
+	if(req->cmd == READ)
+	{
+		writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4);
+		/* We don't yet do cache/readahead and other magic */
+		writel(1<<16, msg+16);
+		while(bh!=NULL)
+		{
+			/*
+			 *	Its best to do this in one not or it in
+			 *	later. mptr is in PCI space so fast to write
+			 *	sucky to read.
+			 */
+			if(bh->b_reqnext)
+				writel(0x10000000|(bh->b_size), mptr);
+			else
+				writel(0xD0000000|(bh->b_size), mptr);
+	
+			writel(virt_to_bus(bh->b_data), mptr+4);
+			mptr+=8;
+			count -= bh->b_size;
+			bh = bh->b_reqnext;
+		}
+	}
+	else if(req->cmd == WRITE)
+	{
+		writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4);
+		writel(1<<16, msg+16);
+		while(bh!=NULL)
+		{
+			if(bh->b_reqnext)
+				writel(0x14000000|(bh->b_size), mptr);
+			else
+				writel(0xD4000000|(bh->b_size), mptr);
+			count -= bh->b_size;
+			writel(virt_to_bus(bh->b_data), mptr+4);
+			mptr+=8;
+			bh = bh->b_reqnext;
+		}
+	}
+	writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg);
+	
+	if(req->current_nr_sectors > 8)
+		printk("Gathered sectors %ld.\n", 
+			req->current_nr_sectors);
+			
+	if(count != 0)
+	{
+		printk(KERN_ERR "Request count botched by %d.\n", count);
+	}
+
+	i2o_post_message(c,m);
+	atomic_inc(&queue_depth);
+
+	return 0;
+}
+
+/*
+ *	Remove a request from the _locked_ request list. We update both the
+ *	list chain and if this is the last item the tail pointer. Caller
+ *	must hold the lock.
+ */
+ 
+static inline void i2ob_unhook_request(struct i2ob_request *ireq)
+{
+	ireq->next = i2ob_qhead;
+	i2ob_qhead = ireq;
+}
+
+/*
+ *	Request completion handler
+ */
+ 
+static void i2ob_end_request(struct request *req)
+{
+	/*
+	 * Loop until all of the buffers that are linked
+	 * to this request have been marked updated and
+	 * unlocked.
+	 */
+
+//	printk("ending request %p: ", req);
+	while (end_that_request_first( req, !req->errors, "i2o block" ))
+	{
+//		printk(" +\n");
+	}
+
+	/*
+	 * It is now ok to complete the request.
+	 */
+	
+//	printk("finishing ");
+	end_that_request_last( req );
+//	printk("done\n");
+}
+
+
+/*
+ *	OSM reply handler. This gets all the message replies
+ */
+
+static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
+{
+	unsigned long flags;
+	struct i2ob_request *ireq;
+	u8 st;
+	u32 *m = (u32 *)msg;
+	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
+	
+	if(m[0] & (1<<13))
+	{
+		printk("IOP fail.\n");
+		printk("From %d To %d Cmd %d.\n",
+			(m[1]>>12)&0xFFF,
+			m[1]&0xFFF,
+			m[1]>>24);
+		printk("Failure Code %d.\n", m[4]>>24);
+		if(m[4]&(1<<16))
+			printk("Format error.\n");
+		if(m[4]&(1<<17))
+			printk("Path error.\n");
+		if(m[4]&(1<<18))
+			printk("Path State.\n");
+		if(m[4]&(1<<18))
+			printk("Congestion.\n");
+		
+		m=(u32 *)bus_to_virt(m[7]);
+		printk("Failing message is %p.\n", m);
+		
+		/* We need to up the request failure count here and maybe
+		   abort it */
+		ireq=&i2ob_queue[m[3]];
+		/* Now flush the message by making it a NOP */
+		m[0]&=0x00FFFFFF;
+		m[0]|=(I2O_CMD_UTIL_NOP)<<24;
+		i2o_post_message(c,virt_to_bus(m));
+		
+	}
+	else
+	{
+		if(m[2]&0x40000000)
+		{
+			int * ptr = (int *)m[3];
+			if(m[4]>>24)
+				*ptr = -1;
+			else
+				*ptr = 1;
+			return;
+		}
+		/*
+		 *	Lets see what is cooking. We stuffed the
+		 *	request in the context.
+		 */
+		 
+		ireq=&i2ob_queue[m[3]];
+		st=m[4]>>24;
+	
+		if(st!=0)
+		{
+			printk(KERN_ERR "i2ob: error %08X\n", m[4]);
+			ireq->req->errors++;	
+			if (ireq->req->errors < MAX_I2OB_RETRIES)
+			{
+				u32 retry_msg;
+				struct i2ob_device *dev;
+
+  				printk(KERN_ERR "i2ob: attempting retry %d for request %p\n",ireq->req->errors+1,ireq->req);
+     				
+		                /* 
+				 * Get a message for this retry.
+				 */
+				dev = &i2ob_dev[(unit&0xF0)];
+                		retry_msg = i2ob_get(dev);
+
+                		/* 
+				 * If we cannot get a message then
+				 * forget the retry and fail the
+				 * request.   Note that since this is
+				 * being called from the interrupt 
+				 * handler, a request has just been 
+				 * completed and there will most likely 
+				 * be space on the inbound message
+				 * fifo so this won't happen often.
+				 */
+                		if(retry_msg!=0xFFFFFFFF)
+				{
+			                /*
+			                 * Decrement the queue depth since
+			                 * this request has completed and
+			                 * it will be incremented again when
+			                 * i2ob_send is called below.
+			                 */
+			                atomic_dec(&queue_depth);
+
+			                /*
+			                 * Send the request again.
+			                 */
+			                i2ob_send(retry_msg, dev,ireq,i2ob[unit].start_sect, (unit&0xF0));
+					/*
+					 * Don't fall through.
+					 */
+					return;
+				}
+			}		
+		}
+		else
+			ireq->req->errors = 0;
+	}
+		
+	/*
+	 *	Dequeue the request. We use irqsave locks as one day we
+	 *	may be running polled controllers from a BH...
+	 */
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	i2ob_unhook_request(ireq);
+	i2ob_end_request(ireq->req);
+	
+	/*
+	 *	We may be able to do more I/O
+	 */
+	 
+	atomic_dec(&queue_depth);
+	i2ob_request(NULL);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static struct i2o_handler i2o_block_handler =
+{
+	i2o_block_reply,
+	"I2O Block OSM",
+	0,
+	I2O_CLASS_RANDOM_BLOCK_STORAGE
+};
+
+/*
+ * The timer handler will attempt to restart requests 
+ * that are queued to the driver.  This handler
+ * currently only gets called if the controller
+ * had no more room in its inbound fifo.  
+ */
+
+static void i2ob_timer_handler(unsigned long dummy)
+{
+	unsigned long flags;
+
+	/*
+	 * We cannot touch the request queue or the timer
+         * flag without holding the io_request_lock.
+	 */
+	spin_lock_irqsave(&io_request_lock,flags);
+
+	/* 
+	 * Clear the timer started flag so that 
+	 * the timer can be queued again.
+	 */
+	i2ob_timer_started = 0;
+
+	/* 
+	 * Restart any requests.
+	 */
+	i2ob_request(NULL);
+
+	/* 
+	 * Free the lock.
+	 */
+	spin_unlock_irqrestore(&io_request_lock,flags);
+}
+
+/*
+ *	The I2O block driver is listed as one of those that pulls the
+ *	front entry off the queue before processing it. This is important
+ *	to remember here. If we drop the io lock then CURRENT will change
+ *	on us. We must unlink CURRENT in this routine before we return, if
+ *	we use it.
+ */
+
+static void i2ob_request(struct request * q)
+{
+	struct request *req;
+	struct i2ob_request *ireq;
+	int unit;
+	struct i2ob_device *dev;
+	u32 m;
+
+	while (CURRENT) {
+		/*
+		 *	On an IRQ completion if there is an inactive
+		 *	request on the queue head it means it isnt yet
+		 *	ready to dispatch.
+		 */
+		if(CURRENT->rq_status == RQ_INACTIVE)
+			return;
+			
+		/*
+		 *	Queue depths probably belong with some kind of
+		 *	generic IOP commit control. Certainly its not right
+		 *	its global!
+		 */
+		if(atomic_read(&queue_depth)>=MAX_I2OB_DEPTH)
+			break;
+
+		req = CURRENT;
+		unit = MINOR(req->rq_dev);
+		dev = &i2ob_dev[(unit&0xF0)];
+		/* Get a message */
+		m = i2ob_get(dev);
+
+		if(m==0xFFFFFFFF)
+		{
+			/* 
+			 * See if the timer has already been queued.
+			 */
+			if (!i2ob_timer_started)
+			{
+				printk(KERN_ERR "i2ob: starting timer\n");
+
+				/*
+				 * Set the timer_started flag to insure
+				 * that the timer is only queued once.
+				 * Queing it more than once will corrupt
+				 * the timer queue.
+				 */
+				i2ob_timer_started = 1;
+
+				/* 
+				 * Set up the timer to expire in
+				 * 500ms.
+				 */
+				i2ob_timer.expires = jiffies + (HZ >> 1);
+
+				/*
+				 * Start it.
+				 */
+				 
+				add_timer(&i2ob_timer);
+			}
+		}
+		req->errors = 0;
+		CURRENT = CURRENT->next;
+		req->sem = NULL;
+		
+		ireq = i2ob_qhead;
+		i2ob_qhead = ireq->next;
+		ireq->req = req;
+
+		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0));
+	}
+}
+
+/*
+ *	SCSI-CAM for ioctl geometry mapping
+ *	Duplicated with SCSI - this should be moved into somewhere common
+ *	perhaps genhd ?
+ */
+ 
+static void i2o_block_biosparam(
+	unsigned long capacity,
+	unsigned short *cyls,
+	unsigned char *hds,
+	unsigned char *secs) 
+{ 
+	unsigned long heads, sectors, cylinders, temp; 
+
+	cylinders = 1024L;			/* Set number of cylinders to max */ 
+	sectors = 62L;      			/* Maximize sectors per track */ 
+
+	temp = cylinders * sectors;		/* Compute divisor for heads */ 
+	heads = capacity / temp;		/* Compute value for number of heads */
+	if (capacity % temp) {			/* If no remainder, done! */ 
+    		heads++;                	/* Else, increment number of heads */ 
+    		temp = cylinders * heads;	/* Compute divisor for sectors */ 
+    		sectors = capacity / temp;	/* Compute value for sectors per
+						       track */ 
+	    	if (capacity % temp) {		/* If no remainder, done! */ 
+			sectors++;                  /* Else, increment number of sectors */ 
+	      		temp = heads * sectors;	/* Compute divisor for cylinders */
+	      		cylinders = capacity / temp;/* Compute number of cylinders */ 
+		} 
+	} 
+	/* if something went wrong, then apparently we have to return
+	   a geometry with more than 1024 cylinders */
+	if (cylinders == 0 || heads > 255 || sectors > 63 || cylinders >1023) 
+	{
+		unsigned long temp_cyl;
+		
+		heads = 64;
+		sectors = 32;
+		temp_cyl = capacity / (heads * sectors);
+		if (temp_cyl > 1024) 
+		{
+			heads = 255;
+			sectors = 63;
+		}
+		cylinders = capacity / (heads * sectors);
+	}
+	*cyls = (unsigned int) cylinders;	/* Stuff return values */ 
+	*secs = (unsigned int) sectors; 
+	*hds  = (unsigned int) heads; 
+} 
+
+/*
+ *	Rescan the partition tables
+ */
+ 
+static int do_i2ob_revalidate(kdev_t dev, int maxu)
+{
+	int minor=MINOR(dev);
+	int i;
+	
+	minor&=0xF0;
+	
+	i2ob_dev[minor].refcnt++;
+	if(i2ob_dev[minor].refcnt>maxu+1)
+	{
+		i2ob_dev[minor].refcnt--;
+		return -EBUSY;
+	}
+	
+	for( i = 15; i>=0 ; i--)
+	{
+		int m = minor+i;
+		kdev_t d = MKDEV(MAJOR_NR, m);
+		struct super_block *sb = get_super(d);
+		
+		sync_dev(d);
+		if(sb)
+			invalidate_inodes(sb);
+		invalidate_buffers(d);
+		i2ob_gendisk.part[m].start_sect = 0;
+		i2ob_gendisk.part[m].nr_sects = 0;
+	}
+
+	/*
+	 *	Do a physical check and then reconfigure
+	 */
+	 
+	i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev,
+		minor);
+	i2ob_dev[minor].refcnt--;
+	return 0;
+}
+
+/*
+ *	Issue device specific ioctl calls.
+ */
+
+static int i2ob_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct i2ob_device *dev;
+	int minor;
+
+	/* Anyone capable of this syscall can do *real bad* things */
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!inode)
+		return -EINVAL;
+	minor = MINOR(inode->i_rdev);
+	if (minor >= (MAX_I2OB<<4))
+		return -ENODEV;
+
+	dev = &i2ob_dev[minor];
+	switch (cmd) {
+		case BLKRASET:
+			if(!capable(CAP_SYS_ADMIN))  return -EACCES;
+			if(arg > 0xff) return -EINVAL;
+			read_ahead[MAJOR(inode->i_rdev)] = arg;
+			return 0;
+
+		case BLKRAGET:
+			if (!arg)  return -EINVAL;
+			return put_user(read_ahead[MAJOR(inode->i_rdev)],
+					(long *) arg); 
+		case BLKGETSIZE:
+			return put_user(i2ob[minor].nr_sects, (long *) arg);
+
+		case BLKFLSBUF:
+			if(!capable(CAP_SYS_ADMIN))  return -EACCES;
+			fsync_dev(inode->i_rdev);
+			invalidate_buffers(inode->i_rdev);
+			return 0;
+			
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry g;
+			int u=minor&0xF0;
+			i2o_block_biosparam(i2ob_sizes[u]<<1, 
+				&g.cylinders, &g.heads, &g.sectors);
+			g.start = i2ob[minor].start_sect;
+			return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0;
+		}
+		
+		RO_IOCTLS(inode->i_rdev, arg);
+	
+		case BLKRRPART:
+			if(!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			return do_i2ob_revalidate(inode->i_rdev,1);
+			
+			
+		default:
+			return -EINVAL;
+	}
+}
+
+/*
+ *	Close the block device down
+ */
+ 
+static int i2ob_release(struct inode *inode, struct file *file)
+{
+	struct i2ob_device *dev;
+	int minor;
+
+	minor = MINOR(inode->i_rdev);
+	if (minor >= (MAX_I2OB<<4))
+		return -ENODEV;
+	dev = &i2ob_dev[(minor&0xF0)];
+	if (dev->refcnt <= 0)
+		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
+	dev->refcnt--;
+	if(dev->refcnt==0)
+	{
+		/*
+		 *	Flush the onboard cache on unmount
+		 */
+		u32 msg[5];
+		int *query_done = &dev->done_flag;
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
+		msg[2] = i2ob_context|0x40000000;
+		msg[3] = (u32)query_done;
+		msg[4] = 60<<16;
+		i2o_post_wait(dev->controller, msg, 20, 2);
+		/*
+		 *	Unlock the media
+		 */
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid;
+		msg[2] = i2ob_context|0x40000000;
+		msg[3] = (u32)query_done;
+		msg[4] = -1;
+		i2o_post_wait(dev->controller, msg, 20, 2);
+	
+		/*
+ 		 * Now unclaim the device.
+		 */
+		if (i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0)
+			printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n");
+
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *	Open the block device.
+ */
+ 
+static int i2ob_open(struct inode *inode, struct file *file)
+{
+	int minor;
+	struct i2ob_device *dev;
+	
+	if (!inode)
+		return -EINVAL;
+	minor = MINOR(inode->i_rdev);
+	if (minor >= MAX_I2OB<<4)
+		return -ENODEV;
+	dev=&i2ob_dev[(minor&0xF0)];
+	if(dev->i2odev == NULL)
+		return -ENODEV;
+		
+	if(dev->refcnt++==0)
+	{ 
+		u32 msg[6];
+		int *query_done;
+		
+		
+		if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0)
+		{
+			dev->refcnt--;
+			return -EBUSY;
+		}
+		
+		query_done = &dev->done_flag;
+		/*
+		 *	Mount the media if needed. Note that we don't use
+		 *	the lock bit. Since we have to issue a lock if it
+		 *	refuses a mount (quite possible) then we might as
+		 *	well just send two messages out.
+		 */
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;		
+		msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid;
+		msg[2] = i2ob_context|0x40000000;
+		msg[3] = (u32)query_done;
+		msg[4] = -1;
+		msg[5] = 0;
+		i2o_post_wait(dev->controller, msg, 24, 2);
+		/*
+		 *	Lock the media
+		 */
+		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid;
+		msg[2] = i2ob_context|0x40000000;
+		msg[3] = (u32)query_done;
+		msg[4] = -1;
+		i2o_post_wait(dev->controller, msg, 20, 2);
+	}		
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *	Issue a device query
+ */
+ 
+static int i2ob_query_device(struct i2ob_device *dev, int table, 
+	int field, void *buf, int buflen)
+{
+	return i2o_query_scalar(dev->controller, dev->tid,
+		table, field, buf, buflen);
+}
+
+
+/*
+ *	Install the I2O block device we found.
+ */
+ 
+static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit)
+{
+	u64 size;
+	u32 blocksize;
+	u32 limit;
+	u8 type;
+	u32 flags, status;
+	struct i2ob_device *dev=&i2ob_dev[unit];
+	int i;
+
+	/*
+	 *	Ask for the current media data. If that isn't supported
+	 *	then we ask for the device capacity data
+	 */
+	 
+	if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0
+	  || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 )
+	{
+		i2ob_query_device(dev, 0x0000, 3, &blocksize, 4);
+		i2ob_query_device(dev, 0x0000, 4, &size, 8);
+	}
+	
+	i2ob_query_device(dev, 0x0000, 5, &flags, 4);
+	i2ob_query_device(dev, 0x0000, 6, &status, 4);
+	i2ob_sizes[unit] = (int)(size>>10);
+	i2ob_hardsizes[unit] = blocksize;
+
+	limit=4096;	/* 8 deep scatter gather */
+
+	printk("Byte limit is %d.\n", limit);
+	
+	for(i=unit;i<=unit+15;i++)
+		i2ob_max_sectors[i]=(limit>>9);
+	
+	i2ob[unit].nr_sects = (int)(size>>9);
+
+	i2ob_query_device(dev, 0x0000, 0, &type, 1);
+	
+	sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4));
+
+	printk("%s: ", d->dev_name);
+	if(status&(1<<10))
+		printk("RAID ");
+	switch(type)
+	{
+		case 0: printk("Disk Storage");break;
+		case 4: printk("WORM");break;
+		case 5: printk("CD-ROM");break;
+		case 7:	printk("Optical device");break;
+		default:
+			printk("Type %d", type);
+	}
+	if(((flags & (1<<3)) && !(status & (1<<3))) ||
+	   ((flags & (1<<4)) && !(status & (1<<4))))
+	{
+		printk(" Not loaded.\n");
+		return 0;
+	}
+	printk(" %dMb, %d byte sectors",
+		(int)(size>>20), blocksize);
+	if(status&(1<<0))
+	{
+		u32 cachesize;
+		i2ob_query_device(dev, 0x0003, 0, &cachesize, 4);
+		cachesize>>=10;
+		if(cachesize>4095)
+			printk(", %dMb cache", cachesize>>10);
+		else
+			printk(", %dKb cache", cachesize);
+	}
+	printk(".\n");
+	printk("%s: Maximum sectors/read set to %d.\n", 
+		d->dev_name, i2ob_max_sectors[unit]);
+	resetup_one_dev(&i2ob_gendisk, unit>>4);
+	return 0;
+}
+
+static void i2ob_probe(void)
+{
+	int i;
+	int unit = 0;
+	int warned = 0;
+		
+	for(i=0; i< MAX_I2O_CONTROLLERS; i++)
+	{
+		struct i2o_controller *c=i2o_find_controller(i);
+		struct i2o_device *d;
+	
+		if(c==NULL)
+			continue;
+
+		for(d=c->devices;d!=NULL;d=d->next)
+		{
+			if(d->lct_data->class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE)
+				continue;
+
+			if(d->lct_data->user_tid != 0xFFF)
+				continue;
+
+			if(unit<MAX_I2OB<<4)
+			{
+ 				/*
+				 * Get the device and fill in the
+				 * Tid and controller.
+				 */
+				struct i2ob_device *dev=&i2ob_dev[unit];
+				dev->i2odev = d; 
+				dev->controller = c;
+				dev->tid = d->lct_data->tid;
+ 
+				/*
+				 * Insure the device can be claimed
+				 * before installing it.
+				 */
+				if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY )==0)
+				{
+					printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit);
+					i2ob_install_device(c,d,unit);
+                                        unit+=16;
+ 
+					/*
+					 * Now that the device has been
+					 * installed, unclaim it so that
+					 * it can be claimed by either
+					 * the block or scsi driver.
+					 */
+					if(i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY))
+						printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid);
+				}
+				else
+					printk(KERN_INFO "TID %d not claimed\n",dev->tid);
+			}
+			else
+			{
+				if(!warned++)
+					printk("i2o_block: too many device, registering only %d.\n", unit>>4);
+			}
+		}
+		i2o_unlock_controller(c);
+	}
+	i2ob_devices = unit;
+}
+
+/*
+ *	Have we seen a media change ?
+ */
+ 
+static int i2ob_media_change(kdev_t dev)
+{
+	int i=MINOR(dev);
+	i>>=4;
+	if(i2ob_media_change_flag[i])
+	{
+		i2ob_media_change_flag[i]=0;
+		return 1;
+	}
+	return 0;
+}
+
+static int i2ob_revalidate(kdev_t dev)
+{
+	return do_i2ob_revalidate(dev, 0);
+}
+
+static int i2ob_reboot_event(struct notifier_block *n, unsigned long code, void *p)
+{
+	int i;
+	
+	if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
+		return NOTIFY_DONE;
+	for(i=0;i<MAX_I2OB;i++)
+	{
+		struct i2ob_device *dev=&i2ob_dev[(i<<4)];
+		
+		if(dev->refcnt!=0)
+		{
+			/*
+			 *	Flush the onboard cache on power down
+			 *	also unlock the media
+			 */
+			u32 msg[5];
+			int *query_done = &dev->done_flag;
+			msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+			msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
+			msg[2] = i2ob_context|0x40000000;
+			msg[3] = (u32)query_done;
+			msg[4] = 60<<16;
+			i2o_post_wait(dev->controller, msg, 20, 2);
+			/*
+			 *	Unlock the media
+			 */
+			msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+			msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid;
+			msg[2] = i2ob_context|0x40000000;
+			msg[3] = (u32)query_done;
+			msg[4] = -1;
+			i2o_post_wait(dev->controller, msg, 20, 2);
+		}
+	}	
+	return NOTIFY_DONE;
+}
+
+struct notifier_block i2ob_reboot_notifier =
+{
+	i2ob_reboot_event,
+	NULL,
+	0
+};
+
+static struct file_operations i2ob_fops =
+{
+	NULL,			/* lseek - default */
+	block_read,		/* read - general block-dev read */
+	block_write,		/* write - general block-dev write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select */
+	i2ob_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	i2ob_open,		/* open */
+	NULL,			/* flush */
+	i2ob_release,		/* release */
+	NULL,			/* fsync */
+	NULL,			/* fasync */
+	i2ob_media_change,	/* Media Change */
+	i2ob_revalidate,	/* Revalidate */
+	NULL			/* File locks */
+};
+
+static void i2ob_geninit(struct gendisk *gd)
+{
+}
+
+	
+static struct gendisk i2ob_gendisk = 
+{
+	MAJOR_NR,
+	"i2ohd",
+	4,
+	1<<4,
+	MAX_I2OB,
+	i2ob_geninit,
+	i2ob,
+	i2ob_sizes,
+	0,
+	NULL,
+	NULL
+};
+
+/*
+ * And here should be modules and kernel interface 
+ *  (Just smiley confuses emacs :-)
+ */
+
+#ifdef MODULE
+#define i2o_block_init init_module
+#endif
+
+int i2o_block_init(void)
+{
+	int i;
+
+	printk(KERN_INFO "I2O Block Storage OSM v0.07. (C) 1999 Red Hat Software.\n");
+	
+	/*
+	 *	Register the block device interfaces
+	 */
+
+	if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) {
+		printk("Unable to get major number %d for i2o_block\n",
+		       MAJOR_NR);
+		return -EIO;
+	}
+#ifdef MODULE
+	printk("i2o_block: registered device at major %d\n", MAJOR_NR);
+#endif
+
+	/*
+	 *	Now fill in the boiler plate
+	 */
+	 
+	blksize_size[MAJOR_NR] = i2ob_blksizes;
+	hardsect_size[MAJOR_NR] = i2ob_hardsizes;
+	blk_size[MAJOR_NR] = i2ob_sizes;
+	max_sectors[MAJOR_NR] = i2ob_max_sectors;
+	blk_dev[MAJOR_NR].request_fn = i2ob_request;	
+
+	for (i = 0; i < MAX_I2OB << 4; i++) {
+		i2ob_dev[i].refcnt = 0;
+		i2ob_dev[i].flags = 0;
+		i2ob_dev[i].controller = NULL;
+		i2ob_dev[i].i2odev = NULL;
+		i2ob_dev[i].tid = 0;
+		i2ob_dev[i].head = NULL;
+		i2ob_dev[i].tail = NULL;
+		i2ob_blksizes[i] = 1024;
+		i2ob_max_sectors[i] = 2;
+	}
+	
+	/*
+	 *	Set up the queue
+	 */
+	
+	for(i = 0; i< MAX_I2OB_DEPTH; i++)
+	{
+		i2ob_queue[i].next = &i2ob_queue[i+1];
+		i2ob_queue[i].num = i;
+	}
+	
+	/* Queue is MAX_I2OB + 1... */
+	i2ob_queue[i].next = NULL;
+	i2ob_qhead = &i2ob_queue[0];
+	
+	/*
+	 *	Timers
+	 */
+	 
+	init_timer(&i2ob_timer);
+	i2ob_timer.function = i2ob_timer_handler;
+	i2ob_timer.data = 0;
+	
+	/*
+	 *	Register the OSM handler as we will need this to probe for
+	 *	drives, geometry and other goodies.
+	 */
+
+	if(i2o_install_handler(&i2o_block_handler)<0)
+	{
+		unregister_blkdev(MAJOR_NR, "i2o_block");
+		printk(KERN_ERR "i2o_block: unable to register OSM.\n");
+		return -EINVAL;
+	}
+	i2ob_context = i2o_block_handler.context;	 
+
+	/*
+	 *	Finally see what is actually plugged in to our controllers
+	 */
+
+	i2ob_probe();
+	
+	register_reboot_notifier(&i2ob_reboot_notifier);
+	return 0;
+}
+
+#ifdef MODULE
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O Block Device OSM");
+
+void cleanup_module(void)
+{
+	struct gendisk **gdp;
+	
+	unregister_reboot_notifier(&i2ob_reboot_notifier);
+	
+	/*
+	 *	Flush the OSM
+	 */
+
+	i2o_remove_handler(&i2o_block_handler);
+		 
+	/*
+	 *	Return the block device
+	 */
+	if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0)
+		printk("i2o_block: cleanup_module failed\n");
+
+	/*
+	 *	Why isnt register/unregister gendisk in the kernel ???
+	 */
+
+	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+		if (*gdp == &i2ob_gendisk)
+			break;
+
+}
+#endif
diff -urN linux-2.2.15-pre9/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- linux-2.2.15-pre9/drivers/i2o/i2o_config.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/i2o_config.c	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,955 @@
+/*
+ * I2O Configuration Interface Driver
+ *
+ * (C) Copyright 1999   Red Hat Software
+ *	
+ * Written by Alan Cox, Building Number Three Ltd
+ *
+ * Modified 04/20/1999 by Deepak Saxena
+ *   - Added basic ioctl() support
+ * Modified 06/07/1999 by Deepak Saxena
+ *   - Added software download ioctl (still testing)
+ * Modified 09/10/1999 by Auvo Häkkinen
+ *   - Changes to i2o_cfg_reply(), ioctl_parms()
+ *   - Added ioct_validate()
+ * Modified 09/30/1999 by Taneli Vähäkangas
+ *   - Fixed ioctl_swdl()
+ * Modified 10/04/1999 by Taneli Vähäkangas
+ *   - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
+ * Modified 11/18/199 by Deepak Saxena
+ *   - Added event managmenet support
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/i2o.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+
+#include <asm/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+static int i2o_cfg_context = -1;
+static void *page_buf;
+static void *i2o_buffer;
+static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED;
+struct wait_queue *i2o_wait_queue;
+
+#define MODINC(x,y) (x = x++ % y)
+
+struct i2o_cfg_info
+{
+	struct file* fp;
+	struct fasync_struct *fasync;
+	struct i2o_evt_info event_q[I2O_EVT_Q_LEN];
+	u16		q_in;		// Queue head index
+	u16		q_out;		// Queue tail index
+	u16		q_len;		// Queue length
+	u16		q_lost;		// Number of lost events
+	u32		q_id;		// Event queue ID...used as tx_context
+	struct	i2o_cfg_info *next;
+};
+static struct i2o_cfg_info *open_files = NULL;
+static int i2o_cfg_info_id = 0;
+
+static int ioctl_getiops(unsigned long);
+static int ioctl_gethrt(unsigned long);
+static int ioctl_getlct(unsigned long);
+static int ioctl_parms(unsigned long, unsigned int);
+static int ioctl_html(unsigned long);
+static int ioctl_swdl(unsigned long);
+static int ioctl_swul(unsigned long);
+static int ioctl_swdel(unsigned long);
+static int ioctl_validate(unsigned long); 
+static int ioctl_evt_reg(unsigned long, struct file *);
+static int ioctl_evt_get(unsigned long, struct file *);
+static int cfg_fasync(int, struct file*, int);
+
+/*
+ *	This is the callback for any message we have posted. The message itself
+ *	will be returned to the message pool when we return from the IRQ
+ *
+ *	This runs in irq context so be short and sweet.
+ */
+static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m)
+{
+	u32 *msg = (u32 *)m;
+
+	if (msg[0] & (1<<13))
+		printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n");
+        
+	if (msg[4] >> 24)  // RegStatus != SUCCESS
+		i2o_report_status(KERN_INFO,"i2o_config",msg);
+
+	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
+	{
+		struct i2o_cfg_info *inf;
+
+		for(inf = open_files; inf; inf = inf->next)
+			if(inf->q_id == msg[3])
+				break;
+
+		//
+		// If this is the case, it means that we're getting
+		// events for a file descriptor that's been close()'d
+		// w/o the user unregistering for events first.
+		// The code currently assumes that the user will 
+		// take care of unregistering for events before closing
+		// a file.
+		// 
+		// TODO: 
+		// Should we track event registartion and deregister
+		// for events when a file is close()'d so this doesn't
+		// happen? That would get rid of the search through
+		// the linked list since file->private_data could point
+		// directly to the i2o_config_info data structure...but
+		// it would mean having all sorts of tables to track
+		// what each file is registered for...I think the
+		// current method is simpler. - DS
+		//			
+		if(!inf)
+			return;
+
+		inf->event_q[inf->q_in].id.iop = c->unit;
+		inf->event_q[inf->q_in].id.tid = m->target_tid;
+		inf->event_q[inf->q_in].id.evt_mask = msg[4];
+
+		//
+		// Data size = msg size - reply header
+		//
+		inf->event_q[inf->q_in].data_size = (m->size - 5) * 4;
+		if(inf->event_q[inf->q_in].data_size)
+			memcpy(inf->event_q[inf->q_in].evt_data, 
+				(unsigned char *)(msg + 5),
+				inf->event_q[inf->q_in].data_size);
+
+		spin_lock(&i2o_config_lock);
+		MODINC(inf->q_in, I2O_EVT_Q_LEN);
+		if(inf->q_len == I2O_EVT_Q_LEN)
+		{
+			MODINC(inf->q_out, I2O_EVT_Q_LEN);
+			inf->q_lost++;
+		}
+		else
+		{
+			// Keep I2OEVTGET on another CPU from touching this
+			inf->q_len++;
+		}
+		spin_unlock(&i2o_config_lock);
+		
+
+//		printk(KERN_INFO "File %p w/id %d has %d events\n",
+//			inf->fp, inf->q_id, inf->q_len);	
+
+		if(inf->fasync)
+			kill_fasync(inf->fasync, SIGIO);
+	}
+
+	return;
+}
+
+/*
+ *	Each of these describes an i2o message handler. They are
+ *	multiplexed by the i2o_core code
+ */
+ 
+struct i2o_handler cfg_handler=
+{
+	i2o_cfg_reply,
+	"Configuration",
+	0,
+	0xffffffff	// All classes
+};
+
+static long long cfg_llseek(struct file *file, long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+
+static ssize_t cfg_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	printk(KERN_INFO "i2o_config write not yet supported\n");
+
+	return 0;
+}
+
+
+static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+	return 0;
+}
+
+/*
+ * IOCTL Handler
+ */
+static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
+	unsigned long arg)
+{
+	int ret;
+
+	switch(cmd)
+	{	
+		case I2OGETIOPS:
+			ret = ioctl_getiops(arg);
+			break;
+
+		case I2OHRTGET:
+			ret = ioctl_gethrt(arg);
+			break;
+
+		case I2OLCTGET:
+			ret = ioctl_getlct(arg);
+			break;
+
+		case I2OPARMSET:
+			ret = ioctl_parms(arg, I2OPARMSET);
+			break;
+
+		case I2OPARMGET:
+			ret = ioctl_parms(arg, I2OPARMGET);
+			break;
+
+		case I2OSWDL:
+			ret = ioctl_swdl(arg);
+			break;
+
+		case I2OSWUL:
+			ret = ioctl_swul(arg);
+			break;
+
+		case I2OSWDEL:
+			ret = ioctl_swdel(arg);
+			break;
+
+		case I2OVALIDATE:
+			ret = ioctl_validate(arg);
+			break;
+			
+		case I2OHTML:
+			ret = ioctl_html(arg);
+			break;
+
+		case I2OEVTREG:
+			ret = ioctl_evt_reg(arg, fp);
+			break;
+
+		case I2OEVTGET:
+			ret = ioctl_evt_get(arg, fp);
+			break;
+
+		default:
+			ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int ioctl_getiops(unsigned long arg)
+{
+	u8 *user_iop_table = (u8*)arg;
+	struct i2o_controller *c = NULL;
+	int i;
+	u8 foo[MAX_I2O_CONTROLLERS];
+
+	if(!access_ok(VERIFY_WRITE, user_iop_table,  MAX_I2O_CONTROLLERS))
+		return -EFAULT;
+
+	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
+	{
+		c = i2o_find_controller(i);
+		if(c)
+		{
+			foo[i] = 1;
+			i2o_unlock_controller(c);
+		}
+		else
+		{
+			foo[i] = 0;
+		}
+	}
+
+	__copy_to_user(user_iop_table, foo, MAX_I2O_CONTROLLERS);
+	return 0;
+}
+
+int ioctl_gethrt(unsigned long arg)
+{
+	struct i2o_controller *c;
+	struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg;
+	struct i2o_cmd_hrtlct kcmd;
+	i2o_hrt *hrt;
+	int len;
+	u32 reslen;
+	int ret = 0;
+
+	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
+		return -EFAULT;
+
+	if(get_user(reslen, kcmd.reslen) < 0)
+		return -EFAULT;
+
+	if(kcmd.resbuf == NULL)
+		return -EFAULT;
+
+	c = i2o_find_controller(kcmd.iop);
+	if(!c)
+		return -ENXIO;
+		
+	hrt = (i2o_hrt *)c->hrt;
+
+	i2o_unlock_controller(c);
+
+	len = 8 + ((hrt->entry_len * hrt->num_entries) << 2);
+	
+	/* We did a get user...so assuming mem is ok...is this bad? */
+	put_user(len, kcmd.reslen);
+	if(len > reslen)
+		ret = -ENOBUFS;	
+	if(copy_to_user(kcmd.resbuf, (void*)hrt, len))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+int ioctl_getlct(unsigned long arg)
+{
+	struct i2o_controller *c;
+	struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg;
+	struct i2o_cmd_hrtlct kcmd;
+	i2o_lct *lct;
+	int len;
+	int ret = 0;
+	u32 reslen;
+
+	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
+		return -EFAULT;
+
+	if(get_user(reslen, kcmd.reslen) < 0)
+		return -EFAULT;
+
+	if(kcmd.resbuf == NULL)
+		return -EFAULT;
+
+	c = i2o_find_controller(kcmd.iop);
+	if(!c)
+		return -ENXIO;
+
+	lct = (i2o_lct *)c->lct;
+	i2o_unlock_controller(c);
+
+	len = (unsigned int)lct->table_size << 2;
+	put_user(len, kcmd.reslen);
+	if(len > reslen)
+		ret = -ENOBUFS;	
+	else if(copy_to_user(kcmd.resbuf, (void*)lct, len))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int ioctl_parms(unsigned long arg, unsigned int type)
+{
+	int ret = 0;
+	struct i2o_controller *c;
+	struct i2o_cmd_psetget *cmd = (struct i2o_cmd_psetget*)arg;
+	struct i2o_cmd_psetget kcmd;
+	u32 reslen;
+	u8 *ops;
+	u8 *res;
+	int len;
+
+	u32 i2o_cmd = (type == I2OPARMGET ? 
+				I2O_CMD_UTIL_PARAMS_GET :
+				I2O_CMD_UTIL_PARAMS_SET);
+
+	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget)))
+		return -EFAULT;
+
+	if(get_user(reslen, kcmd.reslen))
+		return -EFAULT;
+
+	c = i2o_find_controller(kcmd.iop);
+	if(!c)
+		return -ENXIO;
+
+	ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL);
+	if(!ops)
+	{
+		i2o_unlock_controller(c);
+		return -ENOMEM;
+	}
+
+	if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen))
+	{
+		i2o_unlock_controller(c);
+		kfree(ops);
+		return -EFAULT;
+	}
+
+	/*
+	 * It's possible to have a _very_ large table
+	 * and that the user asks for all of it at once...
+	 */
+	res = (u8*)kmalloc(65536, GFP_KERNEL);
+	if(!res)
+	{
+		i2o_unlock_controller(c);
+		kfree(ops);
+		return -ENOMEM;
+	}
+
+        len = i2o_issue_params(i2o_cmd, c, kcmd.tid, 
+       			ops, kcmd.oplen, res, 65536);
+        i2o_unlock_controller(c);
+	kfree(ops);
+        
+	if (len < 0) {
+		kfree(res);
+		return len; /* -DetailedStatus */
+	}
+
+	put_user(len, kcmd.reslen);
+	if(len > reslen)
+		ret = -ENOBUFS;
+	else if(copy_to_user(cmd->resbuf, res, len))
+		ret = -EFAULT;
+
+	kfree(res);
+
+	return ret;
+}
+
+int ioctl_html(unsigned long arg)
+{
+	struct i2o_html *cmd = (struct i2o_html*)arg;
+	struct i2o_html kcmd;
+	struct i2o_controller *c;
+	u8 *res = NULL;
+	void *query = NULL;
+	int ret = 0;
+	int token;
+	u32 len;
+	u32 reslen;
+	u32 msg[MSG_FRAME_SIZE/4];
+
+	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html)))
+	{
+		printk(KERN_INFO "i2o_config: can't copy html cmd\n");
+		return -EFAULT;
+	}
+
+	if(get_user(reslen, kcmd.reslen) < 0)
+	{
+		printk(KERN_INFO "i2o_config: can't copy html reslen\n");
+		return -EFAULT;
+	}
+
+	if(!kcmd.resbuf)		
+	{
+		printk(KERN_INFO "i2o_config: NULL html buffer\n");
+		return -EFAULT;
+	}
+
+	c = i2o_find_controller(kcmd.iop);
+	if(!c)
+		return -ENXIO;
+
+	if(kcmd.qlen) /* Check for post data */
+	{
+		query = kmalloc(kcmd.qlen, GFP_KERNEL);
+		if(!query)
+		{
+			i2o_unlock_controller(c);
+			return -ENOMEM;
+		}
+		if(copy_from_user(query, kcmd.qbuf, kcmd.qlen))
+		{
+			i2o_unlock_controller(c);
+			printk(KERN_INFO "i2o_config: could not get query\n");
+			kfree(query);
+			return -EFAULT;
+		}
+	}
+
+	res = kmalloc(65536, GFP_KERNEL);
+	if(!res)
+	{
+		i2o_unlock_controller(c);
+		return -ENOMEM;
+	}
+
+	msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid;
+	msg[2] = i2o_cfg_context;
+	msg[3] = 0;
+	msg[4] = kcmd.page;
+	msg[5] = 0xD0000000|65536;
+	msg[6] = virt_to_bus(res);
+	if(!kcmd.qlen) /* Check for post data */
+		msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5;
+	else
+	{
+		msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
+		msg[5] = 0x50000000|65536;
+		msg[7] = 0xD4000000|(kcmd.qlen);
+		msg[8] = virt_to_phys(query);
+	}
+
+	token = i2o_post_wait(c, msg, 9*4, 10);
+	if(token)
+	{
+		printk(KERN_DEBUG "token = %#10x\n", token);
+		i2o_unlock_controller(c);
+		kfree(res);
+		if(kcmd.qlen) kfree(query);
+
+		return -ETIMEDOUT;
+	}
+	i2o_unlock_controller(c);
+
+	len = strnlen(res, 65536);
+	put_user(len, kcmd.reslen);
+	if(len > reslen)
+		ret = -ENOMEM;
+	if(copy_to_user(kcmd.resbuf, res, len))
+		ret = -EFAULT;
+
+	kfree(res);
+	if(kcmd.qlen) 
+		kfree(query);
+
+	return ret;
+}
+ 
+int ioctl_swdl(unsigned long arg)
+{
+	struct i2o_sw_xfer kxfer;
+	struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
+	unsigned char maxfrag = 0, curfrag = 1;
+	unsigned char *buffer;
+	u32 msg[9];
+	unsigned int status = 0, swlen = 0, fragsize = 8192;
+	struct i2o_controller *c;
+
+	if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+		return -EFAULT;
+
+	if(get_user(swlen, kxfer.swlen) < 0)
+		return -EFAULT;
+
+	if(get_user(maxfrag, kxfer.maxfrag) < 0)
+		return -EFAULT;
+
+	if(get_user(curfrag, kxfer.curfrag) < 0)
+		return -EFAULT;
+
+	if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192;
+
+	if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize))
+		return -EFAULT;
+	
+	c = i2o_find_controller(kxfer.iop);
+	if(!c)
+		return -ENXIO;
+
+	buffer=kmalloc(fragsize, GFP_KERNEL);
+	if (buffer==NULL)
+	{
+		i2o_unlock_controller(c);
+		return -ENOMEM;
+	}
+	__copy_from_user(buffer, kxfer.buf, fragsize);
+
+	msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7;
+	msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2]= (u32)cfg_handler.context;
+	msg[3]= 0;
+	msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) |
+		(((u32)maxfrag)<<8) | (((u32)curfrag));
+	msg[5]= swlen;
+	msg[6]= kxfer.sw_id;
+	msg[7]= (0xD0000000 | fragsize);
+	msg[8]= virt_to_phys(buffer);
+
+//	printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
+	status = i2o_post_wait(c, msg, sizeof(msg), 60);
+
+	i2o_unlock_controller(c);
+	kfree(buffer);
+	
+	if (status != I2O_POST_WAIT_OK)
+	{
+		// it fails if you try and send frags out of order
+		// and for some yet unknown reasons too
+		printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+int ioctl_swul(unsigned long arg)
+{
+	struct i2o_sw_xfer kxfer;
+	struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
+	unsigned char maxfrag = 0, curfrag = 1;
+	unsigned char *buffer;
+	u32 msg[9];
+	unsigned int status = 0, swlen = 0, fragsize = 8192;
+	struct i2o_controller *c;
+	
+	if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+		return -EFAULT;
+		
+	if(get_user(swlen, kxfer.swlen) < 0)
+		return -EFAULT;
+		
+	if(get_user(maxfrag, kxfer.maxfrag) < 0)
+		return -EFAULT;
+		
+	if(get_user(curfrag, kxfer.curfrag) < 0)
+		return -EFAULT;
+	
+	if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192;
+	
+	if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize))
+		return -EFAULT;
+		
+	c = i2o_find_controller(kxfer.iop);
+	if(!c)
+		return -ENXIO;
+		
+	buffer=kmalloc(fragsize, GFP_KERNEL);
+	if (buffer==NULL)
+	{
+		i2o_unlock_controller(c);
+		return -ENOMEM;
+	}
+	
+	msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7;
+	msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2]= (u32)cfg_handler.context;
+	msg[3]= 0;
+	msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag;
+	msg[5]= swlen;
+	msg[6]= kxfer.sw_id;
+	msg[7]= (0xD0000000 | fragsize);
+	msg[8]= virt_to_bus(buffer);
+	
+//	printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
+	status = i2o_post_wait(c, msg, sizeof(msg), 60);
+	i2o_unlock_controller(c);
+	
+	if (status != I2O_POST_WAIT_OK)
+	{
+		kfree(buffer);
+		printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status);
+		return -ETIMEDOUT;
+	}
+	
+	__copy_to_user(kxfer.buf, buffer, fragsize);
+	kfree(buffer);
+	
+	return 0;
+}
+
+int ioctl_swdel(unsigned long arg)
+{
+	struct i2o_controller *c;
+	struct i2o_sw_xfer kxfer, *pxfer = (struct i2o_sw_xfer *)arg;
+	u32 msg[7];
+	unsigned int swlen;
+	int token;
+	
+	if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+		return -EFAULT;
+		
+	if (get_user(swlen, kxfer.swlen) < 0)
+		return -EFAULT;
+		
+	c = i2o_find_controller(kxfer.iop);
+	if (!c)
+		return -ENXIO;
+
+	msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+	msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2] = (u32)i2o_cfg_context;
+	msg[3] = 0;
+	msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16;
+	msg[5] = swlen;
+	msg[6] = kxfer.sw_id;
+
+	token = i2o_post_wait(c, msg, sizeof(msg), 10);
+	i2o_unlock_controller(c);
+	
+	if (token != I2O_POST_WAIT_OK)
+	{
+		printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token);
+		return -ETIMEDOUT;
+	}
+	
+	return 0;
+}
+
+int ioctl_validate(unsigned long arg)
+{
+        int token;
+        int iop = (int)arg;
+        u32 msg[4];
+        struct i2o_controller *c;
+
+        c=i2o_find_controller(iop);
+        if (!c)
+                return -ENXIO;
+
+        msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+        msg[1] = I2O_CMD_CONFIG_VALIDATE<<24 | HOST_TID<<12 | iop;
+        msg[2] = (u32)i2o_cfg_context;
+        msg[3] = 0;
+
+        token = i2o_post_wait(c, msg, sizeof(msg), 10);
+        i2o_unlock_controller(c);
+
+        if (token != I2O_POST_WAIT_OK)
+        {
+                printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n",
+                	token);
+                return -ETIMEDOUT;
+        }
+
+        return 0;
+}   
+
+static int ioctl_evt_reg(unsigned long arg, struct file *fp)
+{
+	u32 msg[5];
+	struct i2o_evt_id *pdesc = (struct i2o_evt_id *)arg;
+	struct i2o_evt_id kdesc;
+	struct i2o_controller *iop;
+	struct i2o_device *d;
+
+	if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id)))
+		return -EFAULT;
+
+	/* IOP exists? */
+	iop = i2o_find_controller(kdesc.iop);
+	if(!iop)
+		return -ENXIO;
+	i2o_unlock_controller(iop);
+
+	/* Device exists? */
+	for(d = iop->devices; d; d = d->next)
+		if(d->lct_data->tid == kdesc.tid)
+			break;
+
+	if(!d)
+		return -ENODEV;
+
+	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid;
+	msg[2] = (u32)i2o_cfg_context;
+	msg[3] = (u32)fp->private_data;
+	msg[4] = kdesc.evt_mask;
+
+	i2o_post_this(iop, msg, 20);
+
+	return 0;
+}	
+
+static int ioctl_evt_get(unsigned long arg, struct file *fp)
+{
+	u32 id = (u32)fp->private_data;
+	struct i2o_cfg_info *p = NULL;
+	struct i2o_evt_get *uget = (struct i2o_evt_get*)arg;
+	struct i2o_evt_get kget;
+	unsigned int flags;
+
+	// access_ok doesn't check for NULL?!?!
+	if(!arg)
+		return -EFAULT;
+	
+	if(!access_ok(VERIFY_WRITE, uget,  sizeof(struct i2o_evt_get)))
+		return -EFAULT;
+
+	for(p = open_files; p; p = p->next)
+		if(p->q_id == id)
+			break;
+
+	if(!p->q_len)
+	{
+		return -ENOENT;
+		return 0;
+	}
+
+	memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info));
+	MODINC(p->q_out, I2O_EVT_Q_LEN);
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	p->q_len--;
+	kget.pending = p->q_len;
+	kget.lost = p->q_lost;
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+
+	__copy_to_user(uget, &kget, sizeof(struct i2o_evt_get));
+
+	return 0;
+}
+
+static int cfg_open(struct inode *inode, struct file *file)
+{
+	struct i2o_cfg_info *tmp = 
+		(struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL);
+	unsigned int flags;
+
+	if(!tmp)
+		return -ENOMEM;
+
+	file->private_data = (void*)(i2o_cfg_info_id++);
+	tmp->fp = file;
+	tmp->fasync = NULL;
+	tmp->q_id = (u32)file->private_data;
+	tmp->q_len = 0;
+	tmp->q_in = 0;
+	tmp->q_out = 0;
+	tmp->q_lost = 0;
+	tmp->next = open_files;
+
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	open_files = tmp;
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+	
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int cfg_release(struct inode *inode, struct file *file)
+{
+	u32 id = (u32)file->private_data;
+	struct i2o_cfg_info *p1, *p2;
+	unsigned int flags;
+
+	p1 = p2 = NULL;
+
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	for(p1 = open_files; p1; )
+	{
+		if(p1->q_id == id)
+		{
+
+			if(p1->fasync)
+				cfg_fasync(-1, file, 0);
+			if(p2)
+				p2->next = p1->next;
+			else
+				open_files = p1->next;
+
+			kfree(p1);
+			break;
+		}
+		p2 = p1;
+		p1 = p1->next;
+	}
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int cfg_fasync(int fd, struct file *fp, int on)
+{
+	u32 id = (u32)fp->private_data;
+	struct i2o_cfg_info *p;
+
+	for(p = open_files; p; p = p->next)
+		if(p->q_id == id)
+			break;
+
+	if(!p)
+		return -EBADF;
+
+	return fasync_helper(fd, fp, on, &p->fasync);
+}
+
+static struct file_operations config_fops =
+{
+	llseek:		cfg_llseek,
+	read:		cfg_read,
+	write:		cfg_write,
+	ioctl:		cfg_ioctl,
+	open:		cfg_open,
+	release:	cfg_release,
+	fasync:		cfg_fasync,
+};
+
+static struct miscdevice i2o_miscdev = {
+	I2O_MINOR,
+	"i2octl",
+	&config_fops
+};	
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init i2o_config_init(void)
+#endif
+{
+	printk(KERN_INFO "I2O configuration manager v 0.04.\n");
+	printk(KERN_INFO "  (C) Copyright 1999 Red Hat Software");
+	
+	if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL)
+	{
+		printk(KERN_ERR "i2o_config: no memory for page buffer.\n");
+		return -ENOBUFS;
+	}
+	if(misc_register(&i2o_miscdev)==-1)
+	{
+		printk(KERN_ERR "i2o_config: can't register device.\n");
+		kfree(page_buf);
+		return -EBUSY;
+	}
+	/*
+	 *	Install our handler
+	 */
+	if(i2o_install_handler(&cfg_handler)<0)
+	{
+		kfree(page_buf);
+		printk(KERN_ERR "i2o_config: handler register failed.\n");
+		misc_deregister(&i2o_miscdev);
+		return -EBUSY;
+	}
+	/*
+	 *	The low 16bits of the transaction context must match this
+	 *	for everything we post. Otherwise someone else gets our mail
+	 */
+	i2o_cfg_context = cfg_handler.context;
+	return 0;
+}
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	misc_deregister(&i2o_miscdev);
+	
+	if(page_buf)
+		kfree(page_buf);
+	if(i2o_cfg_context != -1)
+		i2o_remove_handler(&cfg_handler);
+	if(i2o_buffer)
+		kfree(i2o_buffer);
+}
+ 
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O Configuration");
+
+#endif
diff -urN linux-2.2.15-pre9/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- linux-2.2.15-pre9/drivers/i2o/i2o_core.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/i2o_core.c	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,2428 @@
+/* 
+ * Core I2O structure managment 
+ * 
+ * (C) Copyright 1999   Red Hat Software 
+ *	
+ * Written by Alan Cox, Building Number Three 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.  
+ * 
+ * A lot of the I2O message side code from this is taken from the 
+ * Red Creek RCPCI45 adapter driver by Red Creek Communications 
+ *
+ * Fixes by: 
+ *		Philipp Rumpf 
+ *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> 
+ *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> 
+ *		Deepak Saxena <deepak@plexity.net> 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <linux/i2o.h>
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <asm/spinlock.h>
+
+#include <linux/bitops.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+
+#include <asm/io.h>
+
+// #define DRIVERDEBUG
+// #define DEBUG_IRQ
+
+#define dprintk(x)
+
+/*
+ *	Size of the I2O module table
+ */
+ 
+static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
+static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
+struct i2o_controller *i2o_controller_chain;
+int i2o_num_controllers = 0;
+static int core_context = 0;
+
+static int i2o_activate_controller(struct i2o_controller *iop);
+static int i2o_online_controller(struct i2o_controller *c);
+static int i2o_init_outbound_q(struct i2o_controller *c);
+static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
+			   struct i2o_message *);
+static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *);
+static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *);
+void i2o_dump_message(u32 *msg);
+
+static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32);
+
+static int i2o_reset_controller(struct i2o_controller *);
+static int i2o_lct_get(struct i2o_controller *);
+static int i2o_hrt_get(struct i2o_controller *);
+
+static void i2o_sys_init(void);
+static void i2o_sys_shutdown(void);
+
+static int i2o_build_sys_table(void);
+static int i2o_systab_send(struct i2o_controller *c);
+
+/*
+ * I2O System Table.  Contains information about
+ * all the IOPs in the system.  Used to inform IOPs
+ * about each other's existence.
+ *
+ * sys_tbl_ver is the CurrentChangeIndicator that is
+ * used by IOPs to track changes.
+ */
+static struct i2o_sys_tbl *sys_tbl = NULL;
+static int sys_tbl_ind = 0;
+static int sys_tbl_len = 0;
+
+#ifdef MODULE
+/* 
+ * Function table to send to bus specific layers
+ * See <include/linux/i2o.h> for explanation of this
+ */
+static struct i2o_core_func_table i2o_core_functions =
+{
+	i2o_install_controller,
+	i2o_activate_controller,
+	i2o_find_controller,
+	i2o_unlock_controller,
+	i2o_run_queue,
+	i2o_delete_controller
+};
+
+#ifdef CONFIG_I2O_PCI_MODULE
+extern int i2o_pci_core_attach(struct i2o_core_func_table *);
+extern void i2o_pci_core_detach(void);
+#endif /* CONFIG_I2O_PCI_MODULE */
+
+#endif /* MODULE */
+
+/*
+ * Structures and definitions for synchronous message posting.
+ * See i2o_post_wait() for description.
+ */ 
+struct i2o_post_wait_data
+{
+	int status;
+	u32 id;
+	struct wait_queue **wq;
+	struct i2o_post_wait_data *next;
+};
+static struct i2o_post_wait_data *post_wait_queue = NULL;
+static u32 post_wait_id = 0;	// Unique ID for each post_wait
+static spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED;
+static void i2o_post_wait_complete(u32, int);
+
+/* Message handler */ 
+static struct i2o_handler i2o_core_handler =
+{
+	(void *)i2o_core_reply,
+	"I2O core layer",
+	0
+};
+
+
+/*
+ *	I2O configuration spinlock. This isnt a big deal for contention
+ *	so we have one only
+ */
+ 
+static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * I2O Core reply handler
+ *
+ * Only messages this should see are i2o_post_wait() replies
+ */
+void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,
+		    struct i2o_message *m)
+{
+	u32 *msg=(u32 *)m;
+	int status;
+	u32 context = msg[2];
+
+#if 0
+	i2o_report_status(KERN_INFO, "i2o_core", msg);
+#endif
+	
+	if (msg[0] & (1<<13)) // Fail bit is set
+        {
+                printk(KERN_ERR "%s: Failed to process the msg:\n",c->name);
+                printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n",
+		       (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] &
+		       0xFFF);
+                printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n"
+		       "LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
+		       msg[4] >> 24, (msg[4] >> 16) & 0xFF,
+		       (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+                printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
+		       msg[5] >> 16, msg[5] & 0xFFF);
+                return;
+        }
+
+	if(msg[2]&0x80000000)	// Post wait message
+	{
+		if (msg[4] >> 24)
+		{
+			i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
+			status = -(msg[4] & 0xFFFF);
+		}
+		else
+			status = I2O_POST_WAIT_OK;
+	
+		i2o_post_wait_complete(context, status);
+	}
+}
+
+/*
+ *	Install an I2O handler - these handle the asynchronous messaging
+ *	from the card once it has initialised.
+ */
+ 
+int i2o_install_handler(struct i2o_handler *h)
+{
+	int i;
+	spin_lock(&i2o_configuration_lock);
+	for(i=0;i<MAX_I2O_MODULES;i++)
+	{
+		if(i2o_handlers[i]==NULL)
+		{
+			h->context = i;
+			i2o_handlers[i]=h;
+			spin_unlock(&i2o_configuration_lock);
+			return 0;
+		}
+	}
+	spin_unlock(&i2o_configuration_lock);
+	return -ENOSPC;
+}
+
+int i2o_remove_handler(struct i2o_handler *h)
+{
+	i2o_handlers[h->context]=NULL;
+	return 0;
+}
+	
+
+/*
+ *	Each I2O controller has a chain of devices on it - these match
+ *	the useful parts of the LCT of the board.
+ */
+ 
+int i2o_install_device(struct i2o_controller *c, struct i2o_device *d)
+{
+	int i;
+
+	spin_lock(&i2o_configuration_lock);
+	d->controller=c;
+	d->owner=NULL;
+	d->next=c->devices;
+	c->devices=d;
+	*d->dev_name = 0;
+
+	for(i = 0; i < I2O_MAX_MANAGERS; i++)
+		d->managers[i] = NULL;
+
+	spin_unlock(&i2o_configuration_lock);
+	return 0;
+}
+
+/* we need this version to call out of i2o_delete_controller */
+
+int __i2o_delete_device(struct i2o_device *d)
+{
+	struct i2o_device **p;
+
+	p=&(d->controller->devices);
+
+	/*
+	 *	Hey we have a driver!
+	 */
+	 
+	if(d->owner)
+		return -EBUSY;
+
+	/*
+	 *	Seek, locate
+	 */
+	 			
+	while(*p!=NULL)
+	{
+		if(*p==d)
+		{
+			/*
+			 *	Destroy
+			 */
+			*p=d->next;
+			kfree(d);
+			return 0;
+		}
+		p=&((*p)->next);
+	}
+	printk(KERN_ERR "i2o_delete_device: passed invalid device.\n");
+	return -EINVAL;
+}
+
+int i2o_delete_device(struct i2o_device *d)
+{
+	int ret;
+
+	spin_lock(&i2o_configuration_lock);
+
+	ret = __i2o_delete_device(d);
+
+	spin_unlock(&i2o_configuration_lock);
+
+	return ret;
+}
+
+/*
+ *	Add and remove controllers from the I2O controller list
+ */
+ 
+int i2o_install_controller(struct i2o_controller *c)
+{
+	int i;
+	spin_lock(&i2o_configuration_lock);
+	for(i=0;i<MAX_I2O_CONTROLLERS;i++)
+	{
+		if(i2o_controllers[i]==NULL)
+		{
+			i2o_controllers[i]=c;
+			c->next=i2o_controller_chain;
+			i2o_controller_chain=c;
+			c->unit = i;
+
+			sprintf(c->name, "i2o/iop%d", i);
+			i2o_num_controllers++;
+			spin_unlock(&i2o_configuration_lock);
+			return 0;
+		}
+	}
+	printk(KERN_ERR "No free i2o controller slots.\n");
+	spin_unlock(&i2o_configuration_lock);
+	return -EBUSY;
+}
+
+int i2o_delete_controller(struct i2o_controller *c)
+{
+	struct i2o_controller **p;
+	int users;
+	char name[16];
+
+	spin_lock(&i2o_configuration_lock);
+	if((users=atomic_read(&c->users)))
+	{
+		printk(KERN_INFO "%s busy: %d users for controller.\n", c->name, users);
+		c->bus_disable(c); 
+		spin_unlock(&i2o_configuration_lock);
+		return -EBUSY;
+	}
+	while(c->devices)
+	{
+		if(__i2o_delete_device(c->devices)<0)
+		{
+			/* Shouldnt happen */
+			c->bus_disable(c); 
+			spin_unlock(&i2o_configuration_lock);
+			return -EBUSY;
+		}
+	}
+
+	p=&i2o_controller_chain;
+
+	while(*p)
+	{
+		if(*p==c)
+		{
+			/* Ask the IOP to switch into RESET state */
+			i2o_reset_controller(c);
+
+			/* Release IRQ */
+			c->destructor(c);
+
+			*p=c->next;
+			spin_unlock(&i2o_configuration_lock);
+
+			if(c->page_frame)
+				kfree(c->page_frame);
+			if(c->hrt)
+				kfree(c->hrt);
+			if(c->lct)
+				kfree(c->lct);
+			if(c->status_block)
+				kfree(c->status_block);
+
+			i2o_controllers[c->unit]=NULL;
+			memcpy(name, c->name, strlen(c->name)+1);
+			kfree(c);
+			i2o_num_controllers--;
+			
+			dprintk((KERN_INFO "%s: Deleted from controller chain.\n", name));
+
+			return 0;
+		}
+		p=&((*p)->next);
+	}
+	spin_unlock(&i2o_configuration_lock);
+	printk(KERN_ERR "i2o_delete_controller: bad pointer!\n");
+	return -ENOENT;
+}
+
+void i2o_unlock_controller(struct i2o_controller *c)
+{
+	atomic_dec(&c->users);
+}
+
+struct i2o_controller *i2o_find_controller(int n)
+{
+	struct i2o_controller *c;
+	
+	if(n<0 || n>=MAX_I2O_CONTROLLERS)
+		return NULL;
+	
+	spin_lock(&i2o_configuration_lock);
+	c=i2o_controllers[n];
+	if(c!=NULL)
+		atomic_inc(&c->users);
+	spin_unlock(&i2o_configuration_lock);
+	return c;
+}
+	
+
+/*
+ * Claim a device for use as either the primary user or just
+ * as a management/secondary user
+ */
+int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
+{
+	/* Device already has a primary user or too many managers */
+	if((type == I2O_CLAIM_PRIMARY && d->owner) ||
+		(d->num_managers == I2O_MAX_MANAGERS))
+	{
+			return -EBUSY;
+	}
+
+	if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, type))
+	{
+		return -EBUSY;
+	}
+
+	spin_lock(&i2o_configuration_lock);
+	if(d->owner)
+	{
+		spin_unlock(&i2o_configuration_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&d->controller->users);
+
+	if(type == I2O_CLAIM_PRIMARY)
+		d->owner=h;
+	else
+		if (i2o_add_management_user(d, h))
+			printk(KERN_WARNING "i2o: Too many managers for TID %d\n",
+				d->lct_data->tid);
+									       
+
+	spin_unlock(&i2o_configuration_lock);
+	return 0;
+}
+
+int i2o_release_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
+{
+	int err = 0;
+
+	spin_lock(&i2o_configuration_lock);
+
+	/* Primary user */
+	if(type == I2O_CLAIM_PRIMARY)
+	{
+		if(d->owner != h)
+			err = -ENOENT;
+		else
+		{
+			if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0,
+					   type))
+			{
+				err = -ENXIO;
+			}
+			else
+			{
+				d->owner = NULL;
+				atomic_dec(&d->controller->users);
+			}
+		}
+
+		spin_unlock(&i2o_configuration_lock);
+		return err;
+	}
+
+	/* Management or other user */
+	if(i2o_remove_management_user(d, h))
+		err = -ENOENT;
+	else
+	{
+		atomic_dec(&d->controller->users);
+
+		if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0, 
+				   type))
+			err = -ENXIO;
+	}
+
+	spin_unlock(&i2o_configuration_lock);
+	return err;
+}
+
+int i2o_add_management_user(struct i2o_device *d, struct i2o_handler *h)
+{
+	int i;
+
+	if(d->num_managers == I2O_MAX_MANAGERS)
+		return 1;
+
+	for(i = 0; i < I2O_MAX_MANAGERS; i++)
+		if(!d->managers[i])
+			d->managers[i] = h;
+	
+	d->num_managers++;
+	
+	return 0;
+}
+
+int i2o_remove_management_user(struct i2o_device *d, struct i2o_handler *h)
+{
+	int i;
+
+	for(i=0; i < I2O_MAX_MANAGERS; i++)
+	{
+		if(d->managers[i] == h)
+		{
+			d->managers[i] = NULL;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+/*
+ *	This is called by the bus specific driver layer when an interrupt
+ *	or poll of this card interface is desired.
+ */
+ 
+void i2o_run_queue(struct i2o_controller *c)
+{
+	struct i2o_message *m;
+	u32 mv;
+
+#ifdef DEBUG_IRQ
+	printk(KERN_INFO "%s: interrupt\n", c->name);
+#endif
+	/* Sometimes we get here, but a message can't be read. Why? */
+	if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
+		mv=I2O_REPLY_READ32(c);
+
+	while (mv!=0xFFFFFFFF)
+	{
+		struct i2o_handler *i;
+		m=(struct i2o_message *)bus_to_virt(mv);
+		/*
+		 *	Temporary Debugging
+		 */
+		if(m->function==0x15)
+			printk("UTFR!\n");
+
+#ifdef DEBUG_IRQ
+		i2o_dump_message((u32*)m);
+#endif
+
+		i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)];
+		if(i)
+			i->reply(i,c,m);
+		else
+		{
+			printk("i2o: Spurious reply to handler %d\n", 
+				m->initiator_context&(MAX_I2O_MODULES-1));
+			i2o_dump_message((u32*)m);
+		}	
+	 	i2o_flush_reply(c,mv);
+		mb();
+		mv=I2O_REPLY_READ32(c);
+	}
+}
+
+
+/*
+ *	Do i2o class name lookup
+ */
+const char *i2o_get_class_name(int class)
+{
+	int idx = 16;
+	static char *i2o_class_name[] = {
+		"Executive",
+		"Device Driver Module",
+		"Block Device",
+		"Tape Device",
+		"LAN Interface",
+		"WAN Interface",
+		"Fibre Channel Port",
+		"Fibre Channel Device",
+		"SCSI Device",
+		"ATE Port",
+		"ATE Device",
+		"Floppy Controller",
+		"Floppy Device",
+		"Secondary Bus Port",
+		"Peer Transport Agent",
+		"Peer Transport",
+		"Unknown"
+	};
+	
+	switch(class&0xFFF)
+	{
+		case I2O_CLASS_EXECUTIVE:
+			idx = 0; break;
+		case I2O_CLASS_DDM:
+			idx = 1; break;
+		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+			idx = 2; break;
+		case I2O_CLASS_SEQUENTIAL_STORAGE:
+			idx = 3; break;
+		case I2O_CLASS_LAN:
+			idx = 4; break;
+		case I2O_CLASS_WAN:
+			idx = 5; break;
+		case I2O_CLASS_FIBRE_CHANNEL_PORT:
+			idx = 6; break;
+		case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
+			idx = 7; break;
+		case I2O_CLASS_SCSI_PERIPHERAL:
+			idx = 8; break;
+		case I2O_CLASS_ATE_PORT:
+			idx = 9; break;
+		case I2O_CLASS_ATE_PERIPHERAL:
+			idx = 10; break;
+		case I2O_CLASS_FLOPPY_CONTROLLER:
+			idx = 11; break;
+		case I2O_CLASS_FLOPPY_DEVICE:
+			idx = 12; break;
+		case I2O_CLASS_BUS_ADAPTER_PORT:
+			idx = 13; break;
+		case I2O_CLASS_PEER_TRANSPORT_AGENT:
+			idx = 14; break;
+		case I2O_CLASS_PEER_TRANSPORT:
+			idx = 15; break;
+	}
+
+	return i2o_class_name[idx];
+}
+
+
+/*
+ *	Wait up to 5 seconds for a message slot to be available.
+ */
+ 
+u32 i2o_wait_message(struct i2o_controller *c, char *why)
+{
+	long time=jiffies;
+	u32 m;
+	while((m=I2O_POST_READ32(c))==0xFFFFFFFF)
+	{
+		if((jiffies-time)>=5*HZ)
+		{
+			dprintk((KERN_ERR "%s: Timeout waiting for message frame (%s).\n", 
+				c->name, why));
+			return 0xFFFFFFFF;
+		}
+		schedule();
+		barrier();
+	}
+	return m;
+}
+
+
+/*
+ *	Wait up to timeout seconds for a reply to be available.
+ */
+ 
+u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout)
+{
+	u32 m;
+	long time=jiffies;
+	
+	while((m=I2O_REPLY_READ32(c))==0xFFFFFFFF)
+	{
+		if(jiffies-time >= timeout*HZ )
+		{
+			dprintk((KERN_ERR "%s: timeout waiting for %s reply.\n",
+				c->name, why));
+			return 0xFFFFFFFF;
+		}
+		schedule();
+	}
+	return m;
+}
+	
+
+/*
+ *	 Dump the information block associated with a given unit (TID)
+ */
+ 
+void i2o_report_controller_unit(struct i2o_controller *c, int unit)
+{
+	char buf[64];
+	
+	if(i2o_query_scalar(c, unit, 0xF100, 3, buf, 16)>=0)
+	{
+		buf[16]=0;
+		printk(KERN_INFO "     Vendor: %s", buf);
+	}
+	if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16)>=0)
+	{
+		buf[16]=0;
+		printk("     Device: %s", buf);
+	}
+#if 0
+	if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0)
+	{
+		buf[16]=0;
+		printk("Description: %s", buf);
+	}
+#endif	
+	if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8)>=0)
+	{
+		buf[8]=0;
+		printk("        Rev: %s\n", buf);
+	}
+}
+
+
+/*
+ *	Parse the hardware resource table. Right now we print it out
+ *	and don't do a lot with it. We should collate these and then
+ *	interact with the Linux resource allocation block.
+ *
+ *	Lets prove we can read it first eh ?
+ *
+ *	This is full of endianisms!
+ */
+ 
+static int i2o_parse_hrt(struct i2o_controller *c)
+{
+#ifdef DRIVERDEBUG
+	u32 *rows=(u32 *)c->hrt;
+	u8 *p=(u8 *)c->hrt;
+	u8 *d;
+	int count;
+	int length;
+	int i;
+	int state;
+
+	if(p[3]!=0) {
+		printk(KERN_ERR "%s: HRT table for controller is too new a version.\n",
+			c->name);
+		return -1;	
+	}
+	
+	count=p[0]|(p[1]<<8);
+	length = p[2];
+	
+	printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
+		c->name, count, length<<2);
+
+	rows+=2;
+	
+	for(i=0;i<count;i++)
+	{
+		printk(KERN_INFO "Adapter %08X: ", rows[0]);
+		p=(u8 *)(rows+1);
+		d=(u8 *)(rows+2);
+		state=p[1]<<8|p[0];
+		
+		printk("TID %04X:[", state&0xFFF);
+		state>>=12;
+		if(state&(1<<0))
+			printk("H");		/* Hidden */
+		if(state&(1<<2))
+		{
+			printk("P");		/* Present */
+			if(state&(1<<1))
+				printk("C");	/* Controlled */
+		}
+		if(state>9)
+			printk("*");		/* Hard */
+		
+		printk("]:");
+		
+		switch(p[3]&0xFFFF)
+		{
+			case 0:
+				/* Adapter private bus - easy */
+				printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", 
+					p[2], d[1]<<8|d[0], *(u32 *)(d+4));
+				break;
+			case 1:
+				/* ISA bus */
+				printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X",
+					p[2], d[2], d[1]<<8|d[0], *(u32 *)(d+4));
+				break;
+					
+			case 2: /* EISA bus */
+				printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+					p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4));
+				break;
+
+			case 3: /* MCA bus */
+				printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+					p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4));
+				break;
+
+			case 4: /* PCI bus */
+				printk("PCI %d: Bus %d Device %d Function %d",
+					p[2], d[2], d[1], d[0]);
+				break;
+
+			case 0x80: /* Other */
+			default:
+				printk("Unsupported bus type.");
+				break;
+		}
+		printk("\n");
+		rows+=length;
+	}
+
+#endif
+	return 0;
+}
+	
+/*
+ *	The logical configuration table tells us what we can talk to
+ *	on the board. Most of the stuff isn't interesting to us. 
+ */
+
+static int i2o_parse_lct(struct i2o_controller *c)
+{
+	int i;
+	int max;
+	int tid;
+	u32 *p;
+	struct i2o_device *d;
+	char str[22];
+	i2o_lct *lct = c->lct;
+
+	if (lct == NULL) {
+		printk(KERN_ERR "%s: LCT is empty???\n",c->name);
+		return -1;
+	}
+	
+	max = lct->table_size;	
+	max -= 3;
+	max /= 9;
+
+	printk(KERN_INFO "%s: LCT has %d entries.\n", c->name,max);
+	
+	if(lct->iop_flags&(1<<0))
+		printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name);
+		
+	for(i=0;i<max;i++)
+	{
+		d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+		if(d==NULL)
+		{
+			printk(KERN_CRIT "i2o_core: Out of memory for I2O device data.\n");
+			return -ENOMEM;
+		}
+		
+		d->controller = c;
+		d->next = NULL;
+
+		d->lct_data = &lct->lct_entry[i];
+
+		d->flags = 0;
+		tid = d->lct_data->tid;
+		
+		printk(KERN_INFO "Target ID %d.\n", tid);
+
+		i2o_report_controller_unit(c, tid);
+		
+		i2o_install_device(c, d);
+		
+		printk(KERN_INFO "     Class: ");
+		
+		sprintf(str, "%-21s", i2o_get_class_name(d->lct_data->class_id));
+		printk("%s", str);
+
+		printk(" Subclass: 0x%04X                Flags: ", 
+			d->lct_data->sub_class);
+
+		if(d->lct_data->device_flags&(1<<0))
+			printk("C");		// ConfigDialog requested
+		if(d->lct_data->device_flags&(1<<1))
+			printk("M");		// Multi-user capable
+		if(!(d->lct_data->device_flags&(1<<4)))
+			printk("P");		// Peer service enabled!
+		if(!(d->lct_data->device_flags&(1<<5)))
+			printk("m");		// Mgmt service enabled!
+		printk("\n");
+		p+=9;
+	}
+	return 0;
+}
+
+
+/* 
+ * Quiesce IOP. Causes IOP to make external operation quiescend. 
+ * Internal operation of the IOP continues normally.
+ */
+int i2o_quiesce_controller(struct i2o_controller *c)
+{
+	u32 msg[4];
+	int ret;
+
+	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
+
+	if ((c->status_block->iop_state != ADAPTER_STATE_READY) &&
+	    (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
+	{
+		return 0;
+	}
+
+	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
+	/* msg[2] filled in i2o_post_wait */
+	msg[3]=0;
+
+	/* Long timeout needed for quiesce if lots of devices */
+
+	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 120)))
+		printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n", 
+			c->name, ret);
+	else
+		dprintk((KERN_INFO "%s: Quiesced.\n", c->name));
+
+	i2o_status_get(c); // Reread the Status Block
+
+	return ret;
+}
+
+/* 
+ * Enable IOP. Allows the IOP to resume external operations.
+ */
+int i2o_enable_controller(struct i2o_controller *c)
+{
+	u32 msg[4];
+	int ret;
+	
+	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
+	/* msg[2] filled in i2o_post_wait */
+
+	/* How long of a timeout do we need? */
+
+	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
+		printk(KERN_ERR "%s: Could not enable (status=%#10x).\n", 
+			c->name, ret);
+	else
+		dprintk((KERN_INFO "%s: Enabled.\n", c->name));
+
+	i2o_status_get(c);
+
+	return ret;
+}
+
+/* 
+ * Clear an IOP to HOLD state, ie. terminate external operations, clear all 
+ * input queues and prepare for a system restart. IOP's internal operation
+ * continues normally and the outbound queue is alive.
+ * IOP is not expected to rebuild its LCT.
+ */
+int i2o_clear_controller(struct i2o_controller *c)
+{
+	struct i2o_controller *iop;
+	u32 msg[4];
+	int ret;
+
+	/* Quiesce all IOPs first */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		i2o_quiesce_controller(iop);
+
+	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
+	/* msg[2] filled in i2o_post_wait */
+	msg[3]=0;
+
+	if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
+		printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n", 
+			c->name, ret);
+	else
+		dprintk((KERN_INFO "%s: Cleared.\n",c->name));
+
+	i2o_status_get(c);
+
+	/* Enable other IOPs */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		if (iop != c)
+			i2o_enable_controller(iop);		
+
+	return ret;
+}
+
+
+/* 
+ * Reset the IOP into INIT state and wait until IOP gets into RESET state.  
+ * Terminate all external operations, clear IOP's inbound and outbound 
+ * queues, terminate all DDMs, and reload the IOP's operating environment 
+ * and all local DDMs. IOP rebuilds its LCT.
+ */
+static int i2o_reset_controller(struct i2o_controller *c)
+{
+	struct i2o_controller *iop; 
+	u32 m;
+	u8 *status;
+	u32 *msg;
+	long time;
+
+	/* Quiesce all IOPs first */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		i2o_quiesce_controller(iop);
+
+	m=i2o_wait_message(c, "AdapterReset");
+	if(m==0xFFFFFFFF)	
+		return -ETIMEDOUT;
+	msg=(u32 *)(c->mem_offset+m);
+
+	status = kmalloc(4,GFP_KERNEL);
+	if (status==NULL) {
+		printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
+			c->name);
+		return -ENOMEM;
+	}
+	memset(status,0,4);
+
+	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[2]=core_context;
+	msg[3]=0;
+	msg[4]=0;
+	msg[5]=0;
+	msg[6]=virt_to_phys(status);
+	msg[7]=0;	/* 64bit host FIXME */
+
+	i2o_post_message(c,m);
+
+	/* Wait for a reply */
+	time=jiffies;
+	while (status[0]==0)
+	{
+		if((jiffies-time)>=5*HZ)
+		{
+			printk(KERN_ERR "%s: IOP reset timeout.\n", c->name);
+			kfree(status);
+			return -ETIMEDOUT;
+		}
+		schedule();
+		barrier();
+	}
+
+	if (status[0]==0x01) 
+	{
+		/* 
+		 * Once the reset is sent, the IOP goes into the INIT state 
+		 * which is indeterminate.  We need to wait until the IOP 
+		 * has rebooted before we can let the system talk to 
+		 * it. We read the inbound Free_List until a message is 
+		 * available.  If we can't read one in the given amount of 
+		 * time, we assume the IOP could not reboot properly.  
+		 */ 
+
+		time = jiffies; 
+		m = I2O_POST_READ32(c); 
+		while(m == 0XFFFFFFFF) 
+		{ 
+			if((jiffies-time) >= 30*HZ)
+			{
+				printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n",
+						c->name); 
+				kfree(status);
+				return -ETIMEDOUT; 
+			} 
+			schedule(); 
+			barrier(); 
+			m = I2O_POST_READ32(c); 
+		} 
+
+		i2o_flush_reply(c,m);
+
+		dprintk((KERN_INFO "%s: Reset completed.\n", c->name));
+	}
+
+	/* If IopReset was rejected or didn't perform reset, try IopClear */
+
+	i2o_status_get(c);
+	if (status[0] == 0x02 || c->status_block->iop_state != ADAPTER_STATE_RESET)
+	{
+		printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); 
+		i2o_clear_controller(c);
+
+	}
+
+	/* Enable other IOPs */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		if (iop != c)
+			i2o_enable_controller(iop);		
+
+	kfree(status);
+	return 0;
+}
+
+
+int i2o_status_get(struct i2o_controller *c)
+{
+	long time;
+	u32 m;
+	u32 *msg;
+	u8 *status_block;
+
+	if (c->status_block == NULL) {
+		c->status_block = (i2o_status_block *)
+					kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
+		if (c->status_block == NULL)
+		{
+			printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", c->name);
+			return -ENOMEM;
+		}
+	}
+
+	status_block = (u8*)c->status_block;
+	memset(c->status_block,0,sizeof(i2o_status_block));
+
+	m=i2o_wait_message(c, "StatusGet");
+	if(m==0xFFFFFFFF)
+		return -ETIMEDOUT;
+
+	msg=(u32 *)(c->mem_offset+m);
+
+	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[2]=core_context;
+	msg[3]=0;
+	msg[4]=0;
+	msg[5]=0;
+	msg[6]=virt_to_phys(c->status_block);
+	msg[7]=0;	/* 64bit host FIXME */
+	msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
+
+	i2o_post_message(c,m);
+
+	/* Wait for a reply */
+	
+	time=jiffies;
+	while(status_block[87]!=0xFF)
+	{
+		if((jiffies-time)>=5*HZ)
+		{
+			printk(KERN_ERR "%s: Get status timeout.\n",c->name);
+			return -ETIMEDOUT;
+		}
+		schedule();
+		barrier();
+	}
+	
+	/* Ok the reply has arrived. Fill in the important stuff */
+	c->inbound_size = c->status_block->inbound_frame_size *4;
+
+#ifdef DRIVERDEBUG
+	printk(KERN_INFO "%s: State = ", c->name);
+	switch (c->status_block->iop_state) {
+		case 0x01:	
+			printk("INIT\n"); 
+			break;
+		case 0x02:	
+			printk("RESET\n"); 
+			break;
+		case 0x04:	
+			printk("HOLD\n"); 
+			break;
+		case 0x05:	
+			printk("READY\n"); 
+			break;
+		case 0x08:	
+			printk("OPERATIONAL\n"); 
+			break;
+		case 0x10:	
+			printk("FAILED\n"); 
+			break;
+		case 0x11:	
+			printk("FAULTED\n"); 
+			break;
+		default:	
+			printk("%x (unknown !!)\n",c->status_block->iop_state);
+	}
+#endif
+
+	return 0;
+}
+
+
+int i2o_hrt_get(struct i2o_controller *c)
+{
+	u32 msg[6];
+	int ret, size = sizeof(i2o_hrt);
+
+	/* Read first just the header to figure out the real size */
+
+	do  {
+		if (c->hrt == NULL) {
+			c->hrt=kmalloc(size, GFP_KERNEL);
+			if (c->hrt == NULL) {
+				printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name);
+				return -ENOMEM;
+			}
+		}
+
+		msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
+		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
+		/* msg[2] filled in i2o_post_wait */
+		msg[3]= 0;
+		msg[4]= (0xD0000000 | size);	/* Simple transaction */
+		msg[5]= virt_to_phys(c->hrt);	/* Dump it here */
+
+		if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) {
+			printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n",
+				c->name, ret);	
+			return ret;
+		}
+
+		if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) {
+			size = c->hrt->num_entries * c->hrt->entry_len << 2;
+			kfree(c->hrt);
+			c->hrt = NULL;
+		}
+	} while (c->hrt == NULL);
+
+	i2o_parse_hrt(c); // just for debugging
+
+	return 0;
+}
+
+static int i2o_systab_send(struct i2o_controller *iop)
+{
+        u32 msg[12];
+        u32 privmem[2];
+        u32 privio[2];
+        int ret;
+
+	/* See i2o_status_block */
+#if 0
+        iop->status->current_mem_base;
+        iop->status->current_mem_size;
+        iop->status->current_io_base;
+        iop->status->current_io_size;
+#endif
+
+/* FIXME */
+        privmem[0]=iop->priv_mem;       /* Private memory space base address */
+        privmem[1]=iop->priv_mem_size;
+        privio[0]=iop->priv_io;         /* Private I/O address */
+        privio[1]=iop->priv_io_size;
+
+	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
+        msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
+	/* msg[2] filled in i2o_post_wait */
+	msg[3] = 0;
+        msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+        msg[5] = 0;                               /* Segment 0 */
+
+        /* 
+         * Provide three SGL-elements:
+         * System table (SysTab), Private memory space declaration and 
+         * Private i/o space declaration  
+	 */
+        msg[6] = 0x54000000 | sys_tbl_len;
+        msg[7] = virt_to_phys(sys_tbl);
+        msg[8] = 0x54000000 | 0;
+        msg[9] = virt_to_phys(privmem);
+        msg[10] = 0xD4000000 | 0;
+        msg[11] = virt_to_phys(privio);
+
+	if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120)))
+		printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", 
+			iop->name, ret);
+	else
+		dprintk((KERN_INFO "%s: SysTab set.\n", iop->name));
+
+	return ret;	
+
+ }
+
+/*
+ * Initialize I2O subsystem.
+ */
+static void __init i2o_sys_init()
+{
+	struct i2o_controller *iop, *niop = NULL;
+
+	printk(KERN_INFO "Activating I2O controllers\n");
+	printk(KERN_INFO "This may take a few minutes if there are many devices\n");
+
+	/* In INIT state, Activate IOPs */
+
+	for (iop = i2o_controller_chain; iop; iop = niop) {
+		niop = iop->next;
+		i2o_activate_controller(iop);
+	}
+
+	/* Active IOPs in HOLD state */
+
+rebuild_sys_tab:
+	if (i2o_controller_chain == NULL)
+		return;
+
+	/*
+	 * If build_sys_table fails, we kill everything and bail
+	 * as we can't init the IOPs w/o a system table
+	 */	
+	if (i2o_build_sys_table() < 0) {
+		i2o_sys_shutdown();
+		return;
+	}
+
+	/* If IOP don't get online, we need to rebuild the System table */
+	for (iop = i2o_controller_chain; iop; iop = niop) {
+		niop = iop->next;
+		if (i2o_online_controller(iop) < 0)
+			goto rebuild_sys_tab;
+	}
+	
+	/* Active IOPs now in OPERATIONAL state */
+}
+
+/*
+ * Shutdown I2O system
+ */
+static void i2o_sys_shutdown(void)
+{
+	struct i2o_controller *iop, *niop;
+
+	/* Delete all IOPs from the controller chain */
+	/* that will reset all IOPs too */
+
+	for (iop = i2o_controller_chain; iop; iop = niop) {
+		niop = iop->next;
+		i2o_delete_controller(iop);
+	}
+}
+
+/*
+ *	Bring an I2O controller into HOLD state. See the spec.
+ */
+int i2o_activate_controller(struct i2o_controller *iop)
+{
+	/* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */
+	/* In READY state, Get status */
+
+	if (i2o_status_get(iop) < 0) {
+		printk("Unable to obtain status of IOP, attempting a reset.\n");
+		i2o_reset_controller(iop);
+		if (i2o_status_get(iop) < 0) {
+			printk("IOP not responding.\n");
+			i2o_delete_controller(iop);
+			return -1;
+		}
+	}
+
+	if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) {
+		printk(KERN_CRIT "%s: hardware fault\n", iop->name);
+		i2o_delete_controller(iop);
+		return -1;
+	}
+
+//	if (iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
+	if (iop->status_block->iop_state == ADAPTER_STATE_READY ||
+	    iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+	    iop->status_block->iop_state == ADAPTER_STATE_FAILED)
+	{
+		dprintk((KERN_INFO "%s: already running...trying to reset\n",
+				iop->name));
+		i2o_reset_controller(iop);			
+
+		if (i2o_status_get(iop) < 0 || 
+			iop->status_block->iop_state != ADAPTER_STATE_RESET)
+		{
+			printk(KERN_CRIT "%s: Failed to initialize.\n", iop->name);
+			i2o_delete_controller(iop);
+			return -1;
+		}
+	}
+
+	if (i2o_init_outbound_q(iop) < 0) {
+		i2o_delete_controller(iop);
+		return -1;
+	}
+
+	/* In HOLD state */
+	
+	if (i2o_hrt_get(iop) < 0) {
+		i2o_delete_controller(iop);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Clear and (re)initialize IOP's outbound queue
+ */
+int i2o_init_outbound_q(struct i2o_controller *c)
+{
+	u8 *status;
+	u32 m;
+	u32 *msg;
+	u32 time;
+	int i;
+
+	m=i2o_wait_message(c, "OutboundInit");
+	if(m==0xFFFFFFFF)
+		return -ETIMEDOUT;
+	msg=(u32 *)(c->mem_offset+m);
+
+	status = kmalloc(4,GFP_KERNEL);
+	if (status==NULL) {
+		printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
+			c->name);
+		return -ENOMEM;
+	}
+	memset(status, 0, 4);
+	
+	msg[0]= EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6;
+	msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2]= core_context;
+	msg[3]= 0x0106;			/* Transaction context */
+	msg[4]= 4096;			/* Host page frame size */
+	/* Frame size is in words. Pick 128, its what everyone elses uses and
+	   other sizes break some adapters. */
+	msg[5]= (MSG_FRAME_SIZE>>2)<<16|0x80;	/* Outbound msg frame size and Initcode */
+	msg[6]= 0xD0000004;		/* Simple SG LE, EOB */
+	msg[7]= virt_to_bus(status);
+
+	i2o_post_message(c,m);
+	
+	barrier();	
+	time=jiffies;
+	while(status[0]<0x02)
+	{
+		if((jiffies-time)>=5*HZ)
+		{
+			if(status[0]==0x00)
+				printk(KERN_ERR "%s: Ignored queue initialize request.\n",
+					c->name);
+			else
+				printk(KERN_ERR "%s: Outbound queue initialize timeout.\n",
+					c->name);
+			kfree(status);
+			return -ETIMEDOUT;
+		}
+		schedule();
+		barrier();
+	}
+
+	if(status[0] != I2O_CMD_OUTBOUND_INIT_COMPLETE)
+	{
+		printk(KERN_ERR "%s: Outbound queue initialize rejected (%d).\n",
+			c->name, status[0]);
+		kfree(status);
+		return -EINVAL;
+	}
+	/* Alloc space for IOP's outbound queue message frames */
+
+	c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
+	if(c->page_frame==NULL) {
+		printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
+			c->name);
+		kfree(status);
+		return -ENOMEM;
+	}	
+	m=virt_to_phys(c->page_frame);
+	
+	/* Post frames */
+
+	for(i=0; i< NMBR_MSG_FRAMES; i++) {
+  		I2O_REPLY_WRITE32(c,m);
+                mb();
+		m += MSG_FRAME_SIZE;
+	}
+
+	kfree(status);
+	return 0;
+}
+
+/*
+ * Get the IOP's Logical Configuration Table
+ */
+int i2o_lct_get(struct i2o_controller *c)
+{
+	u32 msg[8];
+	int ret, size = c->status_block->expected_lct_size;
+
+	do {
+		if (c->lct == NULL) {
+			c->lct = kmalloc(size, GFP_KERNEL);
+			if(c->lct == NULL) {
+				printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
+					c->name);
+				return -ENOMEM;
+			}
+		}
+		memset(c->lct, 0, size);
+
+		msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+		msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+		/* msg[2] filled in i2o_post_wait */
+		msg[3] = 0;
+		msg[4] = 0xFFFFFFFF;	/* All devices */
+		msg[5] = 0x00000000;	/* Report now */
+		msg[6] = 0xD0000000|size;
+		msg[7] = virt_to_bus(c->lct);
+
+		if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) {
+			printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n", 
+				c->name, ret);	
+			return ret;
+		}
+
+		if (c->lct->table_size << 2 > size) {
+			size = c->lct->table_size << 2;
+			kfree(c->lct);
+			c->lct = NULL;
+		}
+	} while (c->lct == NULL);
+
+        if ((ret=i2o_parse_lct(c)) < 0)
+                return ret;
+
+	return 0;
+}
+
+
+/*
+ *	Bring a controller online into OPERATIONAL state. 
+ */
+ 
+int i2o_online_controller(struct i2o_controller *iop)
+{
+	if (i2o_systab_send(iop) < 0) {
+		i2o_delete_controller(iop);
+		return -1;
+	}
+
+	/* In READY state */
+
+	if (i2o_enable_controller(iop) < 0) {
+		i2o_delete_controller(iop);
+		return -1;
+	}
+
+	/* In OPERATIONAL state  */
+
+	if (i2o_lct_get(iop) < 0){
+		i2o_delete_controller(iop);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int i2o_build_sys_table(void)
+{
+	struct i2o_controller *iop = NULL;
+	int count = 0;
+
+	sys_tbl_len = sizeof(struct i2o_sys_tbl) +	// Header + IOPs
+				(i2o_num_controllers) *
+					sizeof(struct i2o_sys_tbl_entry);
+
+	if(sys_tbl)
+		kfree(sys_tbl);
+
+	sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL);
+	if(!sys_tbl) {
+		printk(KERN_CRIT "SysTab Set failed. Out of memory.\n");	
+		return -ENOMEM;
+	}
+	memset((void*)sys_tbl, 0, sys_tbl_len);
+
+	sys_tbl->num_entries = i2o_num_controllers;
+	sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */
+	sys_tbl->change_ind = sys_tbl_ind++;
+
+	for(iop = i2o_controller_chain; iop; iop = iop->next)
+	{
+		// Get updated Status Block so we have the latest information
+		if (i2o_status_get(iop)) {
+			sys_tbl->num_entries--;
+			continue; // try next one	
+		}
+
+		sys_tbl->iops[count].org_id = iop->status_block->org_id;
+		sys_tbl->iops[count].iop_id = iop->unit + 2;
+		sys_tbl->iops[count].seg_num = 0;
+		sys_tbl->iops[count].i2o_version = 
+				iop->status_block->i2o_version;
+		sys_tbl->iops[count].iop_state = 
+				iop->status_block->iop_state;
+		sys_tbl->iops[count].msg_type = 
+				iop->status_block->msg_type;
+		sys_tbl->iops[count].frame_size = 
+				iop->status_block->inbound_frame_size;
+		sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
+		sys_tbl->iops[count].iop_capabilities = 
+				iop->status_block->iop_capabilities;
+		sys_tbl->iops[count].inbound_low = 
+				(u32)virt_to_phys(iop->post_port);
+		sys_tbl->iops[count].inbound_high = 0;	// TODO: 64-bit support
+
+		count++;
+	}
+
+#ifdef DRIVERDEBUG
+{
+	u32 *table = (u32*)sys_tbl;
+	for(count = 0; count < (sys_tbl_len >>2); count++)
+		printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", 
+			count, table[count]);
+}
+#endif
+
+	return 0;
+}
+
+
+/*
+ *	Run time support routines
+ */
+ 
+/*
+ *	Generic "post and forget" helpers. This is less efficient - we do
+ *	a memcpy for example that isnt strictly needed, but for most uses
+ *	this is simply not worth optimising
+ */
+
+int i2o_post_this(struct i2o_controller *c, u32 *data, int len)
+{
+	u32 m;
+	u32 *msg;
+	unsigned long t=jiffies;
+
+	do
+	{
+		mb();
+		m = I2O_POST_READ32(c);
+	}
+	while(m==0xFFFFFFFF && (jiffies-t)<HZ);
+	
+	
+	if(m==0xFFFFFFFF)
+	{
+		printk(KERN_ERR "%s: Timeout waiting for message frame!\n",
+				c->name);
+		return -ETIMEDOUT;
+	}
+
+	msg = (u32 *)(c->mem_offset + m);
+	memcpy_toio(msg, data, len);
+	i2o_post_message(c,m);
+	return 0;
+}
+
+/*
+ *	Post a message and wait for a response flag to be set.
+ */
+int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
+{
+	struct wait_queue *wq_i2o_post = NULL;
+	int status = 0;
+	int flags = 0;
+	struct i2o_post_wait_data *p1, *p2;
+	struct i2o_post_wait_data *wait_data =
+		kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);
+
+	if(!wait_data)
+		return -ENOMEM;
+
+	/* 
+	 * The spin locking is needed to keep anyone from playing 
+	 * with the queue pointers and id while we do the same
+	 */
+	spin_lock_irqsave(&post_wait_lock, flags);
+	wait_data->next = post_wait_queue;
+	post_wait_queue = wait_data;
+	wait_data->id = (++post_wait_id) & 0x7fff;
+	spin_unlock_irqrestore(&post_wait_lock, flags);
+
+	wait_data->wq = &wq_i2o_post;
+	wait_data->status = -EAGAIN;
+
+	msg[2]=0x80000000|(u32)core_context|((u32)wait_data->id<<16);
+
+	if ((status = i2o_post_this(c, msg, len))==0) {
+		interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout);
+		status = wait_data->status;
+	}
+
+	p2 = NULL;
+	spin_lock_irqsave(&post_wait_lock, flags);
+	for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) {
+		if(p1 == wait_data) {
+			if(p2)
+				p2->next = p1->next;
+			else
+				post_wait_queue = p1->next;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&post_wait_lock, flags);
+	
+	kfree(wait_data);
+
+	return status;
+}
+
+/*
+ * i2o_post_wait is completed and we want to wake up the 
+ * sleeping proccess. Called by core's reply handler.
+ */
+static void i2o_post_wait_complete(u32 context, int status)
+{
+	struct i2o_post_wait_data *p1;
+
+	/* 
+	 * We need to search through the post_wait 
+	 * queue to see if the given message is still
+	 * outstanding.  If not, it means that the IOP 
+	 * took longer to respond to the message than we 
+	 * had allowed and timer has already expired.  
+	 * Not much we can do about that except log
+	 * it for debug purposes, increase timeout, and recompile
+	 *
+	 * Lock needed to keep anyone from moving queue pointers 
+	 * around while we're looking through them.
+	 */
+	spin_lock(&post_wait_lock);
+	for(p1 = post_wait_queue; p1; p1 = p1->next) {
+		if(p1->id == ((context >> 16) & 0x7fff)) {
+			p1->status = status;
+			spin_unlock(&post_wait_lock);
+			wake_up_interruptible(p1->wq);
+			return;
+		}
+	}
+	spin_unlock(&post_wait_lock);
+
+	printk(KERN_DEBUG "i2o: i2o_post_wait reply after timeout!");
+}
+
+/*
+ *      Send UTIL_EVENT messages
+ */
+
+int i2o_event_register(struct i2o_controller *c, int tid, int context,
+                        u32 evt_mask)
+{
+        u32 msg[5];
+
+        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+        msg[1] = I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | tid;
+        msg[2] = context;
+        msg[3] = 0;
+        msg[4] = evt_mask;
+
+        if (i2o_post_this(c, msg, sizeof(msg)) < 0)
+                return -ETIMEDOUT;
+
+        return 0;
+}
+
+int i2o_event_ack(struct i2o_controller *c, int tid, int context,
+                u32 evt_indicator, void *evt_data, int evt_data_len)
+{
+        u32 msg[c->inbound_size];
+
+        msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5;
+        msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid;
+	msg[2] = context;
+	msg[3] = 0;
+        msg[4] = evt_indicator;
+        memcpy(msg+5, evt_data, evt_data_len);
+
+        if (i2o_post_this(c, msg, sizeof(msg)) < 0)
+                return -ETIMEDOUT;
+
+        return 0;
+}
+
+/*
+ *	Issue UTIL_CLAIM or UTIL_RELEASE messages
+ */
+ 
+static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, u32 type)
+{
+	u32 msg[5];
+
+	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+	if(onoff)
+		msg[1] = I2O_CMD_UTIL_CLAIM << 24 | HOST_TID<<12 | tid;
+	else	
+		msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid;
+
+	/* msg[2] filled in i2o_post_wait */	
+	msg[3] = 0;
+	msg[4] = type;
+
+	return i2o_post_wait(c, msg, sizeof(msg), 2);
+}
+
+/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
+ *
+ *	This function can be used for all UtilParamsGet/Set operations.
+ *	The OperationBlock is given in opblk-buffer, 
+ *	and results are returned in resblk-buffer.
+ *	Note that the minimum sized resblk is 8 bytes and contains
+ *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
+ */
+int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, 
+                void *opblk, int oplen, void *resblk, int reslen)
+{
+	u32 msg[9]; 
+	u32 *res = (u32 *)resblk;
+	int wait_status;
+
+	msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
+	msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
+	/* msg[2] filled in i2o_post_wait */
+	msg[3] = 0;
+	msg[4] = 0;
+	msg[5] = 0x54000000 | oplen;	/* OperationBlock */
+	msg[6] = virt_to_bus(opblk);
+	msg[7] = 0xD0000000 | reslen;	/* ResultBlock */
+	msg[8] = virt_to_bus(resblk);
+
+	if ((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 20)))
+   		return wait_status; 	/* -DetailedStatus */
+
+	if (res[1]&0x00FF0000) 	/* BlockStatus != SUCCESS */
+	{
+		printk(KERN_WARNING "%s: %s - Error:\n  ErrorInfoSize = 0x%02x, "
+			"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+			iop->name,
+			(cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
+							 : "PARAMS_GET",   
+			res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
+		return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
+	}
+
+        return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ 
+}
+
+/*
+ *	 Query one scalar group value or a whole scalar group.
+ */                  	
+int i2o_query_scalar(struct i2o_controller *iop, int tid, 
+                     int group, int field, void *buf, int buflen)
+{
+	u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
+	u8  resblk[8+buflen]; /* 8 bytes for header */
+	int size;
+
+	if (field == -1)  		/* whole group */
+       		opblk[4] = -1;
+
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, 
+		opblk, sizeof(opblk), resblk, sizeof(resblk));
+			
+	if (size < 0)
+		return size;	
+
+	memcpy(buf, resblk+8, buflen);  /* cut off header */
+	return buflen;
+}
+
+/*
+ *	Set a scalar group value or a whole group.
+ */
+int i2o_set_scalar(struct i2o_controller *iop, int tid, 
+		   int group, int field, void *buf, int buflen)
+{
+	u16 *opblk;
+	u8  resblk[8+buflen]; /* 8 bytes for header */
+        int size;
+
+	opblk = kmalloc(buflen+64, GFP_KERNEL);
+	if (opblk == NULL)
+	{
+		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+		return -ENOMEM;
+	}
+
+	opblk[0] = 1;                        /* operation count */
+	opblk[1] = 0;                        /* pad */
+	opblk[2] = I2O_PARAMS_FIELD_SET;
+	opblk[3] = group;
+
+	if(field == -1) {               /* whole group */
+		opblk[4] = -1;
+		memcpy(opblk+5, buf, buflen);
+	}
+	else                            /* single field */
+	{
+		opblk[4] = 1;
+		opblk[5] = field;
+		memcpy(opblk+6, buf, buflen);
+	}   
+
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
+				opblk, 12+buflen, resblk, sizeof(resblk));
+
+	kfree(opblk);
+	return size;
+}
+
+/* 
+ * 	if oper == I2O_PARAMS_TABLE_GET: 
+ *		Get all table group fields from all rows or
+ *		get specific table group fields from all rows.
+ *
+ * 		if fieldcount == -1 we query all fields from all rows
+ *			ibuf is NULL and ibuflen is 0
+ * 		else we query specific fields from all rows
+ *  			ibuf contains fieldindexes
+ *
+ * 	if oper == I2O_PARAMS_LIST_GET:
+ *		Get all table group fields from specified rows or
+ *		get specific table group fields from specified rows.
+ *
+ * 		if fieldcount == -1 we query all fields from specified rows
+ *			ibuf contains rowcount, keyvalues
+ * 		else we query specific fields from specified rows
+ *  			ibuf contains fieldindexes, rowcount, keyvalues
+ *
+ *	You could also use directly function i2o_issue_params().
+ */
+int i2o_query_table(int oper, struct i2o_controller *iop, int tid, int group,
+		int fieldcount, void *ibuf, int ibuflen,
+		void *resblk, int reslen) 
+{
+	u16 *opblk;
+	int size;
+
+	opblk = kmalloc(10 + ibuflen, GFP_KERNEL);
+	if (opblk == NULL)
+	{
+		printk(KERN_ERR "i2o: no memory for query buffer.\n");
+		return -ENOMEM;
+	}
+
+	opblk[0] = 1;				/* operation count */
+	opblk[1] = 0;				/* pad */
+	opblk[2] = oper;
+	opblk[3] = group;		
+	opblk[4] = fieldcount;
+	memcpy(opblk+5, ibuf, ibuflen);		/* other params */
+
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, 
+				opblk, 10+ibuflen, resblk, reslen);
+
+	kfree(opblk);
+	return size;
+}
+
+/*
+ * 	Clear table group, i.e. delete all rows.
+ */
+
+int i2o_clear_table(struct i2o_controller *iop, int tid, int group)
+{
+	u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group };
+	u8  resblk[32]; /* min 8 bytes for result header */
+
+	return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
+				opblk, sizeof(opblk), resblk, sizeof(resblk));
+}
+
+/*
+ * 	Add a new row into a table group.
+ *
+ * 	if fieldcount==-1 then we add whole rows
+ *		buf contains rowcount, keyvalues
+ * 	else just specific fields are given, rest use defaults
+ *  		buf contains fieldindexes, rowcount, keyvalues
+ */	
+
+int i2o_row_add_table(struct i2o_controller *iop, int tid,
+		    int group, int fieldcount, void *buf, int buflen)
+{
+	u16 *opblk;
+	u8  resblk[32]; /* min 8 bytes for header */
+	int size;
+
+	opblk = kmalloc(buflen+64, GFP_KERNEL);
+	if (opblk == NULL)
+	{
+		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+		return -ENOMEM;
+	}
+
+	opblk[0] = 1;			/* operation count */
+	opblk[1] = 0;			/* pad */
+	opblk[2] = I2O_PARAMS_ROW_ADD;
+	opblk[3] = group;	
+	opblk[4] = fieldcount;
+	memcpy(opblk+5, buf, buflen);
+
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, 
+				opblk, 10+buflen, resblk, sizeof(resblk));
+
+	kfree(opblk);
+	return size;
+}
+
+/*
+ *	Delete rows from a table group.
+ */ 
+
+int i2o_row_delete_table(struct i2o_controller *iop, int tid,
+		    int group, int keycount, void *keys, int keyslen)
+{
+	u16 *opblk; 
+	u8  resblk[32]; /* min 8 bytes for header */
+	int size;
+
+	opblk = kmalloc(keyslen+64, GFP_KERNEL);
+	if (opblk == NULL)
+	{
+		printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+		return -ENOMEM;
+	}
+
+	opblk[0] = 1;			/* operation count */
+	opblk[1] = 0;			/* pad */
+	opblk[2] = I2O_PARAMS_ROW_DELETE;
+	opblk[3] = group;	
+	opblk[4] = keycount;
+	memcpy(opblk+5, keys, keyslen);
+
+	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid,
+				opblk, 10+keyslen, resblk, sizeof(resblk));
+
+	kfree(opblk);
+	return size;
+}
+
+void i2o_report_common_status(u8 req_status)
+{
+	/* the following reply status strings are common to all classes */
+
+	static char *REPLY_STATUS[] = { 
+		"SUCCESS", 
+		"ABORT_DIRTY", 
+		"ABORT_NO_DATA_TRANSFER",
+		"ABORT_PARTIAL_TRANSFER",
+		"ERROR_DIRTY",
+		"ERROR_NO_DATA_TRANSFER",
+		"ERROR_PARTIAL_TRANSFER",
+		"PROCESS_ABORT_DIRTY",
+		"PROCESS_ABORT_NO_DATA_TRANSFER",
+		"PROCESS_ABORT_PARTIAL_TRANSFER",
+		"TRANSACTION_ERROR",
+		"PROGRESS_REPORT"	
+	};
+
+	if (req_status > I2O_REPLY_STATUS_PROGRESS_REPORT)
+		printk("%0#4x / ", req_status);
+	else
+		printk("%s / ", REPLY_STATUS[req_status]);
+	
+	return;
+}
+
+static void i2o_report_common_dsc(u16 detailed_status)
+{
+	/* The following detailed statuscodes are valid 
+	   - for executive class, utility class, DDM class and
+	   - for transaction error replies
+	*/	
+
+	static char *COMMON_DSC[] = { 
+		"SUCCESS",
+		"0x01",				// not used
+		"BAD_KEY",
+		"TCL_ERROR",
+		"REPLY_BUFFER_FULL",
+		"NO_SUCH_PAGE",
+		"INSUFFICIENT_RESOURCE_SOFT",
+		"INSUFFICIENT_RESOURCE_HARD",
+		"0x08",				// not used
+		"CHAIN_BUFFER_TOO_LARGE",
+		"UNSUPPORTED_FUNCTION",
+		"DEVICE_LOCKED",
+		"DEVICE_RESET",
+		"INAPPROPRIATE_FUNCTION",
+		"INVALID_INITIATOR_ADDRESS",
+		"INVALID_MESSAGE_FLAGS",
+		"INVALID_OFFSET",
+		"INVALID_PARAMETER",
+		"INVALID_REQUEST",
+		"INVALID_TARGET_ADDRESS",
+		"MESSAGE_TOO_LARGE",
+		"MESSAGE_TOO_SMALL",
+		"MISSING_PARAMETER",
+		"TIMEOUT",
+		"UNKNOWN_ERROR",
+		"UNKNOWN_FUNCTION",
+		"UNSUPPORTED_VERSION",
+		"DEVICE_BUSY",
+		"DEVICE_NOT_AVAILABLE"		
+	};
+
+	if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
+		printk("%0#4x.\n", detailed_status);
+	else
+		printk("%s.\n", COMMON_DSC[detailed_status]);
+
+	return;
+}
+
+static void i2o_report_util_cmd(u8 cmd)
+{
+	switch (cmd) {
+	case I2O_CMD_UTIL_NOP:
+		printk("UTIL_NOP, ");
+		break;			
+	case I2O_CMD_UTIL_ABORT:
+		printk("UTIL_ABORT, ");
+		break;
+	case I2O_CMD_UTIL_CLAIM:
+		printk("UTIL_CLAIM, ");
+		break;
+	case I2O_CMD_UTIL_RELEASE:
+		printk("UTIL_CLAIM_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_CONFIG_DIALOG:
+		printk("UTIL_CONFIG_DIALOG, ");
+		break;
+	case I2O_CMD_UTIL_DEVICE_RESERVE:
+		printk("UTIL_DEVICE_RESERVE, ");
+		break;
+	case I2O_CMD_UTIL_DEVICE_RELEASE:
+		printk("UTIL_DEVICE_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_EVT_ACK:
+		printk("UTIL_EVENT_ACKNOWLEDGE, ");
+		break;
+	case I2O_CMD_UTIL_EVT_REGISTER:
+		printk("UTIL_EVENT_REGISTER, ");
+		break;
+	case I2O_CMD_UTIL_LOCK:
+		printk("UTIL_LOCK, ");
+		break;
+	case I2O_CMD_UTIL_LOCK_RELEASE:
+		printk("UTIL_LOCK_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_PARAMS_GET:
+		printk("UTIL_PARAMS_GET, ");
+		break;
+	case I2O_CMD_UTIL_PARAMS_SET:
+		printk("UTIL_PARAMS_SET, ");
+		break;
+	case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
+		printk("UTIL_REPLY_FAULT_NOTIFY, ");
+		break;
+	default:
+		printk("%0#2x, ",cmd);	
+	}
+
+	return;	
+}
+
+
+static void i2o_report_exec_cmd(u8 cmd)
+{
+	switch (cmd) {
+	case I2O_CMD_ADAPTER_ASSIGN:
+		printk("EXEC_ADAPTER_ASSIGN, ");
+		break;
+	case I2O_CMD_ADAPTER_READ:
+		printk("EXEC_ADAPTER_READ, ");
+		break;
+	case I2O_CMD_ADAPTER_RELEASE:
+		printk("EXEC_ADAPTER_RELEASE, ");
+		break;
+	case I2O_CMD_BIOS_INFO_SET:
+		printk("EXEC_BIOS_INFO_SET, ");
+		break;
+	case I2O_CMD_BOOT_DEVICE_SET:
+		printk("EXEC_BOOT_DEVICE_SET, ");
+		break;
+	case I2O_CMD_CONFIG_VALIDATE:
+		printk("EXEC_CONFIG_VALIDATE, ");
+		break;
+	case I2O_CMD_CONN_SETUP:
+		printk("EXEC_CONN_SETUP, ");
+		break;
+	case I2O_CMD_DDM_DESTROY:
+		printk("EXEC_DDM_DESTROY, ");
+		break;
+	case I2O_CMD_DDM_ENABLE:
+		printk("EXEC_DDM_ENABLE, ");
+		break;
+	case I2O_CMD_DDM_QUIESCE:
+		printk("EXEC_DDM_QUIESCE, ");
+		break;
+	case I2O_CMD_DDM_RESET:
+		printk("EXEC_DDM_RESET, ");
+		break;
+	case I2O_CMD_DDM_SUSPEND:
+		printk("EXEC_DDM_SUSPEND, ");
+		break;
+	case I2O_CMD_DEVICE_ASSIGN:
+		printk("EXEC_DEVICE_ASSIGN, ");
+		break;
+	case I2O_CMD_DEVICE_RELEASE:
+		printk("EXEC_DEVICE_RELEASE, ");
+		break;
+	case I2O_CMD_HRT_GET:
+		printk("EXEC_HRT_GET, ");
+		break;
+	case I2O_CMD_ADAPTER_CLEAR:
+		printk("EXEC_IOP_CLEAR, ");
+		break;
+	case I2O_CMD_ADAPTER_CONNECT:
+		printk("EXEC_IOP_CONNECT, ");
+		break;
+	case I2O_CMD_ADAPTER_RESET:
+		printk("EXEC_IOP_RESET, ");
+		break;
+	case I2O_CMD_LCT_NOTIFY:
+		printk("EXEC_LCT_NOTIFY, ");
+		break;
+	case I2O_CMD_OUTBOUND_INIT:
+		printk("EXEC_OUTBOUND_INIT, ");
+		break;
+	case I2O_CMD_PATH_ENABLE:
+		printk("EXEC_PATH_ENABLE, ");
+		break;
+	case I2O_CMD_PATH_QUIESCE:
+		printk("EXEC_PATH_QUIESCE, ");
+		break;
+	case I2O_CMD_PATH_RESET:
+		printk("EXEC_PATH_RESET, ");
+		break;
+	case I2O_CMD_STATIC_MF_CREATE:
+		printk("EXEC_STATIC_MF_CREATE, ");
+		break;
+	case I2O_CMD_STATIC_MF_RELEASE:
+		printk("EXEC_STATIC_MF_RELEASE, ");
+		break;
+	case I2O_CMD_STATUS_GET:
+		printk("EXEC_STATUS_GET, ");
+		break;
+	case I2O_CMD_SW_DOWNLOAD:
+		printk("EXEC_SW_DOWNLOAD, ");
+		break;
+	case I2O_CMD_SW_UPLOAD:
+		printk("EXEC_SW_UPLOAD, ");
+		break;
+	case I2O_CMD_SW_REMOVE:
+		printk("EXEC_SW_REMOVE, ");
+		break;
+	case I2O_CMD_SYS_ENABLE:
+		printk("EXEC_SYS_ENABLE, ");
+		break;
+	case I2O_CMD_SYS_MODIFY:
+		printk("EXEC_SYS_MODIFY, ");
+		break;
+	case I2O_CMD_SYS_QUIESCE:
+		printk("EXEC_SYS_QUIESCE, ");
+		break;
+	case I2O_CMD_SYS_TAB_SET:
+		printk("EXEC_SYS_TAB_SET, ");
+		break;
+	default:
+		printk("%02x, ",cmd);	
+	}
+
+	return;	
+}
+
+/* TODO: Add support for other classes */
+void i2o_report_status(const char *severity, const char *module, u32 *msg)
+{
+	u8 cmd = (msg[1]>>24)&0xFF;
+	u8 req_status = (msg[4]>>24)&0xFF;
+	u16 detailed_status = msg[4]&0xFFFF;
+
+	printk("%s%s: ", severity, module);
+
+	if (cmd < 0x1F) { 			// Utility Class
+		i2o_report_util_cmd(cmd);
+		i2o_report_common_status(req_status);
+		i2o_report_common_dsc(detailed_status);
+		return;
+	}
+
+	if (cmd >= 0xA0 && cmd <= 0xEF) {	// Executive class
+		i2o_report_exec_cmd(cmd);
+		i2o_report_common_status(req_status);
+		i2o_report_common_dsc(detailed_status);
+		return;
+	}
+	
+	printk("%02x, %02x / %04x.\n", cmd, req_status, detailed_status);
+	return;
+}
+
+/* Used to dump a message to syslog during debugging */
+void i2o_dump_message(u32 *msg)
+{
+#ifdef DRIVERDEBUG
+	int i;
+
+	printk(KERN_INFO "Dumping I2O message size %d @ %p\n", 
+		msg[0]>>16&0xffff, msg);
+	for(i = 0; i < ((msg[0]>>16)&0xffff); i++)
+		printk(KERN_INFO "  msg[%d] = %0#10x\n", i, msg[i]);
+#endif
+}
+
+#ifdef MODULE
+
+EXPORT_SYMBOL(i2o_install_handler);
+EXPORT_SYMBOL(i2o_remove_handler);
+
+EXPORT_SYMBOL(i2o_install_controller);
+EXPORT_SYMBOL(i2o_delete_controller);
+EXPORT_SYMBOL(i2o_unlock_controller);
+EXPORT_SYMBOL(i2o_find_controller);
+EXPORT_SYMBOL(i2o_num_controllers);
+
+EXPORT_SYMBOL(i2o_event_register);
+EXPORT_SYMBOL(i2o_event_ack);
+
+EXPORT_SYMBOL(i2o_claim_device);
+EXPORT_SYMBOL(i2o_release_device);
+EXPORT_SYMBOL(i2o_run_queue);
+EXPORT_SYMBOL(i2o_activate_controller);
+EXPORT_SYMBOL(i2o_get_class_name);
+EXPORT_SYMBOL(i2o_status_get);
+
+EXPORT_SYMBOL(i2o_query_scalar);
+EXPORT_SYMBOL(i2o_set_scalar);
+EXPORT_SYMBOL(i2o_query_table);
+EXPORT_SYMBOL(i2o_clear_table);
+EXPORT_SYMBOL(i2o_row_add_table);
+
+EXPORT_SYMBOL(i2o_post_this);
+EXPORT_SYMBOL(i2o_post_wait);
+EXPORT_SYMBOL(i2o_issue_params);
+
+EXPORT_SYMBOL(i2o_report_status);
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O Core");
+
+int init_module(void)
+{
+	printk(KERN_INFO "I2O Core - (c) Copyright 1999 Red Hat Software.\n");
+	if (i2o_install_handler(&i2o_core_handler) < 0)
+	{
+		printk(KERN_ERR 
+			"i2o: Unable to install core handler.\nI2O stack not loaded!");
+		return 0;
+	}
+
+	core_context = i2o_core_handler.context;
+	/*
+	 * Attach core to I2O PCI transport (and others as they are developed)
+	 */
+#ifdef CONFIG_I2O_PCI_MODULE
+	if(i2o_pci_core_attach(&i2o_core_functions) < 0)
+		printk(KERN_INFO "i2o: No PCI I2O controllers found\n");
+#endif
+
+	if(i2o_num_controllers)
+		i2o_sys_init();
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if(i2o_num_controllers)
+		i2o_sys_shutdown();
+
+#ifdef CONFIG_I2O_PCI_MODULE
+	i2o_pci_core_detach();
+#endif
+
+	i2o_remove_handler(&i2o_core_handler);
+}
+
+#else
+
+extern int i2o_block_init(void);
+extern int i2o_config_init(void);
+extern int i2o_lan_init(void);
+extern int i2o_pci_init(void);
+extern int i2o_proc_init(void);
+extern int i2o_scsi_init(void);
+
+int __init i2o_init(void)
+{
+	printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n");
+	if (i2o_install_handler(&i2o_core_handler) < 0)
+	{
+		printk(KERN_ERR 
+			"i2o_core: Unable to install core handler.\nI2O stack not loaded!");
+		return 0;
+	}
+
+	core_context = i2o_core_handler.context;
+
+#ifdef CONFIG_I2O_PCI
+	i2o_pci_init();
+#endif
+
+	if(i2o_num_controllers)
+		i2o_sys_init();
+
+	i2o_config_init();
+#ifdef CONFIG_I2O_BLOCK
+	i2o_block_init();
+#endif
+#ifdef CONFIG_I2O_SCSI
+	i2o_scsi_init();
+#endif
+#ifdef CONFIG_I2O_LAN
+	i2o_lan_init();
+#endif
+#ifdef CONFIG_I2O_PROC
+	i2o_proc_init();
+#endif
+	return 0;
+}
+
+#endif
diff -urN linux-2.2.15-pre9/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- linux-2.2.15-pre9/drivers/i2o/i2o_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/i2o_pci.c	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,339 @@
+/*
+ *	Find I2O capable controllers on the PCI bus, and register/install
+ *	them with the I2O layer
+ *
+ *	(C) Copyright 1999   Red Hat Software
+ *	
+ *	Written by Alan Cox, Building Number Three Ltd
+ * 	Modified by Deepak Saxena <deepak@plexity.net>
+ *
+ *	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.
+ *
+ *	TODO:
+ *		Support polled I2O PCI controllers. 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/i2o.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif // CONFIG_MTRR
+
+#ifdef MODULE
+/*
+ * Core function table
+ * See <include/linux/i2o.h> for an explanation
+ */
+static struct i2o_core_func_table *core;
+
+/* Core attach function */
+extern int i2o_pci_core_attach(struct i2o_core_func_table *);
+extern void i2o_pci_core_detach(void);
+#endif /* MODULE */
+
+/*
+ *	Free bus specific resources
+ */
+static void i2o_pci_dispose(struct i2o_controller *c)
+{
+	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
+	if(c->bus.pci.irq > 0)
+		free_irq(c->bus.pci.irq, c);
+	iounmap(((u8 *)c->post_port)-0x40);
+
+#ifdef CONFIG_MTRR
+	if(c->bus.pci.mtrr_reg > 0)
+		mtrr_del(c->bus.pci.mtrr_reg, 0, 0);
+#endif
+}
+
+/*
+ *	No real bus specific handling yet (note that later we will
+ *	need to 'steal' PCI devices on i960 mainboards)
+ */
+ 
+static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * Bus specific enable/disable functions
+ */
+static void i2o_pci_enable(struct i2o_controller *c)
+{
+	I2O_IRQ_WRITE32(c, 0);
+	c->enabled = 1;
+}
+
+static void i2o_pci_disable(struct i2o_controller *c)
+{
+	I2O_IRQ_WRITE32(c, 0xFFFFFFFF);
+	c->enabled = 0;
+}
+
+/*
+ *	Bus specific interrupt handler
+ */
+ 
+static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
+{
+	struct i2o_controller *c = dev_id;
+#ifdef MODULE
+	core->run_queue(c);
+#else
+	i2o_run_queue(c);
+#endif /* MODULE */
+}	
+
+/*
+ *	Install a PCI (or in theory AGP) i2o controller
+ *
+ * TODO: Add support for polled controllers
+ */
+int __init i2o_pci_install(struct pci_dev *dev)
+{
+	struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller),
+						GFP_KERNEL);
+	u8 *mem;
+	u32 memptr = 0;
+	u32 size;
+	
+	int i;
+
+	if(c==NULL)
+	{
+		printk(KERN_ERR "i2o: Insufficient memory to add controller.\n");
+		return -ENOMEM;
+	}
+	memset(c, 0, sizeof(*c));
+
+	for(i=0; i<6; i++)
+	{
+		/* Skip I/O spaces */
+		if(!(dev->base_address[i]&PCI_BASE_ADDRESS_SPACE))
+		{
+			memptr=dev->base_address[i]&~3;
+			break;
+		}
+	}
+	
+	if(i==6)
+	{
+		printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n");
+		kfree(c);
+		return -EINVAL;
+	}
+	
+
+        pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, ~0);
+	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, &size);
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, dev->base_address[i]);
+	
+	size=~(size&PCI_BASE_ADDRESS_MEM_MASK);
+	size++;	/* mind the fence */
+	
+	/* Map the I2O controller */
+	
+	printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size);
+	mem = ioremap(memptr, size);
+	if(mem==NULL)
+	{
+		printk(KERN_ERR "i2o: Unable to map controller.\n");
+		kfree(c);
+		return -EINVAL;
+	}
+
+	c->bus.pci.irq = -1;
+
+	c->irq_mask = (volatile u32 *)(mem+0x34);
+	c->post_port = (volatile u32 *)(mem+0x40);
+	c->reply_port = (volatile u32 *)(mem+0x44);
+
+	c->mem_phys = memptr;
+	c->mem_offset = (u32)mem;
+	c->destructor = i2o_pci_dispose;
+	
+	c->bind = i2o_pci_bind;
+	c->unbind = i2o_pci_unbind;
+	c->bus_enable = i2o_pci_enable;
+	c->bus_disable = i2o_pci_disable;
+	
+	c->type = I2O_TYPE_PCI;
+
+	/* 
+	 * Enable Write Combining MTRR for IOP's memory region
+	 */
+#ifdef CONFIG_MTRR
+	c->bus.pci.mtrr_reg = 
+		mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1);
+#endif
+
+	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
+
+#ifdef MODULE
+	i = core->install(c);
+#else
+	i = i2o_install_controller(c);
+#endif /* MODULE */
+	
+	if(i<0)
+	{
+		printk(KERN_ERR "i2o: Unable to install controller.\n");
+		kfree(c);
+		iounmap(mem);
+		return i;
+	}
+
+	c->bus.pci.irq = dev->irq;
+	if(c->bus.pci.irq)
+	{
+		i=request_irq(dev->irq, i2o_pci_interrupt, SA_SHIRQ,
+			c->name, c);
+		if(i<0)
+		{
+			printk(KERN_ERR "%s: unable to allocate interrupt %d.\n",
+				c->name, dev->irq);
+			c->bus.pci.irq = -1;
+#ifdef MODULE
+			core->delete(c);
+#else
+			i2o_delete_controller(c);
+#endif /* MODULE */	
+			kfree(c);
+			iounmap(mem);
+			return -EBUSY;
+		}
+	}
+
+	printk(KERN_INFO "%s: Installed at IRQ%d\n", c->name, dev->irq);
+	I2O_IRQ_WRITE32(c,0x0);
+	c->enabled = 1;
+	return 0;	
+}
+
+int __init i2o_pci_scan(void)
+{
+	struct pci_dev *dev;
+	int count=0;
+	
+	printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
+
+	for(dev=pci_devices; dev!=NULL; dev=dev->next)
+	{
+		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
+			continue;
+		if((dev->class&0xFF)>1)
+		{
+			printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n");
+			continue;
+		}
+		printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n",
+			dev->bus->number, dev->devfn);
+		pci_set_master(dev);
+		if(i2o_pci_install(dev)==0)
+			count++;
+	}
+	if(count)
+		printk(KERN_INFO "i2o: %d I2O controller%s found and installed.\n", count,
+			count==1?"":"s");
+	return count?count:-ENODEV;
+}
+
+#ifdef I2O_HOTPLUG_SUPPORT
+/*
+ * Activate a newly found PCI I2O controller
+ * Not used now, but will be needed in future for
+ * hot plug PCI support
+ */
+static void i2o_pci_activate(i2o_controller * c)
+{
+	int i=0;
+	struct i2o_controller *c;
+	
+	if(c->type == I2O_TYPE_PCI)
+	{
+		I2O_IRQ_WRITE32(c,0);
+#ifdef MODULE
+		if(core->activate(c))
+#else
+		if(i2o_activate_controller(c))
+#endif /* MODULE */
+		{
+			printk("%s: Failed to initialize.\n", c->name);
+#ifdef MODULE
+			core->unlock(c);
+			core->delete(c);
+#else
+			i2o_unlock_controller(c);
+			i2o_delete_controller(c);
+#endif
+			continue;
+		}
+	}
+}
+#endif // I2O_HOTPLUG_SUPPORT
+
+#ifdef MODULE
+
+int i2o_pci_core_attach(struct i2o_core_func_table *table)
+{
+	MOD_INC_USE_COUNT;
+
+	core = table;
+
+	return i2o_pci_scan();
+}
+
+void i2o_pci_core_detach(void)
+{
+	core = NULL;
+
+	MOD_DEC_USE_COUNT;
+}
+
+int init_module(void)
+{
+	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
+	
+	core = NULL;
+
+ 	return 0;
+ 
+}
+
+void cleanup_module(void)
+{
+}
+
+EXPORT_SYMBOL(i2o_pci_core_attach);
+EXPORT_SYMBOL(i2o_pci_core_detach);
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O PCI Interface");
+
+#else
+void __init i2o_pci_init(void)
+{
+	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
+	i2o_pci_scan();
+}
+#endif
diff -urN linux-2.2.15-pre9/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c
--- linux-2.2.15-pre9/drivers/i2o/i2o_scsi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/i2o_scsi.c	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,914 @@
+/* 
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2, or (at your option) any
+ *  later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  Complications for I2O scsi
+ *
+ *	o	Each (bus,lun) is a logical device in I2O. We keep a map
+ *		table. We spoof failed selection for unmapped units
+ *	o	Request sense buffers can come back for free. 
+ *	o	Scatter gather is a bit dynamic. We have to investigate at
+ *		setup time.
+ *	o	Some of our resources are dynamically shared. The i2o core
+ *		needs a message reservation protocol to avoid swap v net
+ *		deadlocking. We need to back off queue requests.
+ *	
+ *	In general the firmware wants to help. Where its help isn't performance
+ *	useful we just ignore the aid. Its not worth the code in truth.
+ *
+ *	Fixes:
+ *		Steve Ralston	:	Scatter gather now works
+ *
+ *	To Do
+ *		64bit cleanups
+ *		Fix the resource management problems.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <linux/blk.h>
+#include <linux/version.h>
+#include <linux/i2o.h>
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+#include "i2o_scsi.h"
+
+#define VERSION_STRING        "Version 0.0.1"
+
+#define dprintk(x)
+
+#define MAXHOSTS 32
+
+struct proc_dir_entry proc_scsi_i2o_scsi = {
+	PROC_SCSI_I2O, 8, "i2o_scsi", S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+struct i2o_scsi_host
+{
+	struct i2o_controller *controller;
+	s16 task[16][8];		/* Allow 16 devices for now */
+	unsigned long tagclock[16][8];	/* Tag clock for queueing */
+	s16 bus_task;		/* The adapter TID */
+};
+
+static int scsi_context;
+static int lun_done;
+static int i2o_scsi_hosts;
+
+static u32 *retry[32];
+static struct i2o_controller *retry_ctrl[32];
+static struct timer_list retry_timer;
+static int retry_ct = 0;
+
+static atomic_t queue_depth;
+
+/*
+ *	SG Chain buffer support...
+ */
+
+#define SG_MAX_FRAGS		64
+
+/*
+ *	FIXME: we should allocate one of these per bus we find as we
+ *	locate them not in a lump at boot.
+ */
+ 
+typedef struct _chain_buf
+{
+	u32 sg_flags_cnt[SG_MAX_FRAGS];
+	u32 sg_buf[SG_MAX_FRAGS];
+} chain_buf;
+
+#define SG_CHAIN_BUF_SZ sizeof(chain_buf)
+
+#define SG_MAX_BUFS		(i2o_num_controllers * I2O_SCSI_CAN_QUEUE)
+#define SG_CHAIN_POOL_SZ	(SG_MAX_BUFS * SG_CHAIN_BUF_SZ)
+
+static int max_sg_len = 0;
+static chain_buf *sg_chain_pool = NULL;
+static int sg_chain_tag = 0;
+static int sg_max_frags = SG_MAX_FRAGS;
+
+/*
+ *	Retry congested frames. This actually needs pushing down into
+ *	i2o core. We should only bother the OSM with this when we can't
+ *	queue and retry the frame. Or perhaps we should call the OSM
+ *	and its default handler should be this in the core, and this
+ *	call a 2nd "I give up" handler in the OSM ?
+ */
+ 
+static void i2o_retry_run(unsigned long f)
+{
+	int i;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	for(i=0;i<retry_ct;i++)
+		i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i]));
+	retry_ct=0;
+	
+	restore_flags(flags);
+}
+
+static void flush_pending(void)
+{
+	int i;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	for(i=0;i<retry_ct;i++)
+	{
+		retry[i][0]&=~0xFFFFFF;
+		retry[i][0]|=I2O_CMD_UTIL_NOP<<24;
+		i2o_post_message(retry_ctrl[i],virt_to_bus(retry[i]));
+	}
+	retry_ct=0;
+	
+	restore_flags(flags);
+}
+
+static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
+{
+	Scsi_Cmnd *current_command;
+	u32 *m = (u32 *)msg;
+	u8 as,ds,st;
+	
+	if(m[0] & (1<<13))
+	{
+		printk("IOP fail.\n");
+		printk("From %d To %d Cmd %d.\n",
+			(m[1]>>12)&0xFFF,
+			m[1]&0xFFF,
+			m[1]>>24);
+		printk("Failure Code %d.\n", m[4]>>24);
+		if(m[4]&(1<<16))
+			printk("Format error.\n");
+		if(m[4]&(1<<17))
+			printk("Path error.\n");
+		if(m[4]&(1<<18))
+			printk("Path State.\n");
+		if(m[4]&(1<<18))
+			printk("Congestion.\n");
+		
+		m=(u32 *)bus_to_virt(m[7]);
+		printk("Failing message is %p.\n", m);
+		
+		if((m[4]&(1<<18)) && retry_ct < 32)
+		{
+			retry_ctrl[retry_ct]=c;
+			retry[retry_ct]=m;
+			if(!retry_ct++)
+			{
+				retry_timer.expires=jiffies+1;
+				add_timer(&retry_timer);
+			}
+		}
+		else
+		{
+			/* Create a scsi error for this */
+			current_command = (Scsi_Cmnd *)m[3];
+			printk("Aborted %ld\n", current_command->serial_number);
+
+			spin_lock_irq(&io_request_lock);			
+			current_command->result = DID_ERROR << 16;
+			current_command->scsi_done(current_command);
+			spin_unlock_irq(&io_request_lock);			
+			
+			/* Now flush the message by making it a NOP */
+			m[0]&=0x00FFFFFF;
+			m[0]|=(I2O_CMD_UTIL_NOP)<<24;
+			i2o_post_message(c,virt_to_bus(m));
+		}
+		return;
+	}
+			
+	
+	/*
+	 *	Low byte is device status, next is adapter status,
+	 *	(then one byte reserved), then request status.
+	 */
+	ds=(u8)m[4]; 
+	as=(u8)(m[4]>>8);
+	st=(u8)(m[4]>>24);
+	
+	dprintk(("i2o got a scsi reply %08X: ", m[0]));
+	dprintk(("m[2]=%08X: ", m[2]));
+	dprintk(("m[4]=%08X\n", m[4]));
+
+	if(m[2]&0x80000000)
+	{
+		if(m[2]&0x40000000)
+		{
+			dprintk(("Event.\n"));
+			lun_done=1;
+			return;
+		}
+		printk(KERN_ERR "i2o_scsi: bus reset reply.\n");
+		return;
+	}
+	
+	current_command = (Scsi_Cmnd *)m[3];
+	
+	/*
+	 *	Is this a control request coming back - eg an abort ?
+	 */
+	 
+	if(current_command==NULL)
+	{
+		if(st)
+			dprintk(("SCSI abort: %08X", m[4]));
+		dprintk(("SCSI abort completed.\n"));
+		return;
+	}
+	
+	dprintk(("Completed %ld\n", current_command->serial_number));
+	
+	atomic_dec(&queue_depth);
+	
+	if(st == 0x06)
+	{
+		if(m[5] < current_command->underflow)
+		{
+			int i;
+			printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n",
+				m[5], current_command->underflow);
+			printk("Cmd: ");
+			for(i=0;i<15;i++)
+				printk("%02X ", current_command->cmnd[i]);
+			printk(".\n");
+		}
+		else st=0;
+	}
+	
+	if(st)
+	{
+		/* An error has occured */
+
+		dprintk((KERN_DEBUG "SCSI error %08X", m[4]));
+			
+		if (as == 0x0E) 
+			/* SCSI Reset */
+			current_command->result = DID_RESET << 16;
+		else if (as == 0x0F)
+			current_command->result = DID_PARITY << 16;
+		else
+			current_command->result = DID_ERROR << 16;
+	}
+	else
+		/*
+		 *	It worked maybe ?
+		 */		
+		current_command->result = DID_OK << 16 | ds;
+	spin_lock(&io_request_lock);
+	current_command->scsi_done(current_command);
+	spin_unlock(&io_request_lock);
+	return;
+}
+
+struct i2o_handler i2o_scsi_handler=
+{
+	i2o_scsi_reply,
+	"I2O SCSI OSM",
+	0,
+	I2O_CLASS_SCSI_PERIPHERAL
+};
+
+static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun)
+{
+	u8 reply[8];
+	
+	if(i2o_query_scalar(c, d->lct_data->tid, 0, 3, reply, 4)<0)
+		return -1;
+		
+	*target=reply[0];
+	
+	if(i2o_query_scalar(c, d->lct_data->tid, 0, 4, reply, 8)<0)
+		return -1;
+
+	*lun=reply[1];
+
+	dprintk(("SCSI (%d,%d)\n", *target, *lun));
+	return 0;
+}
+
+void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
+{
+	struct i2o_device *unit;
+	struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata;
+	int lun;
+	int target;
+	
+	h->controller=c;
+	h->bus_task=d->lct_data->tid;
+	
+	for(target=0;target<16;target++)
+		for(lun=0;lun<8;lun++)
+			h->task[target][lun] = -1;
+			
+	for(unit=c->devices;unit!=NULL;unit=unit->next)
+	{
+		dprintk(("Class %03X, parent %d, want %d.\n",
+			unit->lct_data->class_id, unit->lct_data->parent_tid, d->lct_data->tid));
+			
+		/* Only look at scsi and fc devices */
+		if (    (unit->lct_data->class_id != I2O_CLASS_SCSI_PERIPHERAL)
+		     && (unit->lct_data->class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL)
+		   )
+			continue;
+
+		/* On our bus ? */
+		dprintk(("Found a disk (%d).\n", unit->lct_data->tid));
+		if ((unit->lct_data->parent_tid == d->lct_data->tid)
+		     || (unit->lct_data->parent_tid == d->lct_data->parent_tid)
+		   )
+		{
+			u16 limit;
+			dprintk(("Its ours.\n"));
+			if(i2o_find_lun(c, unit, &target, &lun)==-1)
+			{
+				printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data->tid);
+				continue;
+			}
+			dprintk(("Found disk %d %d.\n", target, lun));
+			h->task[target][lun]=unit->lct_data->tid;
+			h->tagclock[target][lun]=jiffies;
+
+			/* Get the max fragments/request */
+			i2o_query_scalar(c, d->lct_data->tid, 0xF103, 3, &limit, 2);
+			
+			/* sanity */
+			if ( limit == 0 )
+			{
+				printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n");
+				limit = 1;
+			}
+			
+			shpnt->sg_tablesize = limit;
+
+			dprintk(("i2o_scsi: set scatter-gather to %d.\n", 
+				shpnt->sg_tablesize));
+		}
+	}		
+}
+
+int i2o_scsi_detect(Scsi_Host_Template * tpnt)
+{
+	unsigned long flags;
+	struct Scsi_Host *shpnt = NULL;
+	int i;
+	int count;
+
+	printk("i2o_scsi.c: %s\n", VERSION_STRING);
+
+	if(i2o_install_handler(&i2o_scsi_handler)<0)
+	{
+		printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n");
+		return 0;
+	}
+	scsi_context = i2o_scsi_handler.context;
+	
+	if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL)
+	{
+		printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ);
+		printk("i2o_scsi: SG chaining DISABLED!\n");
+		sg_max_frags = 11;
+	}
+	else
+	{
+		printk("  chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool);
+		printk("  (%d byte buffers X %d can_queue X %d i2o controllers)\n",
+				SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers);
+		sg_max_frags = SG_MAX_FRAGS;    // 64
+	}
+	
+	init_timer(&retry_timer);
+	retry_timer.data = 0UL;
+	retry_timer.function = i2o_retry_run;
+	
+//	printk("SCSI OSM at %d.\n", scsi_context);
+
+	for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++)
+	{
+		struct i2o_controller *c=i2o_find_controller(i);
+		struct i2o_device *d;
+		/*
+		 *	This controller doesn't exist.
+		 */
+		
+		if(c==NULL)
+			continue;
+			
+		/*
+		 *	Fixme - we need some altered device locking. This
+		 *	is racing with device addition in theory. Easy to fix.
+		 */
+		
+		for(d=c->devices;d!=NULL;d=d->next)
+		{
+			/*
+			 *	bus_adapter, SCSI (obsolete), or FibreChannel busses only
+			 */
+			if(    (d->lct_data->class_id!=I2O_CLASS_BUS_ADAPTER_PORT)	// bus_adapter
+//			    && (d->lct_data->class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT)	// FC_PORT
+			  )
+				continue;
+		
+			shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host));
+			save_flags(flags);
+			cli();
+			shpnt->unique_id = (u32)d;
+			shpnt->io_port = 0;
+			shpnt->n_io_port = 0;
+			shpnt->irq = 0;
+			shpnt->this_id = /* Good question */15;
+			restore_flags(flags);
+			i2o_scsi_init(c, d, shpnt);
+			count++;
+		}
+	}
+	i2o_scsi_hosts = count;
+	
+	if(count==0)
+	{
+		if(sg_chain_pool!=NULL)
+		{
+			kfree(sg_chain_pool);
+			sg_chain_pool = NULL;
+		}
+		flush_pending();
+		del_timer(&retry_timer);
+		i2o_remove_handler(&i2o_scsi_handler);
+	}
+	
+	return count;
+}
+
+int i2o_scsi_release(struct Scsi_Host *host)
+{
+	if(--i2o_scsi_hosts==0)
+	{
+		if(sg_chain_pool!=NULL)
+		{
+			kfree(sg_chain_pool);
+			sg_chain_pool = NULL;
+		}
+		flush_pending();
+		del_timer(&retry_timer);
+		i2o_remove_handler(&i2o_scsi_handler);
+	}
+	return 0;
+}
+
+
+const char *i2o_scsi_info(struct Scsi_Host *SChost)
+{
+	struct i2o_scsi_host *hostdata;
+
+	hostdata = (struct i2o_scsi_host *)SChost->hostdata;
+
+	return(&hostdata->controller->name[0]);
+}
+
+
+/*
+ * From the wd93 driver:
+ * Returns true if there will be a DATA_OUT phase with this command, 
+ * false otherwise.
+ * (Thanks to Joerg Dorchain for the research and suggestion.)
+ *
+ */
+static int is_dir_out(Scsi_Cmnd *cmd)
+{
+	switch (cmd->cmnd[0]) 
+	{
+     		case WRITE_6:           case WRITE_10:          case WRITE_12:
+      		case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
+      		case WRITE_VERIFY:      case WRITE_VERIFY_12:      
+      		case COMPARE:           case COPY:              case COPY_VERIFY:
+      		case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
+      		case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:      
+      		case FORMAT_UNIT:       case REASSIGN_BLOCKS:   case RESERVE:
+      		case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
+      		case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
+      		case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
+      		case 0xea:
+        		return 1;
+		default:
+        		return 0;
+	}
+}
+
+int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+	int i;
+	int tid;
+	struct i2o_controller *c;
+	Scsi_Cmnd *current_command;
+	struct Scsi_Host *host;
+	struct i2o_scsi_host *hostdata;
+	u32 *msg, *mptr;
+	u32 m;
+	u32 *lenptr;
+	int direction;
+	int scsidir;
+	u32 len;
+	u32 reqlen;
+	u32 tag;
+	
+	static int max_qd = 1;
+	
+	/*
+	 *	Do the incoming paperwork
+	 */
+	 
+	host = SCpnt->host;
+	hostdata = (struct i2o_scsi_host *)host->hostdata;
+	SCpnt->scsi_done = done;
+	
+	if(SCpnt->target > 15)
+	{
+		printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->target);
+		return -1;
+	}
+	
+	tid = hostdata->task[SCpnt->target][SCpnt->lun];
+	
+	dprintk(("qcmd: Tid = %d\n", tid));
+	
+	current_command = SCpnt;		/* set current command                */
+	current_command->scsi_done = done;	/* set ptr to done function           */
+
+	/* We don't have such a device. Pretend we did the command 
+	   and that selection timed out */
+	
+	if(tid == -1)
+	{
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
+	}
+	
+	dprintk(("Real scsi messages.\n"));
+
+	c = hostdata->controller;
+	
+	/*
+	 *	Obtain an I2O message. Right now we _have_ to obtain one
+	 *	until the scsi layer stuff is cleaned up.
+	 */	
+	 
+	do
+	{
+		mb();
+		m = I2O_POST_READ32(c);
+	}
+	while(m==0xFFFFFFFF);
+	msg = (u32 *)(c->mem_offset + m);
+	
+	/*
+	 *	Put together a scsi execscb message
+	 */
+	
+	len = SCpnt->request_bufflen;
+	direction = 0x00000000;			// SGL IN  (osm<--iop)
+	
+	/*
+	 *	The scsi layer should be handling this stuff
+	 */
+	
+	scsidir = 0x00000000;			// DATA NO XFER
+	if(len)
+	{
+		if(is_dir_out(SCpnt))
+		{
+			direction=0x04000000;	// SGL OUT  (osm-->iop)
+			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
+		}
+		else
+		{
+			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
+		}
+	}
+	
+	writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);
+	writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */
+	/* Sorry 64bit folks. FIXME */
+	writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */
+
+	/* LSI_920_PCI_QUIRK
+	 *
+	 *	Intermittant observations of msg frame word data corruption
+	 *	observed on msg[4] after:
+	 *	  WRITE, READ-MODIFY-WRITE
+	 *	operations.  19990606 -sralston
+	 *
+	 *	(Hence we build this word via tag. Its good practice anyway
+	 *	 we don't want fetches over PCI needlessly)
+	 */
+
+	tag=0;
+	
+	/*
+	 *	Attach tags to the devices
+	 */	
+	if(SCpnt->device->tagged_supported)
+	{
+		/*
+		 *	Some drives are too stupid to handle fairness issues
+		 *	with tagged queueing. We throw in the odd ordered
+		 *	tag to stop them starving themselves.
+		 */
+		if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ))
+		{
+			tag=0x01800000;		/* ORDERED! */
+			hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies;
+		}
+		else
+		{
+			/* Hmmm...  I always see value of 0 here,
+			 *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston
+			 */
+			if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
+				tag=0x01000000;
+			else if(SCpnt->tag == ORDERED_QUEUE_TAG)
+				tag=0x01800000;
+		}
+	}
+
+	/* Direction, disconnect ok, tag, CDBLen */
+	writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]);
+
+	mptr=msg+5;
+
+	/* 
+	 *	Write SCSI command into the message - always 16 byte block 
+	 */
+	 
+	memcpy_toio(mptr, SCpnt->cmnd, 16);
+	mptr+=4;
+	lenptr=mptr++;		/* Remember me - fill in when we know */
+	
+	reqlen = 12;		// SINGLE SGE
+	
+	/*
+	 *	Now fill in the SGList and command 
+	 *
+	 *	FIXME: we need to set the sglist limits according to the 
+	 *	message size of the I2O controller. We might only have room
+	 *	for 6 or so worst case
+	 */
+	
+	if(SCpnt->use_sg)
+	{
+		struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
+		int chain = 0;
+		
+		len = 0;
+
+		if((sg_max_frags > 11) && (SCpnt->use_sg > 11))
+		{
+			chain = 1;
+			/*
+			 *	Need to chain!
+			 */
+			writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++);
+			writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr);
+			mptr = (u32*)(sg_chain_pool + sg_chain_tag);
+			if (SCpnt->use_sg > max_sg_len)
+			{
+				max_sg_len = SCpnt->use_sg;
+				printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n",
+					SCpnt, SCpnt->use_sg, sg_chain_tag);
+			}
+			if ( ++sg_chain_tag == SG_MAX_BUFS )
+				sg_chain_tag = 0;
+			for(i = 0 ; i < SCpnt->use_sg; i++)
+			{
+				*mptr++=direction|0x10000000|sg->length;
+				len+=sg->length;
+				*mptr++=virt_to_bus(sg->address);
+				sg++;
+			}
+			mptr[-2]=direction|0xD0000000|(sg-1)->length;
+		}
+		else
+		{		
+			for(i = 0 ; i < SCpnt->use_sg; i++)
+			{
+				writel(direction|0x10000000|sg->length, mptr++);
+				len+=sg->length;
+				writel(virt_to_bus(sg->address), mptr++);
+				sg++;
+			}
+
+			/* Make this an end of list. Again evade the 920 bug and
+			   unwanted PCI read traffic */
+		
+			writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]);
+		}
+		
+		if(!chain)
+			reqlen = mptr - msg;
+		
+		writel(len, lenptr);
+		
+		if(len != SCpnt->underflow)
+			printk("Cmd len %08X Cmd underflow %08X\n",
+				len, SCpnt->underflow);
+	}
+	else
+	{
+		dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,
+				SCpnt->request_bufflen));
+		writel(len = SCpnt->request_bufflen, lenptr);
+		if(len == 0)
+		{
+			reqlen = 9;
+		}
+		else
+		{
+			writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++);
+			writel(virt_to_bus(SCpnt->request_buffer), mptr++);
+		}
+	}
+	
+	/*
+	 *	Stick the headers on 
+	 */
+
+	writel(reqlen<<16 | SGL_OFFSET_10, msg);
+	
+	/* Queue the message */
+	i2o_post_message(c,m);
+	
+	atomic_inc(&queue_depth);
+	
+	if(atomic_read(&queue_depth)> max_qd)
+	{
+		max_qd=atomic_read(&queue_depth);
+		printk("Queue depth now %d.\n", max_qd);
+	}
+	
+	mb();
+	dprintk(("Issued %ld\n", current_command->serial_number));
+	
+	return 0;
+}
+
+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+	SCpnt->SCp.Status++;
+}
+
+int i2o_scsi_command(Scsi_Cmnd * SCpnt)
+{
+	i2o_scsi_queuecommand(SCpnt, internal_done);
+	SCpnt->SCp.Status = 0;
+	while (!SCpnt->SCp.Status)
+		barrier();
+	return SCpnt->result;
+}
+
+int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
+{
+	struct i2o_controller *c;
+	struct Scsi_Host *host;
+	struct i2o_scsi_host *hostdata;
+	u32 *msg;
+	u32 m;
+	int tid;
+	
+	printk("i2o_scsi: Aborting command block.\n");
+	
+	host = SCpnt->host;
+	hostdata = (struct i2o_scsi_host *)host->hostdata;
+	tid = hostdata->task[SCpnt->target][SCpnt->lun];
+	if(tid==-1)
+	{
+		printk(KERN_ERR "impossible command to abort.\n");
+		return SCSI_ABORT_NOT_RUNNING;
+	}
+	c = hostdata->controller;
+	
+	/*
+	 *	Obtain an I2O message. Right now we _have_ to obtain one
+	 *	until the scsi layer stuff is cleaned up.
+	 */	
+	 
+	do
+	{
+		mb();
+		m = I2O_POST_READ32(c);
+	}
+	while(m==0xFFFFFFFF);
+	msg = bus_to_virt(c->mem_offset + m);
+	
+	writel(FIVE_WORD_MSG_SIZE, &msg[0]);
+	writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, &msg[1]);
+	writel(scsi_context, &msg[2]);
+	writel(0, &msg[3]);	/* Not needed for an abort */
+	writel((u32)SCpnt, &msg[4]);	
+	wmb();
+	i2o_post_message(c,m);
+	wmb();
+	return SCSI_ABORT_PENDING;
+}
+
+int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{
+	int tid;
+	struct i2o_controller *c;
+	struct Scsi_Host *host;
+	struct i2o_scsi_host *hostdata;
+	u32 m;
+	u32 *msg;
+
+	/*
+	 *	Find the TID for the bus
+	 */
+
+	printk("i2o_scsi: Attempting to reset the bus.\n");
+	
+	host = SCpnt->host;
+	hostdata = (struct i2o_scsi_host *)host->hostdata;
+	tid = hostdata->bus_task;
+	c = hostdata->controller;
+
+	/*
+	 *	Now send a SCSI reset request. Any remaining commands
+	 *	will be aborted by the IOP. We need to catch the reply
+	 *	possibly ?
+	 */
+	 
+	m = I2O_POST_READ32(c);
+	
+	/*
+	 *	No free messages, try again next time - no big deal
+	 */
+	 
+	if(m == 0xFFFFFFFF)
+		return SCSI_RESET_PUNT;
+	
+	msg = bus_to_virt(c->mem_offset + m);
+	writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
+	writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, &msg[1]);
+	writel(scsi_context|0x80000000, &msg[2]);
+	/* We use the top bit to split controller and unit transactions */
+	/* Now store unit,tid so we can tie the completion back to a specific device */
+	writel(c->unit << 16 | tid, &msg[3]);
+	i2o_post_message(c,m);
+	return SCSI_RESET_PENDING;
+}
+
+/*
+ *	This is anyones guess quite frankly.
+ */
+ 
+int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip)
+{
+	int size;
+
+	size = disk->capacity;
+	ip[0] = 64;		/* heads                        */
+	ip[1] = 32;		/* sectors                      */
+	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
+		ip[0] = 255;	/* heads                        */
+		ip[1] = 63;	/* sectors                      */
+		ip[2] = size / (255 * 63);	/* cylinders                    */
+	}
+	return 0;
+}
+
+/* Loadable module support */
+#ifdef MODULE
+
+MODULE_AUTHOR("Red Hat Software");
+
+Scsi_Host_Template driver_template = I2OSCSI;
+
+#include "../scsi/scsi_module.c"
+#endif
diff -urN linux-2.2.15-pre9/drivers/i2o/i2o_scsi.h linux/drivers/i2o/i2o_scsi.h
--- linux-2.2.15-pre9/drivers/i2o/i2o_scsi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/i2o/i2o_scsi.h	Mon Dec  3 21:59:54 2001
@@ -0,0 +1,48 @@
+#ifndef _I2O_SCSI_H
+#define _I2O_SCSI_H
+
+#if !defined(LINUX_VERSION_CODE)
+#include <linux/version.h>
+#endif
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+
+#define I2O_SCSI_ID 15
+#define I2O_SCSI_CAN_QUEUE 4
+#define I2O_SCSI_CMD_PER_LUN 6
+
+extern struct proc_dir_entry proc_scsi_i2o_scsi;
+
+extern int i2o_scsi_detect(Scsi_Host_Template *);
+extern const char *i2o_scsi_info(struct Scsi_Host *);
+extern int i2o_scsi_command(Scsi_Cmnd *);
+extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int i2o_scsi_abort(Scsi_Cmnd *);
+extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
+extern int i2o_scsi_bios_param(Disk *, kdev_t, int *);
+extern void i2o_scsi_setup(char *str, int *ints);
+
+#define I2OSCSI {                                          \
+		  next: NULL,				    \
+                  proc_dir:          &proc_scsi_i2o_scsi,\
+                  name:              "I2O SCSI Layer", 	    \
+                  detect:            i2o_scsi_detect,       \
+                  release:	     i2o_scsi_release,	    \
+                  info:              i2o_scsi_info,         \
+                  command:           i2o_scsi_command,      \
+                  queuecommand:      i2o_scsi_queuecommand, \
+                  abort:             i2o_scsi_abort,        \
+                  reset:             i2o_scsi_reset,        \
+                  bios_param:        i2o_scsi_bios_param,   \
+                  can_queue:         I2O_SCSI_CAN_QUEUE,    \
+                  this_id:           I2O_SCSI_ID,           \
+                  sg_tablesize:      8,                     \
+                  cmd_per_lun:       I2O_SCSI_CMD_PER_LUN,  \
+                  unchecked_isa_dma: 0,                     \
+                  use_clustering:    ENABLE_CLUSTERING     \
+                  }
+
+#endif
diff -urN linux-2.2.15-pre9/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- linux-2.2.15-pre9/drivers/misc/parport_pc.c	Mon Dec  3 21:59:48 2001
+++ linux/drivers/misc/parport_pc.c	Mon Dec  3 21:59:55 2001
@@ -902,6 +902,8 @@
 		  { { 0, -1 }, } },
 		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
 		  { { 0, -1 }, } },
+		{ PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902, 1,
+		  { { 0, 1 }, } },
 		{ 0, }
 	};
 
diff -urN linux-2.2.15-pre9/drivers/net/3c509.c linux/drivers/net/3c509.c
--- linux-2.2.15-pre9/drivers/net/3c509.c	Mon Dec  3 21:59:48 2001
+++ linux/drivers/net/3c509.c	Mon Dec  3 21:59:55 2001
@@ -375,6 +375,7 @@
 	
 	((struct el3_private *)dev->priv)->mca_slot = mca_slot;
 	((struct el3_private *)dev->priv)->next_dev = el3_root_dev;
+	((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 	el3_root_dev = dev;
 
 	if (el3_debug > 0)
@@ -434,9 +435,6 @@
 	outw(TxReset, ioaddr + EL3_CMD);
 	outw(RxReset, ioaddr + EL3_CMD);
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
-	/* Set the spinlock before grabbing IRQ! */
-	((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 
 	if (request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev)) {
 		return -EAGAIN;
diff -urN linux-2.2.15-pre9/drivers/net/3c527.c linux/drivers/net/3c527.c
--- linux-2.2.15-pre9/drivers/net/3c527.c	Tue Oct 26 17:53:40 1999
+++ linux/drivers/net/3c527.c	Mon Dec  3 21:59:55 2001
@@ -3,6 +3,7 @@
  *
  *	(c) Copyright 1998 Red Hat Software Inc
  *	Written by Alan Cox.
+ *	Further debugging by Carl Drougge.
  *
  *	Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
  *	(for the MCA stuff) written by Wim Dumon.
@@ -16,7 +17,7 @@
  */
 
 static const char *version =
-	"3c527.c:v0.06 1999/09/16 Alan Cox (alan@redhat.com)\n";
+	"3c527.c:v0.08 2000/02/22 Alan Cox (alan@redhat.com)\n";
 
 /*
  *	Things you need
@@ -100,6 +101,7 @@
 	u32 base;
 	u16 rx_halted;
 	u16 tx_halted;
+	u16 rx_pending;		/* ring due a service */
 	u16 exec_pending;
 	u16 mc_reload_wait;	/* a multicast load request is pending */
 	atomic_t tx_count;		/* buffers left */
@@ -418,6 +420,9 @@
 	printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
 		dev->name, lp->rx_len, lp->tx_len, lp->base);
 	
+	if(lp->tx_len >TX_RING_MAX)
+		lp->tx_len = TX_RING_MAX;
+		
 	dev->open		= mc32_open;
 	dev->stop		= mc32_close;
 	dev->hard_start_xmit	= mc32_send_packet;
@@ -426,6 +431,7 @@
 	
 	lp->rx_halted		= 1;
 	lp->tx_halted		= 1;
+	lp->rx_pending		= 0;
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
@@ -579,6 +585,7 @@
 	mc32_ring_poll(dev);	
 	
 	lp->rx_halted=0;
+	lp->rx_pending=0;
 }
 
 static void mc32_tx_abort(struct device *dev)
@@ -783,6 +790,7 @@
 static int mc32_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	int ioaddr = dev->base_addr;
 
 	if (dev->tbusy) {
 		/*
@@ -833,6 +841,14 @@
 		lp->tx_skb_end++;
 		lp->tx_skb_end&=(TX_RING_MAX-1);
 		
+		/* TX suspend - shouldnt be needed but apparently is.
+		   This is a research item ... */
+		   
+		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
+		lp->tx_box->mbox=0;
+		outb(3, ioaddr+HOST_CMD);
+		
+		/* Transmit now stopped */
 		/* P is the last sending/sent buffer as a pointer */
 		p=(struct skb_header *)bus_to_virt(lp->base+tx_head);
 		
@@ -841,7 +857,7 @@
 		
 		np->control	|= (1<<6);	/* EOL */
 		wmb();
-		
+				
 		np->length	= skb->len;
 
 		if(np->length < 60)
@@ -857,7 +873,9 @@
 		
 		dev->tbusy	= 0;			/* Keep feeding me */		
 		
+		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 		lp->tx_box->mbox=0;
+		outb(5, ioaddr+HOST_CMD);		/* Restart TX */
 		restore_flags(flags);
 	}
 	return 0;
@@ -926,17 +944,15 @@
 	}
 	while(x++<48);
 	
-	/* 
-	 *	This is curious. It seems the receive stop and receive continue
-	 *	commands race against each other, even though we poll for 
-	 *	command ready to be issued. The delay is hackish but is a workaround
-	 *	while I investigate in depth
-	 */
+	/*
+	 *	Restart ring processing
+	 */	
 	
 	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 	lp->rx_box->mbox=0;
 	lp->rx_box->data[0] = top;
 	outb(1<<3, ioaddr+HOST_CMD);	
+	lp->rx_halted = 0;
 }
 
 
@@ -949,7 +965,6 @@
 	struct device *dev = dev_id;
 	struct mc32_local *lp;
 	int ioaddr, status, boguscount = 0;
-	int rx_event = 0;
 	
 	if (dev == NULL) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
@@ -1011,7 +1026,15 @@
 			case 0:
 				break;
 			case 2:	/* RX */
-				rx_event=1;
+				lp->rx_pending=1;
+				if(!lp->rx_halted)
+				{
+					/*
+					 *	Halt ring receive
+					 */
+					while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
+					outb(3<<3, ioaddr+HOST_CMD);
+				}
 				break;
 			case 3:
 			case 4:
@@ -1024,9 +1047,10 @@
 				break;
 			case 6:
 				/* Out of RX buffers stat */
-				/* Must restart */
 				lp->net_stats.rx_dropped++;
-				rx_event = 1; 	/* To restart */
+				lp->rx_pending=1;
+				/* Must restart */
+				lp->rx_halted=1;
 				break;
 			default:
 				printk("%s: strange rx ack %d\n", 
@@ -1060,11 +1084,17 @@
 	}
 	
 	/*
-	 *	Process and restart the receive ring.
+	 *	Process and restart the receive ring. This has some state
+	 *	as we must halt the ring to process it and halting the ring
+	 *	might not occur in the same IRQ handling loop as we issue
+	 *	the halt.
 	 */
 	 
-	if(rx_event)
+	if(lp->rx_pending && lp->rx_halted)
+	{
 		mc32_rx_ring(dev);
+		lp->rx_pending = 0;
+	}
 	dev->interrupt = 0;
 	return;
 }
diff -urN linux-2.2.15-pre9/drivers/net/acenic.c linux/drivers/net/acenic.c
--- linux-2.2.15-pre9/drivers/net/acenic.c	Wed Aug 25 17:29:48 1999
+++ linux/drivers/net/acenic.c	Mon Dec  3 21:59:55 2001
@@ -858,7 +858,7 @@
 {
 #if 0
 	if (!ap->trace_buf)
-		if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)));
+		if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)))
 		    return;
 #endif
 }
diff -urN linux-2.2.15-pre9/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- linux-2.2.15-pre9/drivers/net/dgrs.c	Tue Dec 29 11:32:06 1998
+++ linux/drivers/net/dgrs.c	Mon Dec  3 21:59:55 2001
@@ -1197,8 +1197,11 @@
 
 	priv->intrcnt = 0;
 	for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
+	{
+		rmb();		/* gcc 2.95 needs this */
 		if (priv->intrcnt >= 2)
 			break;
+	}
 	if (priv->intrcnt < 2)
 	{
 		printk("%s: Not interrupting on IRQ %d (%d)\n",
diff -urN linux-2.2.15-pre9/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- linux-2.2.15-pre9/drivers/net/eexpress.c	Sun May 30 10:17:03 1999
+++ linux/drivers/net/eexpress.c	Mon Dec  3 21:59:55 2001
@@ -649,6 +649,7 @@
 			ack_cmd |= SCB_RUstart;
 			scb_wrrfa(dev, lp->rx_buf_start);
 			lp->rx_ptr = lp->rx_buf_start;
+			lp->started |= STARTED_RU;
 		}
 		ack_cmd |= SCB_CUstart | 0x2000;
 	}
diff -urN linux-2.2.15-pre9/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- linux-2.2.15-pre9/drivers/net/irda/nsc-ircc.c	Mon Dec  3 21:59:49 2001
+++ linux/drivers/net/irda/nsc-ircc.c	Mon Dec  3 21:59:55 2001
@@ -725,9 +725,9 @@
 	switch_bank(iobase, BANK2);
 	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
 
-	/* IRCR2: FEND_MD is set */
+	/* IRCR2: FEND_MD is not set */
 	switch_bank(iobase, BANK5);
- 	outb(0x2a, iobase+4);
+ 	outb(0x02, iobase+4);
 
 	/* Make sure that some defaults are OK */
 	switch_bank(iobase, BANK6);
@@ -1448,8 +1448,10 @@
 		/* We must empty the status FIFO no matter what */
 		len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
 
-		if (st_fifo->tail >= MAX_RX_WINDOW)
+		if (st_fifo->tail >= MAX_RX_WINDOW) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n");
 			continue;
+		}
 			
 		st_fifo->entries[st_fifo->tail].status = status;
 		st_fifo->entries[st_fifo->tail].len = len;
@@ -1509,7 +1511,18 @@
 					st_fifo->pending_bytes += len;
 					st_fifo->entries[st_fifo->head].status = status;
 					st_fifo->entries[st_fifo->head].len = len;
-				
+					/*  
+					 * DMA not finished yet, so try again 
+					 * later, set timer value, resolution 
+					 * 125 us 
+					 */
+					switch_bank(iobase, BANK4);
+					outb(0x02, iobase+TMRL); /* x 125 us */
+					outb(0x00, iobase+TMRH);
+
+					/* Start timer */
+					outb(IRCR1_TMR_EN, iobase+IRCR1);
+
 					/* Restore bank register */
 					outb(bank, iobase+BSR);
 					
@@ -1667,21 +1680,12 @@
 	
 	/* Status FIFO event*/
 	if (eir & EIR_SFIF_EV) {
+		/* Check if DMA has finished */
 		if (nsc_ircc_dma_receive_complete(self, iobase)) {
 			/* Wait for next status FIFO interrupt */
 			self->ier = IER_SFIF_IE;
 		} else {
-			/* 
-			 * DMA not finished yet, so try again later, set 
-			 * timer value, resolution 125 us 
-			 */
-			switch_bank(iobase, BANK4);
-			outb(0x02, iobase+TMRL); /* 2 * 125 us */
-			outb(0x00, iobase+TMRH);
-
-			/* Start timer */
-			outb(IRCR1_TMR_EN, iobase+IRCR1);
-			self->ier = IER_TMR_IE | IER_SFIF_IE;
+			self->ier = IER_SFIF_IE | IER_TMR_IE;
 		}
 	} else if (eir & EIR_TMR_EV) { /* Timer finished */
 		/* Disable timer */
@@ -1696,15 +1700,17 @@
 		if (self->io.direction == IO_XMIT) {
 			nsc_ircc_dma_xmit(self, iobase);
 
-			/*  Interrupt on DMA */
+			/* Interrupt on DMA */
 			self->ier = IER_DMA_IE;
 		} else {
-			/* Check if DMA has now finished */
-			nsc_ircc_dma_receive_complete(self, iobase);
-
-			self->ier = IER_SFIF_IE;
+			/* Check (again) if DMA has finished */
+			if (nsc_ircc_dma_receive_complete(self, iobase)) {
+				self->ier = IER_SFIF_IE;
+			} else {
+				self->ier = IER_SFIF_IE | IER_TMR_IE;
+			}
 		}
-	} else if (eir & EIR_DMA_EV) { 
+	} else if (eir & EIR_DMA_EV) {
 		/* Finished with all transmissions? */
 		if (nsc_ircc_dma_xmit_complete(self)) {		
 			/* Check if there are more frames to be transmitted */
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/lm80.h linux/drivers/net/sk98lin/h/lm80.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/lm80.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sk98lin/h/lm80.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	lm80.h	
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.2 $
- * Date:	$Date: 1999/03/12 13:26:51 $
+ * Version:	$Revision: 1.3 $
+ * Date:	$Date: 1999/11/22 13:41:19 $
  * Purpose:	Contains all defines for the LM80 Chip
  *		(National Semiconductor).
  *
@@ -27,6 +27,9 @@
  *
  * History:
  *	$Log: lm80.h,v $
+ *	Revision 1.3  1999/11/22 13:41:19  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.2  1999/03/12 13:26:51  malthoff
  *	remove __STDC__.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skaddr.h linux/drivers/net/sk98lin/h/skaddr.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skaddr.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sk98lin/h/skaddr.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skaddr.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.19 $
- * Date:	$Date: 1999/05/28 10:56:07 $
+ * Version:	$Revision: 1.20 $
+ * Date:	$Date: 1999/11/22 13:46:14 $
  * Purpose:	Header file for Address Management (MC, UC, Prom)
  *
  ******************************************************************************/
@@ -27,6 +27,10 @@
  * History:
  *
  *	$Log: skaddr.h,v $
+ *	Revision 1.20  1999/11/22 13:46:14  cgoos
+ *	Changed license header to GPL.
+ *	Allowing overwrite for SK_ADDR_EQUAL.
+ *	
  *	Revision 1.19  1999/05/28 10:56:07  rassmann
  *	Editorial changes.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skcsum.h linux/drivers/net/sk98lin/h/skcsum.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skcsum.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sk98lin/h/skcsum.h	Mon Dec  3 21:59:55 2001
@@ -1,9 +1,9 @@
 /******************************************************************************
  *
  * Name:	skcsum.h
- * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.2 $
- * Date:	$Date: 1998/09/04 12:16:34 $
+ * Project:	GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx)
+ * Version:	$Revision: 1.5 $
+ * Date:	$Date: 2000/02/21 12:10:05 $
  * Purpose:	Store/verify Internet checksum in send/receive packets.
  *
  ******************************************************************************/
@@ -27,6 +27,18 @@
  * History:
  *
  *	$Log: skcsum.h,v $
+ *	Revision 1.5  2000/02/21 12:10:05  cgoos
+ *	Fixed license comment.
+ *	
+ *	Revision 1.4  2000/02/21 11:08:37  cgoos
+ *	Merged changes back into common source.
+ *	
+ *	Revision 1.1  1999/07/26 14:47:49  mkarl
+ *	changed from common source to windows specific source
+ *	added return SKCS_STATUS_IP_CSUM_ERROR_UDP and
+ *	SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester
+ *	changes for Tx csum offload
+ *	
  *	Revision 1.2  1998/09/04 12:16:34  mhaveman
  *	Checked in for Stephan to allow compilation.
  *	-Added definition SK_CSUM_EVENT_CLEAR_PROTO_STATS to clear statistic
@@ -116,6 +128,9 @@
 #define SKCS_STATUS_UDP_CSUM_ERROR	6
 #define SKCS_STATUS_TCP_CSUM_OK		7
 #define SKCS_STATUS_UDP_CSUM_OK		8
+// needed for Microsoft
+#define SKCS_STATUS_IP_CSUM_ERROR_UDP	9
+#define SKCS_STATUS_IP_CSUM_ERROR_TCP	10
 #endif	/* !SKCS_OVERWRITE_STATUS */
 
 /* Clear protocol statistics event. */
@@ -158,7 +173,7 @@
 	SK_U64 RxUnableCts;	/* Unable to verify receive checksum. */
 	SK_U64 RxErrCts;	/* Receive checksum error. */
 	SK_U64 TxOkCts;		/* Transmit checksum ok. */
-	SK_U64 TxUnableCts;	/* Unable to verify transmit checksum. */
+	SK_U64 TxUnableCts;	/* Unable to calculate checksum in hw. */
 } SKCS_PROTO_STATS;
 
 /*
@@ -167,6 +182,9 @@
 typedef struct s_Csum {
 	/* Enabled receive SK_PROTO_XXX bit flags. */
 	unsigned ReceiveFlags;
+#ifdef TX_CSUM
+	unsigned TransmitFlags;
+#endif // TX_CSUM
 
 	/* The protocol statistics structure; one per supported protocol. */
 	SKCS_PROTO_STATS ProtoStats[SKCS_NUM_PROTOCOLS];
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skdebug.h linux/drivers/net/sk98lin/h/skdebug.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skdebug.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sk98lin/h/skdebug.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skdebug.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.9 $
- * Date:	$Date: 1999/09/14 14:02:43 $
+ * Version:	$Revision: 1.10 $
+ * Date:	$Date: 1999/11/22 13:47:40 $
  * Purpose:	SK specific DEBUG support
  *
  ******************************************************************************/
@@ -26,6 +26,9 @@
  *
  * History:
  *	$Log: skdebug.h,v $
+ *	Revision 1.10  1999/11/22 13:47:40  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.9  1999/09/14 14:02:43  rwahl
  *	Added SK_DBGMOD_PECP.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skdrv1st.h linux/drivers/net/sk98lin/h/skdrv1st.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skdrv1st.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sk98lin/h/skdrv1st.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skdrv1st.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.6 $
- * Date:	$Date: 1999/07/27 08:03:33 $
+ * Version:	$Revision: 1.8 $
+ * Date:	$Date: 2000/02/21 12:19:18 $
  * Purpose:	First header file for driver and all other modules
  *
  ******************************************************************************/
@@ -27,6 +27,15 @@
  * History:
  *
  *	$Log: skdrv1st.h,v $
+ *	Revision 1.8  2000/02/21 12:19:18  cgoos
+ *	Added default for SK_DEBUG_CHKMOD/_CHKCAT
+ *	
+ *	Revision 1.7  1999/11/22 13:50:00  cgoos
+ *	Changed license header to GPL.
+ *	Added overwrite for several functions.
+ *	Removed linux 2.0.x definitions.
+ *	Removed PCI vendor ID definition (now in kernel).
+ *	
  *	Revision 1.6  1999/07/27 08:03:33  cgoos
  *	Changed SK_IN/OUT macros to readX/writeX instead of memory
  *	accesses (necessary for ALPHA).
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skdrv2nd.h linux/drivers/net/sk98lin/h/skdrv2nd.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skdrv2nd.h	Mon Dec  3 21:59:49 2001
+++ linux/drivers/net/sk98lin/h/skdrv2nd.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skdrv2nd.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.7 $
- * Date:	$Date: 1999/09/28 12:38:21 $
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 2000/02/21 10:39:55 $
  * Purpose:	Second header file for driver and all other modules
  *
  ******************************************************************************/
@@ -27,6 +27,13 @@
  * History:
  *
  *	$Log: skdrv2nd.h,v $
+ *	Revision 1.9  2000/02/21 10:39:55  cgoos
+ *	Added flag for jumbo support usage.
+ *	
+ *	Revision 1.8  1999/11/22 13:50:44  cgoos
+ *	Changed license header to GPL.
+ *	Fixed two comments.
+ *	
  *	Revision 1.7  1999/09/28 12:38:21  cgoos
  *	Added CheckQueue to SK_AC.
  *	
@@ -411,7 +418,7 @@
 	int		RxBufSize;	/* length of receive buffers */
         struct net_device_stats stats;	/* linux 'netstat -i' statistics */
 	int		Index;		/* internal board index number */
-	SK_BOOL		JumboActivated; /* jumbo support ever activated */
+	SK_BOOL		JumboActivated;	/* jumbo support ever activated */
 
 	/* adapter RAM sizes for queues of active port */
 	int		RxQueueSize;	/* memory used for receive queue */
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skerror.h linux/drivers/net/sk98lin/h/skerror.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skerror.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sk98lin/h/skerror.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skerror.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.3 $
- * Date:	$Date: 1999/09/14 14:04:42 $
+ * Version:	$Revision: 1.4 $
+ * Date:	$Date: 1999/11/22 13:51:59 $
  * Purpose:	SK specific Error log support
  *
  ******************************************************************************/
@@ -26,6 +26,9 @@
  *
  * History:
  *	$Log: skerror.h,v $
+ *	Revision 1.4  1999/11/22 13:51:59  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.3  1999/09/14 14:04:42  rwahl
  *	Added error base SK_ERRBASE_PECP.
  *	Changed error base for driver.
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skgedrv.h linux/drivers/net/sk98lin/h/skgedrv.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skgedrv.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sk98lin/h/skgedrv.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgedrv.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.3 $
- * Date:	$Date: 1998/12/01 13:31:39 $
+ * Version:	$Revision: 1.4 $
+ * Date:	$Date: 1999/11/22 13:52:46 $
  * Purpose:	Interface with the driver
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: skgedrv.h,v $
+ *	Revision 1.4  1999/11/22 13:52:46  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.3  1998/12/01 13:31:39  cgoos
  *	SWITCH INTERN Event added.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skgehw.h linux/drivers/net/sk98lin/h/skgehw.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skgehw.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/net/sk98lin/h/skgehw.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgehw.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.33 $
- * Date:	$Date: 1999/08/27 11:17:10 $
+ * Version:	$Revision: 1.34 $
+ * Date:	$Date: 1999/11/22 13:53:40 $
  * Purpose:	Defines and Macros for the Gigabit Ethernet Adapter Product
  *		Family
  *
@@ -27,6 +27,9 @@
  *
  * History:
  * $Log: skgehw.h,v $
+ * Revision 1.34  1999/11/22 13:53:40  cgoos
+ * Changed license header to GPL.
+ *
  * Revision 1.33  1999/08/27 11:17:10  malthoff
  * It's more savely to put bracket around marco parameters.
  * Brackets added for PHY_READ and PHY_WRITE.
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skgehwt.h linux/drivers/net/sk98lin/h/skgehwt.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skgehwt.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skgehwt.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skhwt.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.4 $
- * Date:	$Date: 1998/08/19 09:50:58 $
+ * Version:	$Revision: 1.5 $
+ * Date:	$Date: 1999/11/22 13:54:24 $
  * Purpose:	Defines for the hardware timer functions
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: skgehwt.h,v $
+ *	Revision 1.5  1999/11/22 13:54:24  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.4  1998/08/19 09:50:58  gklug
  *	fix: remove struct keyword from c-code (see CCC) add typedefs
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skgei2c.h linux/drivers/net/sk98lin/h/skgei2c.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skgei2c.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skgei2c.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgei2c.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.16 $
- * Date:	$Date: 1999/11/12 08:24:10 $
+ * Version:	$Revision: 1.17 $
+ * Date:	$Date: 1999/11/22 13:55:25 $
  * Purpose:	Special genesis defines for I2C
  *		(taken from Monalisa (taken from Concentrator))
  *
@@ -28,6 +28,9 @@
  * History:
  *
  *	$Log: skgei2c.h,v $
+ *	Revision 1.17  1999/11/22 13:55:25  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.16  1999/11/12 08:24:10  malthoff
  *	Change voltage warning and error limits
  *	(warning +-5%, error +-10%).
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skgeinit.h linux/drivers/net/sk98lin/h/skgeinit.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skgeinit.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skgeinit.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgeinit.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.44 $
- * Date:	$Date: 1999/10/26 07:34:15 $
+ * Version:	$Revision: 1.45 $
+ * Date:	$Date: 1999/11/22 13:56:19 $
  * Purpose:	Structures and prototypes for the GE Init Module
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: skgeinit.h,v $
+ *	Revision 1.45  1999/11/22 13:56:19  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.44  1999/10/26 07:34:15  malthoff
  *	The define SK_LNK_ON has been lost in v1.41.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skgepnm2.h linux/drivers/net/sk98lin/h/skgepnm2.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skgepnm2.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skgepnm2.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgepnm2.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.24 $
- * Date:	$Date: 1999/04/13 15:11:11 $
+ * Version:	$Revision: 1.25 $
+ * Date:	$Date: 1999/11/22 13:57:41 $
  * Purpose:	Defines for Private Network Management Interface
  *
  ****************************************************************************/
@@ -27,6 +27,10 @@
  * History:
  *
  *	$Log: skgepnm2.h,v $
+ *	Revision 1.25  1999/11/22 13:57:41  cgoos
+ *	Changed license header to GPL.
+ *	Allowing overwrite for SK_PNMI_STORE/_READ defines.
+ *	
  *	Revision 1.24  1999/04/13 15:11:11  mhaveman
  *	Changed copyright.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skgepnmi.h linux/drivers/net/sk98lin/h/skgepnmi.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skgepnmi.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skgepnmi.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgepnmi.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.37 $
- * Date:	$Date: 1999/09/14 14:25:32 $
+ * Version:	$Revision: 1.39 $
+ * Date:	$Date: 1999/12/06 10:09:47 $
  * Purpose:	Defines for Private Network Management Interface
  *
  ****************************************************************************/
@@ -27,6 +27,12 @@
  * History:
  *
  *	$Log: skgepnmi.h,v $
+ *	Revision 1.39  1999/12/06 10:09:47  rwahl
+ *	Added new error log message.
+ *	
+ *	Revision 1.38  1999/11/22 13:57:55  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.37  1999/09/14 14:25:32  rwahl
  *	Set MDB version for 1000Base-T (sensors, Master/Slave) changes.
  *	
@@ -559,6 +565,8 @@
 #define SK_PNMI_ERR050MSG	"MacUpdate: Cannot update statistic counter"
 #define SK_PNMI_ERR051		(SK_ERRBASE_PNMI + 51)
 #define SK_PNMI_ERR051MSG	"SkPnmiEvent: Port switch suspicious"
+#define SK_PNMI_ERR052		(SK_ERRBASE_PNMI + 52)
+#define SK_PNMI_ERR052MSG	"MacPrivateConf: SK_HWEV_SET_ROLE returned not 0"
 
 /*
  * Management counter macros called by the driver
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skgesirq.h linux/drivers/net/sk98lin/h/skgesirq.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skgesirq.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skgesirq.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgesirq.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.18 $
- * Date:	$Date: 1999/05/19 07:32:59 $
+ * Version:	$Revision: 1.20 $
+ * Date:	$Date: 1999/12/06 10:00:44 $
  * Purpose:	SK specific Gigabit Ethernet special IRQ functions
  *
  ******************************************************************************/
@@ -26,6 +26,12 @@
  *
  * History:
  *	$Log: skgesirq.h,v $
+ *	Revision 1.20  1999/12/06 10:00:44  cgoos
+ *	Added SET event for role.
+ *	
+ *	Revision 1.19  1999/11/22 13:58:26  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.18  1999/05/19 07:32:59  cgoos
  *	Changes for 1000Base-T.
  *	
@@ -99,6 +105,7 @@
 #define SK_HWEV_UPDATE_STAT	5	/* Update Statistics by PNMI */
 #define SK_HWEV_SET_LMODE	6	/* Set Link Mode by PNMI */
 #define SK_HWEV_SET_FLOWMODE	7	/* Set Flow Control Mode by PNMI */
+#define SK_HWEV_SET_ROLE	8	/* Set Master/Slave (Role) by PNMI */
 
 #define	SK_WA_ACT_TIME		(5000000L)	/* 5 sec */
 #define	SK_WA_INA_TIME		(100000L)	/* 100 msec */
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/ski2c.h linux/drivers/net/sk98lin/h/ski2c.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/ski2c.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/ski2c.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	ski2c.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.27 $
- * Date:	$Date: 1999/05/20 09:23:10 $
+ * Version:	$Revision: 1.28 $
+ * Date:	$Date: 1999/11/22 13:55:46 $
  * Purpose:	Defines to access Voltage and Temperature Sensor
  *		(taken from Monalisa (taken from Concentrator))
  *
@@ -28,6 +28,9 @@
  * History:
  *
  *	$Log: ski2c.h,v $
+ *	Revision 1.28  1999/11/22 13:55:46  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.27  1999/05/20 09:23:10  cgoos
  *	Changes for 1000Base-T (Fan sensors).
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skqueue.h linux/drivers/net/sk98lin/h/skqueue.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skqueue.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skqueue.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skqueue.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.12 $
- * Date:	$Date: 1998/09/08 08:48:01 $
+ * Version:	$Revision: 1.13 $
+ * Date:	$Date: 1999/11/22 13:59:05 $
  * Purpose:	Defines for the Event queue
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: skqueue.h,v $
+ *	Revision 1.13  1999/11/22 13:59:05  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.12  1998/09/08 08:48:01  gklug
  *	add: init level handling
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skrlmt.h linux/drivers/net/sk98lin/h/skrlmt.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skrlmt.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skrlmt.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skrlmt.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.26 $
- * Date:	$Date: 1999/10/04 14:01:19 $
+ * Version:	$Revision: 1.27 $
+ * Date:	$Date: 1999/11/22 13:59:56 $
  * Purpose:	Header file for Redundant Link ManagemenT.
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: skrlmt.h,v $
+ *	Revision 1.27  1999/11/22 13:59:56  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.26  1999/10/04 14:01:19  rassmann
  *	Corrected reaction to reception of BPDU frames.
  *	Added parameter descriptions to "For Readme" section skrlmt.txt.
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/sktimer.h linux/drivers/net/sk98lin/h/sktimer.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/sktimer.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/sktimer.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	sktimer.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.8 $
- * Date:	$Date: 1998/09/08 08:48:02 $
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 1999/11/22 14:00:29 $
  * Purpose:	Defines for the timer functions
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: sktimer.h,v $
+ *	Revision 1.9  1999/11/22 14:00:29  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.8  1998/09/08 08:48:02  gklug
  *	add: init level handling
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/sktypes.h linux/drivers/net/sk98lin/h/sktypes.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/sktypes.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/sktypes.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	sktypes.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.1 $
- * Date:	$Date: 1999/02/16 07:41:40 $
+ * Version:	$Revision: 1.2 $
+ * Date:	$Date: 1999/11/22 14:01:58 $
  * Purpose:	Define data types for Linux
  *
  ******************************************************************************/
@@ -27,6 +27,10 @@
  * History:
  *
  *	$Log: sktypes.h,v $
+ *	Revision 1.2  1999/11/22 14:01:58  cgoos
+ *	Changed license header to GPL.
+ *	Now using Linux' fixed size types instead of standard types.
+ *	
  *	Revision 1.1  1999/02/16 07:41:40  cgoos
  *	First version.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/skvpd.h linux/drivers/net/sk98lin/h/skvpd.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/skvpd.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/skvpd.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skvpd.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.8 $
- * Date:	$Date: 1999/03/11 14:26:40 $
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 1999/11/22 14:02:27 $
  * Purpose:	Defines and Macros for VPD handling
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: skvpd.h,v $
+ *	Revision 1.9  1999/11/22 14:02:27  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.8  1999/03/11 14:26:40  malthoff
  *	Replace __STDC__ with SK_KR_PROTO.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/h/xmac_ii.h linux/drivers/net/sk98lin/h/xmac_ii.h
--- linux-2.2.15-pre9/drivers/net/sk98lin/h/xmac_ii.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/h/xmac_ii.h	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	xmac_ii.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.25 $
- * Date:	$Date: 1999/08/12 19:19:38 $
+ * Version:	$Revision: 1.26 $
+ * Date:	$Date: 1999/11/22 14:03:00 $
  * Purpose:	Defines and Macros for XaQti's Gigabit Ethernet Controller
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: xmac_ii.h,v $
+ *	Revision 1.26  1999/11/22 14:03:00  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.25  1999/08/12 19:19:38  malthoff
  *	Add PHY_B_AC_TX_TST bit according to BCOM A1 errata sheet.
  *	
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skaddr.c linux/drivers/net/sk98lin/skaddr.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skaddr.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skaddr.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skaddr.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.33 $
- * Date:	$Date: 1999/05/28 10:56:06 $
+ * Version:	$Revision: 1.34 $
+ * Date:	$Date: 1999/11/22 13:23:44 $
  * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,9 @@
  * History:
  *
  *	$Log: skaddr.c,v $
+ *	Revision 1.34  1999/11/22 13:23:44  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.33  1999/05/28 10:56:06  rassmann
  *	Editorial changes.
  *	
@@ -164,7 +165,7 @@
 
 #ifndef	lint
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skaddr.c,v 1.33 1999/05/28 10:56:06 rassmann Exp $ (C) SysKonnect.";
+	"@(#) $Id: skaddr.c,v 1.34 1999/11/22 13:23:44 cgoos Exp $ (C) SysKonnect.";
 #endif	/* !defined(lint) */
 
 #define __SKADDR_C
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skcsum.c linux/drivers/net/sk98lin/skcsum.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skcsum.c	Mon Dec  3 21:59:49 2001
+++ linux/drivers/net/sk98lin/skcsum.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skcsum.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.3 $
- * Date:	$Date: 1999/05/10 08:39:33 $
+ * Version:	$Revision: 1.6 $
+ * Date:	$Date: 2000/02/21 12:35:10 $
  * Purpose:	Store/verify Internet checksum in send/receive packets.
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,19 @@
  * History:
  *
  *	$Log: skcsum.c,v $
+ *	Revision 1.6  2000/02/21 12:35:10  cgoos
+ *	Fixed license header comment.
+ *	
+ *	Revision 1.5  2000/02/21 11:05:19  cgoos
+ *	Merged changes back to common source.
+ *	Fixed rx path for BIG ENDIAN architecture.
+ *	
+ *	Revision 1.1  1999/07/26 15:28:12  mkarl
+ *	added return SKCS_STATUS_IP_CSUM_ERROR_UDP and
+ *	SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester
+ *	changed from common source to windows specific source
+ *	therefore restarting with v1.0
+ *	
  *	Revision 1.3  1999/05/10 08:39:33  mkarl
  *	prevent overflows in SKCS_HTON16
  *	fixed a bug in pseudo header checksum calculation
@@ -48,7 +59,7 @@
 
 #ifndef lint
 static const char SysKonnectFileId[] = "@(#)"
-	"$Id: skcsum.c,v 1.3 1999/05/10 08:39:33 mkarl Exp $"
+	"$Id: skcsum.c,v 1.6 2000/02/21 12:35:10 cgoos Exp $"
 	" (C) SysKonnect.";
 #endif	/* !lint */
 
@@ -557,16 +568,24 @@
 	 * not want us to do so because we cannot do any further processing of
 	 * the packet without a valid IP checksum.
 	 */
+	
+	/* Get the next level protocol identifier. */
+	
+	NextLevelProtocol = *(SK_U8 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
 
 	if (IpHeaderChecksum != 0xFFFF) {
 		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxErrCts++;
+		/* the NDIS tester wants to know the upper level protocol too */
+		if (NextLevelProtocol == SKCS_PROTO_ID_TCP) {
+			return(SKCS_STATUS_IP_CSUM_ERROR_TCP);
+		}
+		else if (NextLevelProtocol == SKCS_PROTO_ID_UDP) {
+			return(SKCS_STATUS_IP_CSUM_ERROR_UDP);
+		}
 		return (SKCS_STATUS_IP_CSUM_ERROR);
 	}
 
-	/* Get the next level protocol identifier. */
-
-	NextLevelProtocol =
-		*(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
 
 	/*
 	 * Check if this is a TCP or UDP frame and if we should calculate the
@@ -617,6 +636,7 @@
 	/*
 	 * Calculate the TCP/UDP checksum.
 	 */
+
 	/* Get total length of IP header and data. */
 
 	IpDataLength =
@@ -642,6 +662,7 @@
 		(unsigned long) SKCS_HTON16(IpDataLength) +
 
 		/* Add the TCP/UDP header checksum. */
+
 		(unsigned long) IpDataChecksum;
 
 	/* Add-in any carries. */
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skge.c	Mon Dec  3 21:59:49 2001
+++ linux/drivers/net/sk98lin/skge.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:      	skge.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.27 $
- * Date:       	$Date: 1999/11/25 09:06:28 $
+ * Version:	$Revision: 1.29 $
+ * Date:       	$Date: 2000/02/21 13:31:56 $
  * Purpose:	The main driver source module
  *
  ******************************************************************************/
@@ -46,6 +46,16 @@
  * History:
  *
  *	$Log: skge.c,v $
+ *	Revision 1.29  2000/02/21 13:31:56  cgoos
+ *	Fixed "unused" warning for UltraSPARC change.
+ *	
+ *	Revision 1.28  2000/02/21 10:32:36  cgoos
+ *	Added fixes for UltraSPARC.
+ *	Now printing RlmtMode and PrefPort setting at startup.
+ *	Changed XmitFrame return value.
+ *	Fixed rx checksum calculation for BIG ENDIAN systems.
+ *	Fixed rx jumbo frames counted as ierrors.
+ *	
  *	Revision 1.27  1999/11/25 09:06:28  cgoos
  *	Changed base_addr to unsigned long.
  *	
@@ -348,7 +358,9 @@
 SK_AC		*pAC;
 struct pci_dev	*pdev = NULL;
 unsigned long	base_address;
+#ifdef __sparc_v9__
 unsigned short	tmp;
+#endif
 
 	if (probed)
 		return -ENODEV;
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skgehwt.c linux/drivers/net/sk98lin/skgehwt.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skgehwt.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skgehwt.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgehwt.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.12 $
- * Date:	$Date: 1998/10/15 15:11:34 $
+ * Version:	$Revision: 1.13 $
+ * Date:	$Date: 1999/11/22 13:31:12 $
  * Purpose:	Hardware Timer.
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,9 @@
  * History:
  *
  *	$Log: skgehwt.c,v $
+ *	Revision 1.13  1999/11/22 13:31:12  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.12  1998/10/15 15:11:34  gklug
  *	fix: ID_sccs to SysKonnectFileId
  *	
@@ -76,7 +77,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.12 1998/10/15 15:11:34 gklug Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.13 1999/11/22 13:31:12 cgoos Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skgeinit.c linux/drivers/net/sk98lin/skgeinit.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skgeinit.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skgeinit.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgeinit.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.54 $
- * Date:	$Date: 1999/10/26 07:32:54 $
+ * Version:	$Revision: 1.55 $
+ * Date:	$Date: 1999/11/22 13:32:26 $
  * Purpose:	Contains functions to initialize the GE HW
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,9 @@
  * History:
  *
  *	$Log: skgeinit.c,v $
+ *	Revision 1.55  1999/11/22 13:32:26  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.54  1999/10/26 07:32:54  malthoff
  *	Initialize PHWLinkUp with SK_FALSE. Required for Diagnostics.
  *	
@@ -275,7 +276,7 @@
 /* local variables ************************************************************/
 
 static const char SysKonnectFileId[] =
-	"@(#)$Id: skgeinit.c,v 1.54 1999/10/26 07:32:54 malthoff Exp $ (C) SK ";
+	"@(#)$Id: skgeinit.c,v 1.55 1999/11/22 13:32:26 cgoos Exp $ (C) SK ";
 
 struct s_QOffTab {
 	int	RxQOff;		/* Receive Queue Address Offset */
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skgepnmi.c linux/drivers/net/sk98lin/skgepnmi.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skgepnmi.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skgepnmi.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgepnmi.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.69 $
- * Date:	$Date: 1999/10/18 11:42:15 $
+ * Version:	$Revision: 1.72 $
+ * Date:	$Date: 1999/12/06 16:15:53 $
  * Purpose:	Private Network Management Interface
  *
  ****************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,15 @@
  * History:
  *
  *	$Log: skgepnmi.c,v $
+ *	Revision 1.72  1999/12/06 16:15:53  rwahl
+ *	Fixed problem of instance range for current and factory MAC address.
+ *	
+ *	Revision 1.71  1999/12/06 10:14:20  rwahl
+ *	Fixed bug 10476; set operation for PHY_OPERATION_MODE.
+ *	
+ *	Revision 1.70  1999/11/22 13:33:34  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.69  1999/10/18 11:42:15  rwahl
  *	Added typecasts for checking event dependent param (debug only).
  *	
@@ -297,7 +304,8 @@
 
 
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skgepnmi.c,v 1.69 1999/10/18 11:42:15 rwahl Exp $ (C) SysKonnect.";
+	"@(#) $Id: skgepnmi.c,v 1.72 1999/12/06 16:15:53 rwahl Exp $"
+	" (C) SysKonnect.";
 
 #include "h/skdrv1st.h"
 #include "h/sktypes.h"
@@ -3245,7 +3253,7 @@
 
 	if ((Instance != (SK_U32)(-1))) {
 		
-		if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {
+		if ((Instance < 1) || (Instance > LogPortMax)) {
 
 			*pLen = 0;
 			return (SK_PNMI_ERR_UNKNOWN_INST);
@@ -5622,6 +5630,7 @@
 
 	case OID_SKGE_LINK_MODE:
 	case OID_SKGE_FLOWCTRL_MODE:
+	case OID_SKGE_PHY_OPERATION_MODE:
 		if (*pLen < Limit - LogPortIndex) {
 
 			*pLen = Limit - LogPortIndex;
@@ -5795,6 +5804,82 @@
 					return (SK_PNMI_ERR_GENERAL);
 				}
 			}
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE :
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+				/* mode of this port remains unchanged */
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_MS_MODE_AUTO ||
+				Val8 > SK_MS_MODE_SLAVE) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with new master/slave (role) mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_ROLE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR052,
+							SK_PNMI_ERR052MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new master/slave
+				 * (role) mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_ROLE, EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR052,
+						SK_PNMI_ERR052MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			
 			Offset += sizeof(char);
 			break;
 
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skgesirq.c linux/drivers/net/sk98lin/skgesirq.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skgesirq.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skgesirq.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skgesirq.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.46 $
- * Date:	$Date: 1999/09/16 10:30:07 $
+ * Version:	$Revision: 1.49 $
+ * Date:	$Date: 1999/12/17 11:02:50 $
  * Purpose:	Special IRQ module
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,15 @@
  * History:
  *
  *	$Log: skgesirq.c,v $
+ *	Revision 1.49  1999/12/17 11:02:50  gklug
+ *	fix: read PHY_STAT of Broadcom chip more often to assure good status
+ *	
+ *	Revision 1.48  1999/12/06 10:01:17  cgoos
+ *	Added SET function for Role.
+ *	
+ *	Revision 1.47  1999/11/22 13:34:24  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.46  1999/09/16 10:30:07  cgoos
  *	Removed debugging output statement from Linux.
  *	
@@ -215,7 +222,7 @@
 
 */
 static const char SysKonnectFileId[] =
-	"$Id: skgesirq.c,v 1.46 1999/09/16 10:30:07 cgoos Exp $" ;
+	"$Id: skgesirq.c,v 1.49 1999/12/17 11:02:50 gklug Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skgepnmi.h"		/* PNMI Definitions */
@@ -1338,7 +1345,7 @@
 
 	pPrt->PIsave = 0;
 
-	/* Now wait for each ports link */
+	/* Now wait for each port's link */
 	if (pPrt->PLinkMode == SK_LMODE_HALF ||
 	    pPrt->PLinkMode == SK_LMODE_FULL) {
 		AutoNeg = SK_FALSE;
@@ -1355,13 +1362,43 @@
 	PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat);
 
 	SkXmAutoNegLipaBcom(pAC, IoC, Port, PhyStat);
-	if ((PhyStat & PHY_ST_LSYNC) == 0){
-		return(SK_HW_PS_NONE) ; 
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNeg:%d, PhyStat: %Xh.\n", AutoNeg, PhyStat));
+
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+
+	if ((PhyStat & PHY_ST_LSYNC) == 0) {
+		if (ResAb & (PHY_B_1000S_MSF)) {
+			/* Error */
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				("Master/Slave Fault port %d\n", Port));
+			pPrt->PAutoNegFail = SK_TRUE;
+			pPrt->PMSStatus = SK_MS_STAT_FAULT;
+			return (SK_AND_OTHER);
+		}
+		return (SK_HW_PS_NONE);
+	}
+	
+	if (ResAb & (PHY_B_1000S_MSF)) {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("Master/Slave Fault port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
+		return (SK_AND_OTHER);
+	} else if (ResAb & PHY_B_1000S_MSR) {
+		pPrt->PMSStatus = SK_MS_STAT_MASTER;
+	} else {
+		pPrt->PMSStatus = SK_MS_STAT_SLAVE;
 	}
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNeg:%d, PhyStat: %Xh.\n", AutoNeg, PhyStat));
 
 	if (AutoNeg) {
 		if (PhyStat & PHY_ST_AN_OVER) {
-			SkHWLinkUp(pAC, IoC, Port) ;
+			SkHWLinkUp(pAC, IoC, Port);
 			Done = SkXmAutoNegDone(pAC,IoC,Port);
 			if (Done != SK_AND_OK) {
 				/* Get PHY parameters, for debuging only */
@@ -1400,6 +1437,8 @@
 				Port));
 		}
 #endif
+
+#if 0
 		PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
 		if (ResAb & (PHY_B_1000S_MSF)) {
 			/* Error */
@@ -1413,6 +1452,7 @@
 		} else {
 			pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
 		}
+#endif	/* 0 */
 
 
 		/*
@@ -1753,6 +1793,18 @@
 		if (pAC->GIni.GP[Port].PFlowCtrlMode != Val8) {
 			/* Set New Flow Control mode */
 			pAC->GIni.GP[Port].PFlowCtrlMode = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	case SK_HWEV_SET_ROLE:
+		Val8 = (SK_U8) Para.Para32[1];
+		if (pAC->GIni.GP[Port].PMSMode != Val8) {
+			/* Set New link mode */
+			pAC->GIni.GP[Port].PMSMode = Val8;
 
 			/* Restart Port */
 			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/ski2c.c linux/drivers/net/sk98lin/ski2c.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/ski2c.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/ski2c.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	ski2c.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.41 $
- * Date:	$Date: 1999/09/14 14:11:30 $
+ * Version:	$Revision: 1.42 $
+ * Date:	$Date: 1999/11/22 13:35:12 $
  * Purpose:	Funktions to access Voltage and Temperature Sensor
  *		(taken from Monalisa (taken from Concentrator))
  *
@@ -14,8 +14,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -30,6 +28,9 @@
  * History:
  *
  *	$Log: ski2c.c,v $
+ *	Revision 1.42  1999/11/22 13:35:12  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.41  1999/09/14 14:11:30  malthoff
  *	The 1000BT Dual Link adapter has got only one Fan.
  *	The second Fan has been removed.
@@ -175,7 +176,7 @@
 	i2C Protocol
 */
 static const char SysKonnectFileId[] =
-	"$Id: ski2c.c,v 1.41 1999/09/14 14:11:30 malthoff Exp $" ;
+	"$Id: ski2c.c,v 1.42 1999/11/22 13:35:12 cgoos Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/lm80.h"
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/sklm80.c linux/drivers/net/sk98lin/sklm80.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/sklm80.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/sklm80.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	sklm80.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.16 $
- * Date:	$Date: 1999/05/27 14:05:47 $
+ * Version:	$Revision: 1.17 $
+ * Date:	$Date: 1999/11/22 13:35:51 $
  * Purpose:	Funktions to access Voltage and Temperature Sensor (LM80)
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,9 @@
  * History:
  *
  *	$Log: sklm80.c,v $
+ *	Revision 1.17  1999/11/22 13:35:51  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.16  1999/05/27 14:05:47  malthoff
  *	Fans: Set SenVal to 0 if the fan value is 0 or 0xff. Both values
  *	are outside the limits (0: div zero error, 0xff: value not in
@@ -92,7 +93,7 @@
 	LM80 functions
 */
 static const char SysKonnectFileId[] =
-	"$Id: sklm80.c,v 1.16 1999/05/27 14:05:47 malthoff Exp $" ;
+	"$Id: sklm80.c,v 1.17 1999/11/22 13:35:51 cgoos Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/lm80.h"
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skqueue.c linux/drivers/net/sk98lin/skqueue.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skqueue.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skqueue.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skqueue.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.14 $
- * Date:	$Date: 1998/10/15 15:11:35 $
+ * Version:	$Revision: 1.15 $
+ * Date:	$Date: 1999/11/22 13:36:29 $
  * Purpose:	Management of an event queue.
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,9 @@
  * History:
  *
  *	$Log: skqueue.c,v $
+ *	Revision 1.15  1999/11/22 13:36:29  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.14  1998/10/15 15:11:35  gklug
  *	fix: ID_sccs to SysKonnectFileId
  *	
@@ -81,7 +82,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.14 1998/10/15 15:11:35 gklug Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.15 1999/11/22 13:36:29 cgoos Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skqueue.h"		/* Queue Definitions */
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skrlmt.c linux/drivers/net/sk98lin/skrlmt.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skrlmt.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skrlmt.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skrlmt.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.48 $
- * Date:	$Date: 1999/10/04 14:01:17 $
+ * Version:	$Revision: 1.49 $
+ * Date:	$Date: 1999/11/22 13:38:02 $
  * Purpose:	Manage links on SK-NET Adapters, esp. redundant ones.
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,10 @@
  * History:
  *
  *	$Log: skrlmt.c,v $
+ *	Revision 1.49  1999/11/22 13:38:02  cgoos
+ *	Changed license header to GPL.
+ *	Added initialization to some variables to avoid compiler warnings.
+ *	
  *	Revision 1.48  1999/10/04 14:01:17  rassmann
  *	Corrected reaction to reception of BPDU frames.
  *	Added parameter descriptions to "For Readme" section skrlmt.txt.
@@ -216,7 +218,7 @@
 
 #ifndef	lint
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skrlmt.c,v 1.48 1999/10/04 14:01:17 rassmann Exp $ (C) SysKonnect.";
+	"@(#) $Id: skrlmt.c,v 1.49 1999/11/22 13:38:02 cgoos Exp $ (C) SysKonnect.";
 #endif	/* !defined(lint) */
 
 #define __SKRLMT_C
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/sktimer.c linux/drivers/net/sk98lin/sktimer.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/sktimer.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/sktimer.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	sktimer.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.11 $
- * Date:	$Date: 1998/12/17 13:24:13 $
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 1999/11/22 13:38:51 $
  * Purpose:	High level timer functions.
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,9 @@
  * History:
  *
  *	$Log: sktimer.c,v $
+ *	Revision 1.12  1999/11/22 13:38:51  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.11  1998/12/17 13:24:13  gklug
  *	fix: restart problem: do NOT destroy timer queue if init 1 is done
  *	
@@ -75,7 +76,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.11 1998/12/17 13:24:13 gklug Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.12 1999/11/22 13:38:51 cgoos Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skvpd.c linux/drivers/net/sk98lin/skvpd.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skvpd.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skvpd.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skvpd.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.24 $
- * Date:	$Date: 1999/03/11 14:25:49 $
+ * Version:	$Revision: 1.25 $
+ * Date:	$Date: 1999/11/22 13:39:32 $
  * Purpose:	Shared software to read and write VPD data
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,9 @@
  * History:
  *
  *	$Log: skvpd.c,v $
+ *	Revision 1.25  1999/11/22 13:39:32  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.24  1999/03/11 14:25:49  malthoff
  *	Replace __STDC__ with SK_KR_PROTO.
  *	
@@ -120,7 +121,7 @@
 	Please refer skvpd.txt for infomation how to include this module
  */
 static const char SysKonnectFileId[] =
-	"@(#)$Id: skvpd.c,v 1.24 1999/03/11 14:25:49 malthoff Exp $ (C) SK" ;
+	"@(#)$Id: skvpd.c,v 1.25 1999/11/22 13:39:32 cgoos Exp $ (C) SK" ;
 
 #include "h/skdrv1st.h"
 #include "h/sktypes.h"
diff -urN linux-2.2.15-pre9/drivers/net/sk98lin/skxmac2.c linux/drivers/net/sk98lin/skxmac2.c
--- linux-2.2.15-pre9/drivers/net/sk98lin/skxmac2.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sk98lin/skxmac2.c	Mon Dec  3 21:59:55 2001
@@ -2,8 +2,8 @@
  *
  * Name:	skxmac2.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.49 $
- * Date:	$Date: 1999/11/22 08:12:13 $
+ * Version:	$Revision: 1.50 $
+ * Date:	$Date: 1999/11/22 13:40:14 $
  * Purpose:	Contains functions to initialize the XMAC II
  *
  ******************************************************************************/
@@ -13,8 +13,6 @@
  *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,9 @@
  * History:
  *
  *	$Log: skxmac2.c,v $
+ *	Revision 1.50  1999/11/22 13:40:14  cgoos
+ *	Changed license header to GPL.
+ *	
  *	Revision 1.49  1999/11/22 08:12:13  malthoff
  *	Add workaround for power consumption feature of Bcom C0 chip.
  *	
@@ -224,7 +225,7 @@
 /* local variables ************************************************************/
 
 static const char SysKonnectFileId[] =
-	"@(#)$Id: skxmac2.c,v 1.49 1999/11/22 08:12:13 malthoff Exp $ (C) SK ";
+	"@(#)$Id: skxmac2.c,v 1.50 1999/11/22 13:40:14 cgoos Exp $ (C) SK ";
 
 /* BCOM PHY magic pattern list */
 typedef struct s_PhyHack {
diff -urN linux-2.2.15-pre9/drivers/net/tlan.c linux/drivers/net/tlan.c
--- linux-2.2.15-pre9/drivers/net/tlan.c	Mon Dec  3 21:59:49 2001
+++ linux/drivers/net/tlan.c	Mon Dec  3 21:59:55 2001
@@ -1143,9 +1143,7 @@
 		printk( "TLAN:  Received interrupt for uncompleted TX frame.\n" );
 	}
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
 	priv->stats.tx_bytes += head_list->frameSize;
-#endif
 
 	head_list->cStat = TLAN_CSTAT_UNUSED;
 	dev->tbusy = 0;
@@ -1263,9 +1261,7 @@
 			skb_reserve( skb, 2 );
 			t = (void *) skb_put( skb, head_list->frameSize );
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
 			priv->stats.rx_bytes += head_list->frameSize;
-#endif
 
 			memcpy( t, head_buffer, head_list->frameSize );
 			skb->protocol = eth_type_trans( skb, dev );
@@ -1287,9 +1283,8 @@
 			skb = (struct sk_buff *) head_list->buffer[9].address;
 			head_list->buffer[9].address = 0;
 			skb_trim( skb, head_list->frameSize );
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+
 			priv->stats.rx_bytes += head_list->frameSize;
-#endif
 
 			skb->protocol = eth_type_trans( skb, dev );
 			netif_rx( skb );
diff -urN linux-2.2.15-pre9/drivers/pnp/Config.in linux/drivers/pnp/Config.in
--- linux-2.2.15-pre9/drivers/pnp/Config.in	Wed Jul 23 11:14:31 1997
+++ linux/drivers/pnp/Config.in	Mon Dec  3 21:59:55 2001
@@ -9,7 +9,7 @@
 
 if [ "$CONFIG_PNP" = "y" ]; then
   if [ "$CONFIG_PARPORT" != "n" ]; then
-    dep_tristate '  Auto-probe for parallel devices' CONFIG_PNP_PARPORT $CONFIG_PARPORT
+    dep_tristate '  Auto-probe for parallel devices' CONFIG_PNP_PARPORT $CONFIG_PARPORT $CONFIG_PARPORT_PC
   fi
 fi
 
diff -urN linux-2.2.15-pre9/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- linux-2.2.15-pre9/drivers/sound/cmpci.c	Mon Dec  3 21:59:49 2001
+++ linux/drivers/sound/cmpci.c	Mon Dec  3 21:59:55 2001
@@ -2316,7 +2316,7 @@
 #ifdef CONFIG_SOUND_CMPCI_REAR
 static int	rear_out = 1;
 #else
-static int	read_out = 0;
+static int	rear_out = 0;
 #endif
 
 int __init init_cmpci(void)
diff -urN linux-2.2.15-pre9/drivers/sound/vidc_audio.c linux/drivers/sound/vidc_audio.c
--- linux-2.2.15-pre9/drivers/sound/vidc_audio.c	Wed Dec 16 12:52:01 1998
+++ linux/drivers/sound/vidc_audio.c	Mon Dec  3 21:59:55 2001
@@ -79,7 +79,7 @@
 			newsize = 208;
 		if (newsize > 4096)
 			newsize = 4096;
-		for (new2size = 128; new2size < newsize; new2size <<= 1);
+		for (new2size = 128; new2size < newsize; new2size <<= 1)
 			if (new2size - newsize > newsize - (new2size >> 1))
 				new2size >>= 1;
 		dma_bufsize = new2size;
diff -urN linux-2.2.15-pre9/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- linux-2.2.15-pre9/drivers/video/fbcon.c	Wed Aug 25 17:29:49 1999
+++ linux/drivers/video/fbcon.c	Mon Dec  3 21:59:55 2001
@@ -1087,8 +1087,12 @@
 
 static inline void fbcon_softback_note(struct vc_data *conp, int t, int count)
 {
-    unsigned short *p = (unsigned short *)
-    	(conp->vc_origin + t * conp->vc_size_row);
+    unsigned short *p;
+    
+    if (conp->vc_num != fg_console)
+    	return;
+    p = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row);
+
     while (count) {
     	scr_memcpyw((u16 *)softback_in, p, conp->vc_size_row);
     	count--;
diff -urN linux-2.2.15-pre9/fs/isofs/inode.c linux/fs/isofs/inode.c
--- linux-2.2.15-pre9/fs/isofs/inode.c	Tue Jan  4 10:12:23 2000
+++ linux/fs/isofs/inode.c	Mon Dec  3 21:59:55 2001
@@ -958,16 +958,20 @@
 }
 
 
-static void test_and_set_uid(uid_t *p, uid_t value)
+static inline void test_and_set_uid(uid_t *p, uid_t value)
 {
 	if(value) {
 		*p = value;
-#if 0
-		printk("Resetting to %d\n", value);
-#endif
 	}
 }
 
+static inline void test_and_set_gid(gid_t *p, gid_t value)
+{
+        if(value) {
+                *p = value;
+        }
+}
+
 static int isofs_read_level3_size(struct inode * inode)
 {
 	unsigned long ino = inode->i_ino;
@@ -1171,6 +1175,7 @@
 	  parse_rock_ridge_inode(raw_inode, inode);
 	  /* hmm..if we want uid or gid set, override the rock ridge setting */
 	 test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid);
+         test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid);
 	}
 
 #ifdef DEBUG
diff -urN linux-2.2.15-pre9/fs/qnx4/bitmap.c linux/fs/qnx4/bitmap.c
--- linux-2.2.15-pre9/fs/qnx4/bitmap.c	Mon Dec  3 21:59:49 2001
+++ linux/fs/qnx4/bitmap.c	Mon Dec  3 21:59:55 2001
@@ -61,11 +61,11 @@
 
 unsigned long qnx4_count_free_blocks(struct super_block *sb)
 {
-	int start = sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk - 1;
+	int start = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk) - 1;
 	int total = 0;
 	int total_free = 0;
 	int offset = 0;
-	int size = sb->u.qnx4_sb.BitMap->di_size;
+	int size = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size);
 	struct buffer_head *bh;
 
 	while (total < size) {
@@ -76,6 +76,7 @@
 		count_bits(bh->b_data, size - total, &total_free);
 		brelse(bh);
 		total += QNX4_BLOCK_SIZE;
+		offset++;
 	}
 
 	return total_free;
@@ -90,8 +91,8 @@
 
 int qnx4_is_free(struct super_block *sb, long block)
 {
-	int start = sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk - 1;
-	int size = sb->u.qnx4_sb.BitMap->di_size;
+	int start = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk) - 1;
+	int size = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size);
 	struct buffer_head *bh;
 	const char *g;
 	int ret = -EIO;
@@ -119,8 +120,8 @@
 
 int qnx4_set_bitmap(struct super_block *sb, long block, int busy)
 {
-	int start = sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk - 1;
-	int size = sb->u.qnx4_sb.BitMap->di_size;
+	int start = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk) - 1;
+	int size = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size);
 	struct buffer_head *bh;
 	char *g;
 
diff -urN linux-2.2.15-pre9/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- linux-2.2.15-pre9/fs/qnx4/dir.c	Mon Dec  3 21:59:49 2001
+++ linux/fs/qnx4/dir.c	Mon Dec  3 21:59:55 2001
@@ -35,13 +35,13 @@
 	QNX4DEBUG(("filp->f_pos         = %ld\n", (long) filp->f_pos));
 
 	while (filp->f_pos < inode->i_size) {
-		blknum = qnx4_block_map( inode, filp->f_pos >> QNX4_BLOCK_SIZE_SHIFT );
+		blknum = qnx4_block_map( inode, filp->f_pos >> QNX4_BLOCK_SIZE_BITS );
 		bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
 		if(bh==NULL) {
 			printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
 			break;
 		}
-		ix = ( (filp->f_pos >> QNX4_DIR_ENTRY_SIZE_SHIFT) - (filp->f_pos >> QNX4_BLOCK_SIZE_SHIFT) * QNX4_INODES_PER_BLOCK) & QNX4_INODES_PER_BLOCK_MASK;
+		ix = (int)(filp->f_pos >> QNX4_DIR_ENTRY_SIZE_BITS) % QNX4_INODES_PER_BLOCK;
 		while (ix < QNX4_INODES_PER_BLOCK) {
 			offset = ix * QNX4_DIR_ENTRY_SIZE;
 			de = (struct qnx4_inode_entry *) (bh->b_data + offset);
diff -urN linux-2.2.15-pre9/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- linux-2.2.15-pre9/fs/qnx4/inode.c	Mon Dec  3 21:59:49 2001
+++ linux/fs/qnx4/inode.c	Mon Dec  3 21:59:55 2001
@@ -104,15 +104,15 @@
 	}
 	raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
 	    (ino % QNX4_INODES_PER_BLOCK);
-	raw_inode->di_mode = inode->i_mode;
-	raw_inode->di_uid = inode->i_uid;
-	raw_inode->di_gid = inode->i_gid;
-	raw_inode->di_nlink = inode->i_nlink;
-	raw_inode->di_size = inode->i_size;
-	raw_inode->di_mtime = inode->i_mtime;
-	raw_inode->di_atime = inode->i_atime;
-	raw_inode->di_ctime = inode->i_ctime;
-	raw_inode->di_first_xtnt.xtnt_size = inode->i_blocks;
+	raw_inode->di_mode  = cpu_to_le16(inode->i_mode);
+	raw_inode->di_uid   = cpu_to_le16(inode->i_uid);
+	raw_inode->di_gid   = cpu_to_le16(inode->i_gid);
+	raw_inode->di_nlink = cpu_to_le16(inode->i_nlink);
+	raw_inode->di_size  = cpu_to_le32(inode->i_size);
+	raw_inode->di_mtime = cpu_to_le32(inode->i_mtime);
+	raw_inode->di_atime = cpu_to_le32(inode->i_atime);
+	raw_inode->di_ctime = cpu_to_le32(inode->i_ctime);
+	raw_inode->di_first_xtnt.xtnt_size = cpu_to_le32(inode->i_blocks);
 	mark_buffer_dirty(bh, 1);
 	brelse(bh);
 }
@@ -213,15 +213,15 @@
 	struct buffer_head *bh = 0;
 	struct qnx4_xblk *xblk = 0;
 	struct qnx4_inode_info *qnx4_inode = &inode->u.qnx4_i;
-	qnx4_nxtnt_t nxtnt = qnx4_inode->i_num_xtnts;
+	qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->i_num_xtnts);
 
-	if ( iblock < qnx4_inode->i_first_xtnt.xtnt_size ) {
+	if ( iblock < le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_size) ) {
 		// iblock is in the first extent. This is easy.
-		block = qnx4_inode->i_first_xtnt.xtnt_blk + iblock - 1;
+		block = le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_blk) + iblock - 1;
 	} else {
 		// iblock is beyond first extent. We have to follow the extent chain.
-		i_xblk = qnx4_inode->i_xblk;
-		offset = iblock - qnx4_inode->i_first_xtnt.xtnt_size;
+		i_xblk = le32_to_cpu(qnx4_inode->i_xblk);
+		offset = iblock - le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_size);
 		ix = 0;
 		while ( --nxtnt > 0 ) {
 			if ( ix == 0 ) {
@@ -237,14 +237,14 @@
 					return -EIO;
 				}
 			}
-			if ( offset < xblk->xblk_xtnts[ix].xtnt_size ) {
+			if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) {
 				// got it!
-				block = xblk->xblk_xtnts[ix].xtnt_blk + offset - 1;
+				block = le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_blk) + offset - 1;
 				break;
 			}
-			offset -= xblk->xblk_xtnts[ix].xtnt_size;
+			offset -= le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size);
 			if ( ++ix >= xblk->xblk_num_xtnts ) {
-				i_xblk = xblk->xblk_next_xblk;
+				i_xblk = le32_to_cpu(xblk->xblk_next_xblk);
 				ix = 0;
 				brelse( bh );
 				bh = 0;
@@ -293,8 +293,8 @@
 		return "no qnx4 filesystem (no root dir).";
 	} else {
 		QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", kdevname(s->s_dev)));
-		rd = sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_blk - 1;
-		rl = sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_size;
+		rd = le32_to_cpu(sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
+		rl = le32_to_cpu(sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_size);
 		for (j = 0; j < rl; j++) {
 			bh = bread(sb->s_dev, rd + j, QNX4_BLOCK_SIZE);	/* root dir, first block */
 			if (bh == NULL) {
@@ -330,14 +330,13 @@
 	struct buffer_head *bh;
 	kdev_t dev = s->s_dev;
 	struct inode *root;
-	char *tmpc;
 	const char *errmsg;
 
 	MOD_INC_USE_COUNT;
 	lock_super(s);
 	set_blocksize(dev, QNX4_BLOCK_SIZE);
 	s->s_blocksize = QNX4_BLOCK_SIZE;
-	s->s_blocksize_bits = 9;
+	s->s_blocksize_bits = QNX4_BLOCK_SIZE_BITS;
 	s->s_dev = dev;
 
 	/* Check the boot signature. Since the qnx4 code is
@@ -348,9 +347,7 @@
 		printk("qnx4: unable to read the boot sector\n");
 		goto outnobh;
 	}
-	tmpc = (char *) bh->b_data;
-	if (tmpc[4] != 'Q' || tmpc[5] != 'N' || tmpc[6] != 'X' ||
-	    tmpc[7] != '4' || tmpc[8] != 'F' || tmpc[9] != 'S') {
+	if ( memcmp( (char*)bh->b_data + 4, "QNX4FS", 6 ) ) {
 		if (!silent)
 			printk("qnx4: wrong fsid in boot sector.\n");
 		goto out;
@@ -440,42 +437,27 @@
 	raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
 	    (ino % QNX4_INODES_PER_BLOCK);
 
-	inode->i_mode = raw_inode->di_mode;
-	inode->i_uid = raw_inode->di_uid;
-	inode->i_gid = raw_inode->di_gid;
-	inode->i_nlink = raw_inode->di_nlink;
-	inode->i_size = raw_inode->di_size;
-	inode->i_mtime = raw_inode->di_mtime;
-	inode->i_atime = raw_inode->di_atime;
-	inode->i_ctime = raw_inode->di_ctime;
-	inode->i_blocks = raw_inode->di_first_xtnt.xtnt_size;
+	inode->i_mode    = le16_to_cpu(raw_inode->di_mode);
+	inode->i_uid     = le16_to_cpu(raw_inode->di_uid);
+	inode->i_gid     = le16_to_cpu(raw_inode->di_gid);
+	inode->i_nlink   = le16_to_cpu(raw_inode->di_nlink);
+	inode->i_size    = le32_to_cpu(raw_inode->di_size);
+	inode->i_mtime   = le32_to_cpu(raw_inode->di_mtime);
+	inode->i_atime   = le32_to_cpu(raw_inode->di_atime);
+	inode->i_ctime   = le32_to_cpu(raw_inode->di_ctime);
+	inode->i_blocks  = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size);
 	inode->i_blksize = QNX4_DIR_ENTRY_SIZE;
 
 	memcpy(&inode->u.qnx4_i, (struct qnx4_inode_info *) raw_inode, QNX4_DIR_ENTRY_SIZE);
 	inode->i_op = &qnx4_file_inode_operations;
-	if (S_ISREG(inode->i_mode)) {
+	if (S_ISREG(inode->i_mode))
 		inode->i_op = &qnx4_file_inode_operations;
-	} else {
-		if (S_ISDIR(inode->i_mode)) {
-			inode->i_op = &qnx4_dir_inode_operations;
-		} else {
-			if (S_ISLNK(inode->i_mode)) {
-				inode->i_op = &qnx4_symlink_inode_operations;
-			} else {
-				if (S_ISCHR(inode->i_mode)) {
-					inode->i_op = &chrdev_inode_operations;
-				} else {
-					if (S_ISBLK(inode->i_mode)) {
-						inode->i_op = &blkdev_inode_operations;
-					} else {
-						if (S_ISFIFO(inode->i_mode)) {
-							init_fifo(inode);
-						}
-					}
-				}
-			}
-		}
-	}
+	else if (S_ISDIR(inode->i_mode))
+		inode->i_op = &qnx4_dir_inode_operations;
+	else if (S_ISLNK(inode->i_mode))
+		inode->i_op = &qnx4_symlink_inode_operations;
+	else
+		printk("qnx4: bad inode %d on dev %s\n",ino,kdevname(inode->i_dev));
 	brelse(bh);
 }
 
@@ -489,7 +471,7 @@
 
 __initfunc(int init_qnx4_fs(void))
 {
-	printk("QNX4 filesystem v0.2.1 registered.\n");
+	printk("QNX4 filesystem v0.2.2 registered.\n");
 	return register_filesystem(&qnx4_fs_type);
 }
 
diff -urN linux-2.2.15-pre9/fs/qnx4/namei.c linux/fs/qnx4/namei.c
--- linux-2.2.15-pre9/fs/qnx4/namei.c	Mon Dec  3 21:59:49 2001
+++ linux/fs/qnx4/namei.c	Mon Dec  3 21:59:55 2001
@@ -120,7 +120,8 @@
 	/* The entry is linked, let's get the real info */
 	if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
 		lnk = (struct qnx4_link_info *) de;
-		ino = (lnk->dl_inode_blk - 1) * QNX4_INODES_PER_BLOCK +
+		ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) *
+		    QNX4_INODES_PER_BLOCK +
 		    lnk->dl_inode_ndx;
 	}
 	brelse(bh);
diff -urN linux-2.2.15-pre9/include/linux/blk.h linux/include/linux/blk.h
--- linux-2.2.15-pre9/include/linux/blk.h	Tue Jan  4 10:12:24 2000
+++ linux/include/linux/blk.h	Mon Dec  3 21:59:55 2001
@@ -400,6 +400,14 @@
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == I2O_MAJOR)
+
+#define DEVICE_NAME "I2O block"
+#define DEVICE_REQUEST do_i2ob_request
+#define DEVICE_NR(device) (MINOR(device)>>4)
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device)
+
 #endif /* MAJOR_NR == whatever */
 
 #if (MAJOR_NR != SCSI_TAPE_MAJOR)
diff -urN linux-2.2.15-pre9/include/linux/i2o.h linux/include/linux/i2o.h
--- linux-2.2.15-pre9/include/linux/i2o.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/i2o.h	Mon Dec  3 21:59:55 2001
@@ -0,0 +1,848 @@
+#ifndef _I2O_H
+#define _I2O_H
+
+/*
+ *	Tunable parameters first
+ */
+
+/* How many different OSM's are we allowing */ 
+#define MAX_I2O_MODULES		64
+/* How many controllers are we allowing */
+#define MAX_I2O_CONTROLLERS	32
+
+#include <linux/ioctl.h>
+
+/*
+ * I2O Control IOCTLs and structures
+ */
+#define I2O_MAGIC_NUMBER	'i'
+#define I2OGETIOPS		_IOR(I2O_MAGIC_NUMBER,0,u8[MAX_I2O_CONTROLLERS])
+#define I2OHRTGET		_IOWR(I2O_MAGIC_NUMBER,1,struct i2o_cmd_hrtlct)
+#define I2OLCTGET		_IOWR(I2O_MAGIC_NUMBER,2,struct i2o_cmd_hrtlct)
+#define I2OPARMSET		_IOWR(I2O_MAGIC_NUMBER,3,struct i2o_cmd_psetget)
+#define I2OPARMGET		_IOWR(I2O_MAGIC_NUMBER,4,struct i2o_cmd_psetget)
+#define I2OSWDL			_IOWR(I2O_MAGIC_NUMBER,5,struct i2o_sw_xfer)
+#define I2OSWUL			_IOWR(I2O_MAGIC_NUMBER,6,struct i2o_sw_xfer)
+#define I2OSWDEL		_IOWR(I2O_MAGIC_NUMBER,7,struct i2o_sw_xfer)
+#define I2OVALIDATE		_IOR(I2O_MAGIC_NUMBER,8,u32)
+#define I2OHTML			_IOWR(I2O_MAGIC_NUMBER,9,struct i2o_html)
+#define I2OEVTREG		_IOW(I2O_MAGIC_NUMBER,10,struct i2o_evt_id)
+#define I2OEVTGET		_IOR(I2O_MAGIC_NUMBER,11,struct i2o_evt_info)
+
+struct i2o_cmd_hrtlct
+{
+	unsigned int iop;	/* IOP unit number */
+	void *resbuf;		/* Buffer for result */
+	unsigned int *reslen;	/* Buffer length in bytes */
+};
+
+struct i2o_cmd_psetget
+{
+	unsigned int iop;	/* IOP unit number */
+	unsigned int tid;	/* Target device TID */
+	void *opbuf;		/* Operation List buffer */
+	unsigned int oplen;	/* Operation List buffer length in bytes */
+	void *resbuf;		/* Result List buffer */
+	unsigned int *reslen;	/* Result List buffer length in bytes */
+};
+
+struct i2o_sw_xfer
+{
+	unsigned int iop;	/* IOP unit number */
+	unsigned char flags;	/* Flags field */
+	unsigned char sw_type;	/* Software type */
+	unsigned int sw_id;	/* Software ID */
+	void *buf;		/* Pointer to software buffer */
+	unsigned int *swlen;	/* Length of software data */
+	unsigned int *maxfrag;	/* Maximum fragment count */
+        unsigned int *curfrag;	/* Current fragment count */
+};
+
+struct i2o_html
+{
+	unsigned int iop;	/* IOP unit number */
+	unsigned int tid;	/* Target device ID */
+	unsigned int page;	/* HTML page */
+	void *resbuf;		/* Buffer for reply HTML page */
+	unsigned int *reslen;	/* Length in bytes of reply buffer */
+	void *qbuf;		/* Pointer to HTTP query string */
+	unsigned int qlen;	/* Length in bytes of query string buffer */
+};
+
+#define I2O_EVT_Q_LEN 32
+
+struct i2o_evt_id
+{
+	unsigned int iop;
+	unsigned int tid;
+	unsigned int evt_mask;
+};
+
+//
+// Event data size = frame size - message header + evt indicator
+#define I2O_EVT_DATA_SIZE 88
+
+struct i2o_evt_info
+{
+	struct i2o_evt_id id;
+	unsigned char evt_data[I2O_EVT_DATA_SIZE];
+ 	unsigned int data_size;
+};
+
+struct i2o_evt_get
+{
+	struct i2o_evt_info info;
+	int pending;
+	int lost;
+};
+
+
+/**************************************************************************
+ * HRT related constants and structures
+ **************************************************************************/
+#define I2O_BUS_LOCAL	0
+#define I2O_BUS_ISA	1
+#define I2O_BUS_EISA	2
+#define I2O_BUS_MCA	3
+#define I2O_BUS_PCI	4
+#define I2O_BUS_PCMCIA	5
+#define I2O_BUS_NUBUS	6
+#define I2O_BUS_CARDBUS	7
+#define I2O_BUS_UNKNOWN	0x80
+
+#ifndef __KERNEL__
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+#endif /* __KERNEL__ */
+
+typedef struct _i2o_pci_bus {
+	u8 PciFunctionNumber;
+	u8 PciDeviceNumber;
+	u8 PciBusNumber;
+	u8 reserved;
+	u16 PciVendorID;
+	u16 PciDeviceID;
+} i2o_pci_bus;
+
+typedef struct _i2o_local_bus {
+	u16 LbBaseIOPort;
+	u16 reserved;
+	u32 LbBaseMemoryAddress;
+} i2o_local_bus;
+
+typedef struct _i2o_isa_bus {
+	u16 IsaBaseIOPort;
+	u8 CSN;
+	u8 reserved;
+	u32 IsaBaseMemoryAddress;
+} i2o_isa_bus;
+
+typedef struct _i2o_eisa_bus_info {
+	u16 EisaBaseIOPort;
+	u8 reserved;
+	u8 EisaSlotNumber;
+	u32 EisaBaseMemoryAddress;
+} i2o_eisa_bus;
+
+typedef struct _i2o_mca_bus {
+	u16 McaBaseIOPort;
+	u8 reserved;
+	u8 McaSlotNumber;
+	u32 McaBaseMemoryAddress;
+} i2o_mca_bus;
+
+typedef struct _i2o_other_bus {
+	u16 BaseIOPort;
+	u16 reserved;
+	u32 BaseMemoryAddress;
+} i2o_other_bus;
+
+typedef struct _i2o_hrt_entry {
+	u32 adapter_id;
+	u32 parent_tid:12;
+	u32 state:4;
+	u32 bus_num:8;
+	u32 bus_type:8;
+	union {
+		i2o_pci_bus pci_bus;
+		i2o_local_bus local_bus;
+		i2o_isa_bus isa_bus;
+		i2o_eisa_bus eisa_bus;
+		i2o_mca_bus mca_bus;
+		i2o_other_bus other_bus;
+	} bus;
+} i2o_hrt_entry;
+
+typedef struct _i2o_hrt {
+	u16 num_entries;
+	u8 entry_len;
+	u8 hrt_version;
+	u32 change_ind;
+	i2o_hrt_entry hrt_entry[1];
+} i2o_hrt;
+
+typedef struct _i2o_lct_entry {
+	u32 entry_size:16;
+	u32 tid:12;
+	u32 reserved:4;
+	u32 change_ind;
+	u32 device_flags;
+	u32 class_id:12;
+	u32 version:4;
+	u32 vendor_id:16;
+	u32 sub_class;
+	u32 user_tid:12;
+	u32 parent_tid:12;
+	u32 bios_info:8;
+	u8 identity_tag[8];
+	u32 event_capabilities;
+} i2o_lct_entry;
+
+typedef struct _i2o_lct {
+	u32 table_size:16;
+	u32 boot_tid:12;
+	u32 lct_ver:4;
+	u32 iop_flags;
+	u32 current_change_ind;
+	i2o_lct_entry lct_entry[1];
+} i2o_lct;
+
+typedef struct _i2o_status_block {
+	u16 org_id;
+	u16 reserved;
+	u16 iop_id:12;
+	u16 reserved1:4;
+	u16 host_unit_id;
+	u16 segment_number:12;
+	u16 i2o_version:4;
+	u8 iop_state;
+	u8 msg_type;
+	u16 inbound_frame_size;
+	u8 init_code;	
+	u8 reserved2;
+	u32 max_inbound_frames;
+	u32 cur_inbound_frames;
+	u32 max_outbound_frames;
+	char product_id[24];	
+	u32 expected_lct_size;
+	u32 iop_capabilities;
+	u32 desired_mem_size;
+	u32 current_mem_size;
+	u32 current_mem_base;
+	u32 desired_io_size;
+	u32 current_io_size;
+	u32 current_io_base;
+	u32 reserved3:24;
+	u32 cmd_status:8;
+} i2o_status_block;
+ 
+/* Event indicator mask flags */
+#define I2O_EVT_IND_STATE_CHANGE		0x80000000
+#define I2O_EVT_IND_GENERAL_WARNING		0x40000000
+#define I2O_EVT_IND_CONFIGURATION_FLAG		0x20000000
+#define I2O_EVT_IND_LOCK_RELEASE		0x10000000
+#define I2O_EVT_IND_CAPABILITY_CHANGE		0x08000000
+#define I2O_EVT_IND_DEVICE_RESET		0x04000000
+#define I2O_EVT_IND_EVT_MASK_MODIFIED		0x02000000
+#define I2O_EVT_IND_FIELD_MODIFIED		0x01000000
+#define I2O_EVT_IND_VENDOR_EVT			0x00800000
+#define I2O_EVT_IND_DEVICE_STATE		0x00400000
+
+/* Event data for generic events */
+#define I2O_EVT_STATE_CHANGE_NORMAL		0x00
+#define I2O_EVT_STATE_CHANGE_SUSPENDED		0x01
+#define I2O_EVT_STATE_CHANGE_RESTART		0x02
+#define I2O_EVT_STATE_CHANGE_NA_RECOVER		0x03
+#define I2O_EVT_STATE_CHANGE_NA_NO_RECOVER	0x04
+#define I2O_EVT_STATE_CHANGE_QUIESCE_REQUEST	0x05
+#define I2O_EVT_STATE_CHANGE_FAILED		0x10
+#define I2O_EVT_STATE_CHANGE_FAULTED		0x11
+
+#define I2O_EVT_GEN_WARNING_NORMAL		0x00
+#define I2O_EVT_GEN_WARNING_ERROR_THRESHOLD	0x01
+#define I2O_EVT_GEN_WARNING_MEDIA_FAULT		0x02
+
+#define I2O_EVT_CAPABILITY_OTHER		0x01
+#define I2O_EVT_CAPABILITY_CHANGED		0x02
+
+#define I2O_EVT_SENSOR_STATE_CHANGED		0x01
+
+#ifdef __KERNEL__   /* ioctl stuff only thing exported to users */
+
+#define I2O_MAX_MANAGERS	4
+
+/*
+ *	I2O Interface Objects
+ */
+
+#include <linux/config.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+
+/*
+ * message structures
+ */
+
+struct i2o_message
+{
+	u8	version_offset;
+	u8	flags;
+	u16	size;
+	u32	target_tid:12;
+	u32	init_tid:12;
+	u32	function:8;	
+	u32	initiator_context;
+	/* List follows */
+};
+
+/*
+ *	Each I2O device entity has one or more of these. There is one
+ *	per device. *FIXME* how to handle multiple types on one unit.
+ */
+ 
+struct i2o_device
+{
+	i2o_lct_entry *lct_data;/* Device LCT information */
+	u32 flags;		
+	int i2oversion;		/* I2O version supported. Actually there
+				 * should be high and low version */
+
+	struct proc_dir_entry* proc_entry;	/* /proc dir */
+
+	/* Primary user */
+	struct i2o_handler *owner;
+
+	/* Management users */
+	struct i2o_handler *managers[I2O_MAX_MANAGERS];		
+	int num_managers;
+
+	struct i2o_controller *controller;	/* Controlling IOP */
+	struct i2o_device *next;	/* Chain */
+	char dev_name[8];		/* linux /dev name if available */
+};
+
+/*
+ *	Resource data for each PCI I2O controller
+ */	 	
+struct i2o_pci
+{
+	int irq;
+#ifdef CONFIG_MTRR
+	int mtrr_reg;
+#endif
+};
+
+
+/*
+ *	Each I2O controller has one of these objects
+ */
+ 
+struct i2o_controller
+{
+	char name[16];
+	int unit;
+	int type;
+	int enabled;
+
+#define I2O_TYPE_PCI		0x01		/* PCI I2O controller */	
+
+	struct notifier_block *event_notifer;	/* Events */
+	atomic_t users;
+	struct i2o_device *devices;		/* I2O device chain */
+	struct i2o_controller *next;		/* Controller chain */
+	volatile u32 *post_port;		/* Messaging ports */
+	volatile u32 *reply_port;
+	volatile u32 *irq_mask;			/* Interrupt port */
+
+	i2o_status_block *status_block;		/* IOP status block */
+	i2o_lct *lct;
+	i2o_hrt *hrt;
+
+	u32 mem_offset;				/* MFA offset */
+	u32 mem_phys;				/* MFA physical */
+
+	u32 priv_mem;
+	u32 priv_mem_size;
+	u32 priv_io;
+	u32 priv_io_size;
+
+	struct proc_dir_entry* proc_entry;	/* /proc dir */
+
+	union
+	{					/* Bus information */
+		struct i2o_pci pci;
+	} bus;
+	/* Bus specific destructor */
+	void (*destructor)(struct i2o_controller *);		
+	/* Bus specific attach/detach */
+	int (*bind)(struct i2o_controller *, struct i2o_device *);	
+	/* Bus specific initiator */
+	int (*unbind)(struct i2o_controller *, struct i2o_device *);
+	/* Bus specific enable/disable */
+	void (*bus_enable)(struct i2o_controller *c);
+	void (*bus_disable)(struct i2o_controller *c);
+
+	void *page_frame;		/* Message buffers */
+	int inbound_size;		/* Inbound queue size */
+};
+
+struct i2o_handler
+{
+	void (*reply)(struct i2o_handler *, struct i2o_controller *, struct i2o_message *);
+	char *name;
+	int context;		/* Low 8 bits of the transaction info */
+	u32 class;			/* I2O classes that this driver handles */
+	/* User data follows */
+};
+
+#ifdef MODULE
+/*
+ * Used by bus specific modules to communicate with the core
+ *
+ * This is needed because the bus modules cannot make direct
+ * calls to the core as this results in the i2o_bus_specific_module
+ * being dependent on the core, not the otherway around.
+ * In that case, a 'modprobe i2o_lan' loads i2o_core & i2o_lan,
+ * but _not_ i2o_pci...which makes the whole thing pretty useless :)
+ *
+ */
+struct i2o_core_func_table
+{
+	int	(*install)(struct i2o_controller *);
+	int	(*activate)(struct i2o_controller *);
+	struct  i2o_controller*	(*find)(int);
+	void	(*unlock)(struct i2o_controller *);
+	void	(*run_queue)(struct i2o_controller *c);
+	int	(*delete)(struct i2o_controller *);
+};
+#endif
+
+/*
+ * I2O System table entry
+ */
+struct i2o_sys_tbl_entry
+{
+	u16	org_id;
+	u16	reserved1;
+	u32	iop_id:12;
+	u32	reserved2:20;
+	u16	seg_num:12;
+	u16 	i2o_version:4;
+	u8 	iop_state;
+	u8 	msg_type;
+	u16	frame_size;
+	u16	reserved3;
+	u32	last_changed;
+	u32	iop_capabilities;
+	u32	inbound_low;
+	u32	inbound_high;
+};
+
+struct i2o_sys_tbl
+{
+	u8 	num_entries;
+	u8 	version;
+	u16 	reserved1;
+	u32	change_ind;
+	u32	reserved2;
+	u32	reserved3;
+	struct i2o_sys_tbl_entry iops[0];
+};	
+
+/*
+ *	Messenger inlines
+ */
+extern inline u32 I2O_POST_READ32(struct i2o_controller *c)
+{
+	return *c->post_port;
+}
+
+extern inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val)
+{
+	*c->post_port = Val;
+}
+
+
+extern inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
+{
+	return *c->reply_port;
+}
+
+extern inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
+{
+	*c->reply_port= Val;
+}
+ 
+
+extern inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
+{
+	return *c->irq_mask;
+}
+
+extern inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val)
+{
+	*c->irq_mask = Val;
+}
+
+
+extern inline void i2o_post_message(struct i2o_controller *c, u32 m)
+{
+	/* The second line isnt spurious - thats forcing PCI posting */
+	I2O_POST_WRITE32(c,m);
+	(void) I2O_IRQ_READ32(c);
+}
+
+extern inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
+{
+	I2O_REPLY_WRITE32(c,m);
+}
+
+extern int i2o_install_controller(struct i2o_controller *);
+extern int i2o_delete_controller(struct i2o_controller *);
+extern void i2o_unlock_controller(struct i2o_controller *);
+extern struct i2o_controller *i2o_find_controller(int);
+extern int i2o_status_get(struct i2o_controller *);
+extern int i2o_num_controllers;
+
+extern int i2o_install_handler(struct i2o_handler *);
+extern int i2o_remove_handler(struct i2o_handler *);
+
+extern int i2o_claim_device(struct i2o_device *, struct i2o_handler *, u32);
+extern int i2o_release_device(struct i2o_device *, struct i2o_handler *, u32);
+
+extern int i2o_post_this(struct i2o_controller *, u32 *, int);
+extern int i2o_post_wait(struct i2o_controller *, u32 *, int, int);
+extern int i2o_issue_params(int, struct i2o_controller *, int, void *,
+			    int, void *, int); 
+
+extern int i2o_query_scalar(struct i2o_controller *, int, int, int, void *, int);
+extern int i2o_set_scalar(struct i2o_controller *, int, int, int, void *, int);
+
+extern int i2o_query_table(int, struct i2o_controller *, int, int, int, void *,
+			   int, void *, int);
+extern int i2o_clear_table(struct i2o_controller *, int, int); 
+extern int i2o_row_add_table(struct i2o_controller *, int, int, int, void *,
+			     int);
+
+extern int i2o_event_register(struct i2o_controller *, int, int, u32); 
+extern int i2o_event_ack(struct i2o_controller *, int, int, u32, void *, int);
+
+extern void i2o_run_queue(struct i2o_controller *);
+extern void i2o_report_status(const char *, const char *, u32 *);
+extern void i2o_dump_message(u32 *);
+
+extern const char *i2o_get_class_name(int);
+
+
+/*
+ *	I2O classes / subclasses
+ */
+
+/*  Class ID and Code Assignments
+ *  (LCT.ClassID.Version field)
+ */
+#define    I2O_CLASS_VERSION_10                        0x00
+#define    I2O_CLASS_VERSION_11                        0x01
+
+/*  Class code names
+ *  (from v1.5 Table 6-1 Class Code Assignments.)
+ */
+ 
+#define    I2O_CLASS_EXECUTIVE                         0x000
+#define    I2O_CLASS_DDM                               0x001
+#define    I2O_CLASS_RANDOM_BLOCK_STORAGE              0x010
+#define    I2O_CLASS_SEQUENTIAL_STORAGE                0x011
+#define    I2O_CLASS_LAN                               0x020
+#define    I2O_CLASS_WAN                               0x030
+#define    I2O_CLASS_FIBRE_CHANNEL_PORT                0x040
+#define    I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL          0x041
+#define    I2O_CLASS_SCSI_PERIPHERAL                   0x051
+#define    I2O_CLASS_ATE_PORT                          0x060
+#define    I2O_CLASS_ATE_PERIPHERAL                    0x061
+#define    I2O_CLASS_FLOPPY_CONTROLLER                 0x070
+#define    I2O_CLASS_FLOPPY_DEVICE                     0x071
+#define    I2O_CLASS_BUS_ADAPTER_PORT                  0x080
+#define    I2O_CLASS_PEER_TRANSPORT_AGENT              0x090
+#define    I2O_CLASS_PEER_TRANSPORT                    0x091
+
+/*  Rest of 0x092 - 0x09f reserved for peer-to-peer classes
+ */
+ 
+#define    I2O_CLASS_MATCH_ANYCLASS                    0xffffffff
+
+/*  Subclasses
+ */
+
+#define    I2O_SUBCLASS_i960                           0x001
+#define    I2O_SUBCLASS_HDM                            0x020
+#define    I2O_SUBCLASS_ISM                            0x021
+ 
+/* Operation functions */
+
+#define I2O_PARAMS_FIELD_GET	0x0001
+#define I2O_PARAMS_LIST_GET	0x0002
+#define I2O_PARAMS_MORE_GET	0x0003
+#define I2O_PARAMS_SIZE_GET	0x0004
+#define I2O_PARAMS_TABLE_GET	0x0005
+#define I2O_PARAMS_FIELD_SET	0x0006
+#define I2O_PARAMS_LIST_SET	0x0007
+#define I2O_PARAMS_ROW_ADD	0x0008
+#define I2O_PARAMS_ROW_DELETE	0x0009
+#define I2O_PARAMS_TABLE_CLEAR	0x000A
+
+/*
+ *	I2O serial number conventions / formats
+ *	(circa v1.5)
+ */
+
+#define    I2O_SNFORMAT_UNKNOWN                        0
+#define    I2O_SNFORMAT_BINARY                         1
+#define    I2O_SNFORMAT_ASCII                          2
+#define    I2O_SNFORMAT_UNICODE                        3
+#define    I2O_SNFORMAT_LAN48_MAC                      4
+#define    I2O_SNFORMAT_WAN                            5
+
+/* Plus new in v2.0 (Yellowstone pdf doc)
+ */
+
+#define    I2O_SNFORMAT_LAN64_MAC                      6
+#define    I2O_SNFORMAT_DDM                            7
+#define    I2O_SNFORMAT_IEEE_REG64                     8
+#define    I2O_SNFORMAT_IEEE_REG128                    9
+#define    I2O_SNFORMAT_UNKNOWN2                       0xff
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+
+#define TRL_SINGLE_FIXED_LENGTH		0x00
+#define TRL_SINGLE_VARIABLE_LENGTH	0x40
+#define TRL_MULTIPLE_FIXED_LENGTH	0x80
+
+/*
+ *	Messaging API values
+ */
+ 
+#define	I2O_CMD_ADAPTER_ASSIGN		0xB3
+#define	I2O_CMD_ADAPTER_READ		0xB2
+#define	I2O_CMD_ADAPTER_RELEASE		0xB5
+#define	I2O_CMD_BIOS_INFO_SET		0xA5
+#define	I2O_CMD_BOOT_DEVICE_SET		0xA7
+#define	I2O_CMD_CONFIG_VALIDATE		0xBB
+#define	I2O_CMD_CONN_SETUP		0xCA
+#define	I2O_CMD_DDM_DESTROY		0xB1
+#define	I2O_CMD_DDM_ENABLE		0xD5
+#define	I2O_CMD_DDM_QUIESCE		0xC7
+#define	I2O_CMD_DDM_RESET		0xD9
+#define	I2O_CMD_DDM_SUSPEND		0xAF
+#define	I2O_CMD_DEVICE_ASSIGN		0xB7
+#define	I2O_CMD_DEVICE_RELEASE		0xB9
+#define	I2O_CMD_HRT_GET			0xA8
+#define	I2O_CMD_ADAPTER_CLEAR		0xBE
+#define	I2O_CMD_ADAPTER_CONNECT		0xC9
+#define	I2O_CMD_ADAPTER_RESET		0xBD
+#define	I2O_CMD_LCT_NOTIFY		0xA2
+#define	I2O_CMD_OUTBOUND_INIT		0xA1
+#define	I2O_CMD_PATH_ENABLE		0xD3
+#define	I2O_CMD_PATH_QUIESCE		0xC5
+#define	I2O_CMD_PATH_RESET		0xD7
+#define	I2O_CMD_STATIC_MF_CREATE	0xDD
+#define	I2O_CMD_STATIC_MF_RELEASE	0xDF
+#define	I2O_CMD_STATUS_GET		0xA0
+#define	I2O_CMD_SW_DOWNLOAD		0xA9
+#define	I2O_CMD_SW_UPLOAD		0xAB
+#define	I2O_CMD_SW_REMOVE		0xAD
+#define	I2O_CMD_SYS_ENABLE		0xD1
+#define	I2O_CMD_SYS_MODIFY		0xC1
+#define	I2O_CMD_SYS_QUIESCE		0xC3
+#define	I2O_CMD_SYS_TAB_SET		0xA3
+
+#define I2O_CMD_UTIL_NOP		0x00
+#define I2O_CMD_UTIL_ABORT		0x01
+#define I2O_CMD_UTIL_CLAIM		0x09
+#define I2O_CMD_UTIL_RELEASE		0x0B
+#define I2O_CMD_UTIL_PARAMS_GET		0x06
+#define I2O_CMD_UTIL_PARAMS_SET		0x05
+#define I2O_CMD_UTIL_EVT_REGISTER	0x13
+#define I2O_CMD_UTIL_EVT_ACK		0x14
+#define I2O_CMD_UTIL_CONFIG_DIALOG	0x10
+#define I2O_CMD_UTIL_DEVICE_RESERVE	0x0D
+#define I2O_CMD_UTIL_DEVICE_RELEASE	0x0F
+#define I2O_CMD_UTIL_LOCK		0x17
+#define I2O_CMD_UTIL_LOCK_RELEASE	0x19
+#define I2O_CMD_UTIL_REPLY_FAULT_NOTIFY	0x15
+
+#define I2O_CMD_SCSI_EXEC		0x81
+#define I2O_CMD_SCSI_ABORT		0x83
+#define I2O_CMD_SCSI_BUSRESET		0x27
+
+#define I2O_CMD_BLOCK_READ		0x30
+#define I2O_CMD_BLOCK_WRITE		0x31
+#define I2O_CMD_BLOCK_CFLUSH		0x37
+#define I2O_CMD_BLOCK_MLOCK		0x49
+#define I2O_CMD_BLOCK_MUNLOCK		0x4B
+#define I2O_CMD_BLOCK_MMOUNT		0x41
+#define I2O_CMD_BLOCK_MEJECT		0x43
+
+#define I2O_PRIVATE_MSG			0xFF
+
+/*
+ *	Init Outbound Q status 
+ */
+ 
+#define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS	0x01
+#define I2O_CMD_OUTBOUND_INIT_REJECTED		0x02
+#define I2O_CMD_OUTBOUND_INIT_FAILED		0x03
+#define I2O_CMD_OUTBOUND_INIT_COMPLETE		0x04
+
+/*
+ *	I2O Get Status State values 
+ */
+
+#define	ADAPTER_STATE_INITIALIZING		0x01
+#define	ADAPTER_STATE_RESET			0x02
+#define	ADAPTER_STATE_HOLD			0x04
+#define ADAPTER_STATE_READY			0x05
+#define	ADAPTER_STATE_OPERATIONAL		0x08
+#define	ADAPTER_STATE_FAILED			0x10
+#define	ADAPTER_STATE_FAULTED			0x11
+	
+/* I2O API function return values */
+
+#define I2O_RTN_NO_ERROR			0
+#define I2O_RTN_NOT_INIT			1
+#define I2O_RTN_FREE_Q_EMPTY			2
+#define I2O_RTN_TCB_ERROR			3
+#define I2O_RTN_TRANSACTION_ERROR		4
+#define I2O_RTN_ADAPTER_ALREADY_INIT		5
+#define I2O_RTN_MALLOC_ERROR			6
+#define I2O_RTN_ADPTR_NOT_REGISTERED		7
+#define I2O_RTN_MSG_REPLY_TIMEOUT		8
+#define I2O_RTN_NO_STATUS			9
+#define I2O_RTN_NO_FIRM_VER			10
+#define	I2O_RTN_NO_LINK_SPEED			11
+
+/* Reply message status defines for all messages */
+
+#define I2O_REPLY_STATUS_SUCCESS                    	0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY                	0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     	0x02
+#define	I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER		0x03
+#define	I2O_REPLY_STATUS_ERROR_DIRTY			0x04
+#define	I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER		0x05
+#define	I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER		0x06
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY		0x08
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER	0x09
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER	0x0A
+#define	I2O_REPLY_STATUS_TRANSACTION_ERROR		0x0B
+#define	I2O_REPLY_STATUS_PROGRESS_REPORT		0x80
+
+/* Status codes and Error Information for Parameter functions */
+
+#define I2O_PARAMS_STATUS_SUCCESS		0x00
+#define I2O_PARAMS_STATUS_BAD_KEY_ABORT		0x01
+#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE   	0x02
+#define I2O_PARAMS_STATUS_BUFFER_FULL		0x03
+#define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL	0x04
+#define I2O_PARAMS_STATUS_FIELD_UNREADABLE	0x05
+#define I2O_PARAMS_STATUS_FIELD_UNWRITEABLE	0x06
+#define I2O_PARAMS_STATUS_INSUFFICIENT_FIELDS	0x07
+#define I2O_PARAMS_STATUS_INVALID_GROUP_ID	0x08
+#define I2O_PARAMS_STATUS_INVALID_OPERATION	0x09
+#define I2O_PARAMS_STATUS_NO_KEY_FIELD		0x0A
+#define I2O_PARAMS_STATUS_NO_SUCH_FIELD		0x0B
+#define I2O_PARAMS_STATUS_NON_DYNAMIC_GROUP	0x0C
+#define I2O_PARAMS_STATUS_OPERATION_ERROR	0x0D
+#define I2O_PARAMS_STATUS_SCALAR_ERROR		0x0E
+#define I2O_PARAMS_STATUS_TABLE_ERROR		0x0F
+#define I2O_PARAMS_STATUS_WRONG_GROUP_TYPE	0x10
+
+/* DetailedStatusCode defines for Executive, DDM, Util and Transaction error
+ * messages: Table 3-2 Detailed Status Codes.*/
+
+#define I2O_DSC_SUCCESS                        0x0000
+#define I2O_DSC_BAD_KEY                        0x0002
+#define I2O_DSC_TCL_ERROR                      0x0003
+#define I2O_DSC_REPLY_BUFFER_FULL              0x0004
+#define I2O_DSC_NO_SUCH_PAGE                   0x0005
+#define I2O_DSC_INSUFFICIENT_RESOURCE_SOFT     0x0006
+#define I2O_DSC_INSUFFICIENT_RESOURCE_HARD     0x0007
+#define I2O_DSC_CHAIN_BUFFER_TOO_LARGE         0x0009
+#define I2O_DSC_UNSUPPORTED_FUNCTION           0x000A
+#define I2O_DSC_DEVICE_LOCKED                  0x000B
+#define I2O_DSC_DEVICE_RESET                   0x000C
+#define I2O_DSC_INAPPROPRIATE_FUNCTION         0x000D
+#define I2O_DSC_INVALID_INITIATOR_ADDRESS      0x000E
+#define I2O_DSC_INVALID_MESSAGE_FLAGS          0x000F
+#define I2O_DSC_INVALID_OFFSET                 0x0010
+#define I2O_DSC_INVALID_PARAMETER              0x0011
+#define I2O_DSC_INVALID_REQUEST                0x0012
+#define I2O_DSC_INVALID_TARGET_ADDRESS         0x0013
+#define I2O_DSC_MESSAGE_TOO_LARGE              0x0014
+#define I2O_DSC_MESSAGE_TOO_SMALL              0x0015
+#define I2O_DSC_MISSING_PARAMETER              0x0016
+#define I2O_DSC_TIMEOUT                        0x0017
+#define I2O_DSC_UNKNOWN_ERROR                  0x0018
+#define I2O_DSC_UNKNOWN_FUNCTION               0x0019
+#define I2O_DSC_UNSUPPORTED_VERSION            0x001A
+#define I2O_DSC_DEVICE_BUSY                    0x001B
+#define I2O_DSC_DEVICE_NOT_AVAILABLE           0x001C
+
+/* Device Claim Types */
+#define	I2O_CLAIM_PRIMARY					0x01000000
+#define	I2O_CLAIM_MANAGEMENT					0x02000000
+#define	I2O_CLAIM_AUTHORIZED					0x03000000
+#define	I2O_CLAIM_SECONDARY					0x04000000
+ 
+/* Message header defines for VersionOffset */
+#define I2OVER15	0x0001
+#define I2OVER20	0x0002
+/* Default is 1.5, FIXME: Need support for both 1.5 and 2.0 */
+#define I2OVERSION	I2OVER15
+#define SGL_OFFSET_0    I2OVERSION
+#define SGL_OFFSET_4    (0x0040 | I2OVERSION)
+#define SGL_OFFSET_5    (0x0050 | I2OVERSION)
+#define SGL_OFFSET_6    (0x0060 | I2OVERSION)
+#define SGL_OFFSET_7    (0x0070 | I2OVERSION)
+#define SGL_OFFSET_8    (0x0080 | I2OVERSION)
+#define SGL_OFFSET_9    (0x0090 | I2OVERSION)
+#define SGL_OFFSET_10   (0x00A0 | I2OVERSION)
+
+#define TRL_OFFSET_5    (0x0050 | I2OVERSION)
+#define TRL_OFFSET_6    (0x0060 | I2OVERSION)
+
+ /* msg header defines for MsgFlags */
+#define MSG_STATIC	0x0100
+#define MSG_64BIT_CNTXT	0x0200
+#define MSG_MULTI_TRANS	0x1000
+#define MSG_FAIL	0x2000
+#define MSG_LAST	0x4000
+#define MSG_REPLY	0x8000
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE	0x00030000
+#define FOUR_WORD_MSG_SIZE	0x00040000
+#define FIVE_WORD_MSG_SIZE	0x00050000
+#define SIX_WORD_MSG_SIZE	0x00060000
+#define SEVEN_WORD_MSG_SIZE	0x00070000
+#define EIGHT_WORD_MSG_SIZE	0x00080000
+#define NINE_WORD_MSG_SIZE	0x00090000
+#define TEN_WORD_MSG_SIZE	0x000A0000
+#define I2O_MESSAGE_SIZE(x)	((x)<<16)
+
+
+/* Special TID Assignments */
+
+#define ADAPTER_TID		0
+#define HOST_TID		1
+
+#define MSG_FRAME_SIZE		128
+#define NMBR_MSG_FRAMES		128
+
+#define MSG_POOL_SIZE		16384
+
+#define I2O_POST_WAIT_OK	0
+#define I2O_POST_WAIT_TIMEOUT	-ETIMEDOUT
+
+#endif /* __KERNEL__ */
+
+#endif /* _I2O_H */
diff -urN linux-2.2.15-pre9/include/linux/major.h linux/include/linux/major.h
--- linux-2.2.15-pre9/include/linux/major.h	Tue Jan  4 10:12:25 2000
+++ linux/include/linux/major.h	Mon Dec  3 21:59:55 2001
@@ -102,6 +102,8 @@
 #define COMPAQ_SMART2_MAJOR6	78
 #define COMPAQ_SMART2_MAJOR7	79
 
+#define I2O_MAJOR		80	/* 80->87 */
+
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
diff -urN linux-2.2.15-pre9/include/linux/pci.h linux/include/linux/pci.h
--- linux-2.2.15-pre9/include/linux/pci.h	Mon Dec  3 21:59:49 2001
+++ linux/include/linux/pci.h	Mon Dec  3 21:59:55 2001
@@ -273,6 +273,9 @@
 #define PCI_CLASS_SERIAL_USB		0x0c03
 #define PCI_CLASS_SERIAL_FIBER		0x0c04
 
+#define PCI_BASE_CLASS_INTELLIGENT      0x0e
+#define PCI_CLASS_INTELLIGENT_I2O       0x0e00
+
 #define PCI_CLASS_HOT_SWAP_CONTROLLER	0xff00
 
 #define PCI_CLASS_OTHERS		0xff
@@ -1027,6 +1030,9 @@
 #define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8002 /* The Lava Dual Parallel is */
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B	0x8003 /* two PCI devices on a card */
+
+#define PCI_VENDOR_ID_AFAVLAB		0x14db
+#define PCI_DEVICE_ID_AFAVLAB_TK9902	0x2120
 
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
diff -urN linux-2.2.15-pre9/include/linux/qnx4_fs.h linux/include/linux/qnx4_fs.h
--- linux-2.2.15-pre9/include/linux/qnx4_fs.h	Mon Dec  3 21:59:49 2001
+++ linux/include/linux/qnx4_fs.h	Mon Dec  3 21:59:55 2001
@@ -3,7 +3,7 @@
  *  Author                       : Richard Frowijn
  *  Function                     : qnx4 global filesystem definitions
  *  Version                      : 1.0.2
- *  Last modified                : 2000-01-15
+ *  Last modified                : 2000-02-14
  *
  *  History                      : 23-03-1998 created
  */
@@ -29,12 +29,12 @@
 #define QNX4_VALID_FS		0x0001	/* Clean fs. */
 #define QNX4_ERROR_FS		0x0002	/* fs has errors. */
 #define QNX4_BLOCK_SIZE         0x200	/* blocksize of 512 bytes */
-#define QNX4_BLOCK_SIZE_SHIFT	9
+#define QNX4_BLOCK_SIZE_BITS	9
 #define QNX4_DIR_ENTRY_SIZE     0x040	/* dir entry size of 64 bytes */
-#define QNX4_DIR_ENTRY_SIZE_SHIFT 6
+#define QNX4_DIR_ENTRY_SIZE_BITS 6
 #define QNX4_XBLK_ENTRY_SIZE    0x200	/* xblk entry size */
 #define QNX4_INODES_PER_BLOCK   0x08	/* 512 / 64 */
-#define QNX4_INODES_PER_BLOCK_MASK 0x07
+
 /* for filenames */
 #define QNX4_SHORT_NAME_MAX	16
 #define QNX4_NAME_MAX		48
diff -urN linux-2.2.15-pre9/include/linux/tty.h linux/include/linux/tty.h
--- linux-2.2.15-pre9/include/linux/tty.h	Tue Jan  4 10:12:25 2000
+++ linux/include/linux/tty.h	Mon Dec  3 21:59:55 2001
@@ -304,6 +304,7 @@
 	unsigned int canon_column;
 	struct semaphore atomic_read;
 	struct semaphore atomic_write;
+	spinlock_t read_lock;
 };
 
 /* tty magic number */
diff -urN linux-2.2.15-pre9/mm/Makefile linux/mm/Makefile
--- linux-2.2.15-pre9/mm/Makefile	Tue Nov 17 14:28:18 1998
+++ linux/mm/Makefile	Mon Dec  3 21:59:55 2001
@@ -9,7 +9,7 @@
 
 O_TARGET := mm.o
 O_OBJS	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
-	    vmalloc.o slab.o \
+	    vmalloc.o slab.o oom_kill.o \
 	    swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.15-pre9/mm/oom_kill.c linux/mm/oom_kill.c
--- linux-2.2.15-pre9/mm/oom_kill.c	Wed Dec 31 16:00:00 1969
+++ linux/mm/oom_kill.c	Mon Dec  3 21:59:55 2001
@@ -0,0 +1,188 @@
+/*
+ *  linux/mm/oom_kill.c
+ * 
+ *  Copyright (C)  1998,2000  Rik van Riel
+ *	Thanks go out to Claus Fischer for some serious inspiration and
+ *	for goading me into coding this file...
+ *
+ *  The routines in this file are used to kill a process when
+ *  we're seriously out of memory. This gets called from kswapd()
+ *  in linux/mm/vmscan.c when we really run out of memory.
+ *
+ *  Since we won't call these routines often (on a well-configured
+ *  machine) this file will double as a 'coding guide' and a signpost
+ *  for newbie kernel hackers. It features several pointers to major
+ *  kernel subsystems and hints as to where to find out what things do.
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/swap.h>
+#include <linux/swapctl.h>
+#include <linux/timex.h>
+
+/* #define DEBUG */
+#define min(a,b) (((a)<(b))?(a):(b))
+
+/*
+ * A rough approximation to the sqrt() function.
+ */
+inline int int_sqrt(unsigned int x)
+{
+	unsigned int out = x;
+	while (x & ~(unsigned int)1) x >>=2, out >>=1;
+	if (x) out -= out >> 2;
+	return (out ? out : 1);
+}	
+
+/*
+ * Basically, points = size / (sqrt(CPU_used) * sqrt(sqrt(time_running)))
+ * with some bonusses/penalties.
+ *
+ * We try to chose our `guilty' task in such a way that we free
+ * up the maximum amount of memory and lose the minimum amount of
+ * done work.
+ *
+ * The definition of the task_struct, the structure describing the state
+ * of each process, can be found in include/linux/sched.h. For
+ * capability info, you should read include/linux/capability.h.
+ */
+
+inline int badness(struct task_struct *p)
+{
+	int points = p->mm->total_vm;
+	points /= int_sqrt((p->times.tms_utime + p->times.tms_stime) >> (SHIFT_HZ + 3));
+	points /= int_sqrt(int_sqrt((jiffies - p->start_time) >> (SHIFT_HZ + 10)));
+/*
+ * Niced processes are probably less important; kernel/sched.c
+ * and include/linux/sched.h contain most info on scheduling.
+ */
+	if (p->priority < DEF_PRIORITY)
+		points <<= 1;
+/*
+ * p->(e)uid is the process User ID, ID 0 is root, the super user.
+ * The super user usually only runs (important) system services
+ * and properly checked programs which we don't want to kill.
+ */
+	if (p->uid == 0 || p->euid == 0 || cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN))
+		points >>= 2;
+/*
+ * We don't want to kill a process with direct hardware access.
+ * Not only could this mess up the hardware, but these processes
+ * are usually fairly important too.
+ */
+	if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO))
+		points >>= 1;
+#ifdef DEBUG
+	printk(KERN_DEBUG "OOMkill: task %d (%s) got %d points\n",
+	p->pid, p->comm, points);
+#endif
+	return points;
+}
+
+/*
+ * Simple selection loop. We chose the process with the highest
+ * number of 'points'. We need the locks to make sure that the
+ * list of task structs doesn't change while we look the other way.
+ */
+inline struct task_struct * select_bad_process(void)
+{
+	int points = 0, maxpoints = 0;
+	struct task_struct *p = NULL;
+	struct task_struct *chosen = NULL;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p)
+	{
+		if (p->pid)
+			points = badness(p);
+		if (points > maxpoints) {
+			chosen = p;
+			maxpoints = points;
+		}
+	}
+	read_unlock(&tasklist_lock);
+	return chosen;
+}
+
+/*
+ * We kill the 'best' process and print a message to userspace.
+ * The only things to be careful about are:
+ *  - don't SIGKILL a process with direct hardware access.
+ *  - are we killing ourselves?
+ *  - when we kill someone else, can we sleep and get out of the way?
+ */
+void oom_kill(unsigned long gfp_mask)
+{
+
+	struct task_struct *p = select_bad_process();
+
+	if (p == NULL)
+		return;
+
+	if (p == current) {
+		printk(KERN_ERR "Out of Memory: Killed process %d (%s).",
+			 p->pid, p->comm);
+	} else {
+		printk(KERN_ERR "Out of Memory: Killed process %d (%s), "
+			"saved process %d (%s).",
+			p->pid, p->comm, current->pid, current->comm);
+	}
+
+	/* This process has hardware access, be more careful */
+	if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO)) {
+		force_sig(SIGTERM, p);
+	} else {
+		force_sig(SIGKILL, p);
+	}
+
+	/* Get out of the way so that p can die */
+	if (p != current && (gfp_mask & __GFP_WAIT) && current->state == TASK_RUNNING) {
+		p->counter = 2 * DEF_PRIORITY;
+		current->policy |= SCHED_YIELD;
+		schedule();
+	}
+	return;
+}
+
+/*
+ * We are called when __get_free_pages() thinks the system may
+ * be out of memory. If we really are out of memory, we can do
+ * nothing except freeing up memory by killing a process...
+ */
+
+int out_of_memory(unsigned long gfp_mask)
+{
+	int count = page_cluster;
+	int loop = 0;
+	int freed = 0;
+
+again:
+	if (gfp_mask & __GFP_WAIT) {
+		/* Try to free up some memory */
+		current->flags |= PF_MEMALLOC;
+		do {
+			freed += try_to_free_pages(gfp_mask);
+			run_task_queue(&tq_disk);
+			if (freed && nr_free_pages > freepages.min) {
+				current->flags &= ~PF_MEMALLOC;
+				return 0;
+			}
+		} while (--count);
+		current->flags &= ~PF_MEMALLOC;
+	}
+
+	/* Darn, we failed. Now we have to kill something */
+	if (!loop)
+		oom_kill(gfp_mask);
+
+	if (nr_free_pages > freepages.min)
+		return 0;
+	if (!loop) {
+		loop = 1;
+		goto again;
+	}
+	/* Still out of memory, let the caller deal with it */
+	return 1;
+}
diff -urN linux-2.2.15-pre9/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-2.2.15-pre9/mm/page_alloc.c	Mon Dec  3 21:59:49 2001
+++ linux/mm/page_alloc.c	Mon Dec  3 21:59:55 2001
@@ -20,7 +20,9 @@
 
 int nr_swap_pages = 0;
 int nr_free_pages = 0;
+int low_on_memory = 0;
 extern struct wait_queue * kswapd_wait;
+extern int out_of_memory(unsigned long);
 
 /*
  * Free area management
@@ -209,31 +211,50 @@
 	 * further thought.
 	 */
 	if (!(current->flags & PF_MEMALLOC)) {
-		int freed;
 #ifdef SLEEP_MEMORY_DEBUGGING
 		if (current->state != TASK_RUNNING && (gfp_mask & __GFP_WAIT)) {
-			printk("gfp called by non-running (%d) task from %p!\n",
+			printk("gfp called by non-running (%ld) task from %p!\n",
 				current->state, __builtin_return_address(0));
 			/* if we're not running, we can't sleep */
 			gfp_mask &= ~__GFP_WAIT;
 		}
 #endif		
 
+		if (low_on_memory) {
+			int freed;
+			current->flags |= PF_MEMALLOC;
+			freed = try_to_free_pages(gfp_mask);
+			current->flags &= ~PF_MEMALLOC;
+			if (time_after(jiffies, low_on_memory + 60 * HZ))
+				out_of_memory(gfp_mask);
+			if (freed && nr_free_pages > freepages.low)
+				low_on_memory = 0;
+		}
+
 		if (nr_free_pages <= freepages.low) {
 			wake_up_interruptible(&kswapd_wait);
+			if ((gfp_mask & __GFP_WAIT) && current->state == TASK_RUNNING) {
+				schedule();
+				/* kswapd couldn't save us */
+				if (nr_free_pages <= freepages.low)
+					low_on_memory = jiffies;
+			}
 		}
+
 		if (nr_free_pages > freepages.min)
 			goto ok_to_allocate;
 
-		/* Danger, danger! Do something or fail */
-		current->flags |= PF_MEMALLOC;
-		freed = try_to_free_pages(gfp_mask);
-		current->flags &= ~PF_MEMALLOC;
+		/*
+		 * out_of_memory() should usually fix the situation.
+		 * If it does, we can continue like nothing happened.
+		 */
+		if (!out_of_memory(gfp_mask))
+			goto ok_to_allocate;
 
 		if ((gfp_mask & __GFP_MED) && nr_free_pages > freepages.min / 2)
 			goto ok_to_allocate;
 
-		if (!freed && !(gfp_mask & __GFP_HIGH))
+		if (!(gfp_mask & __GFP_HIGH))
 			goto nopage;
 	}
 ok_to_allocate:
diff -urN linux-2.2.15-pre9/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.2.15-pre9/mm/vmscan.c	Mon Dec  3 21:59:49 2001
+++ linux/mm/vmscan.c	Mon Dec  3 21:59:55 2001
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 
 #include <asm/pgtable.h>
+extern int low_on_memory;
 
 /*
  * The swap-out functions return 1 if they successfully
@@ -495,8 +496,17 @@
 		 */
 		while (nr_free_pages < freepages.high)
 		{
-			if (!do_try_to_free_pages(GFP_KSWAPD))
-				break;
+			if (!do_try_to_free_pages(GFP_KSWAPD)) {
+				/* out of memory? we can't do much */
+				low_on_memory = jiffies;
+				if (nr_free_pages < freepages.min) {
+					run_task_queue(&tq_disk);
+					tsk->state = TASK_INTERRUPTIBLE;
+					schedule_timeout(HZ);
+				} else {	
+					break;
+				}
+			}
 			if (tsk->need_resched)
 				schedule();
 		}
diff -urN linux-2.2.15-pre9/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- linux-2.2.15-pre9/net/ipv4/tcp_timer.c	Mon Dec  3 21:59:49 2001
+++ linux/net/ipv4/tcp_timer.c	Mon Dec  3 21:59:55 2001
@@ -387,12 +387,14 @@
 	for(i = chain_start; i < (chain_start + ((tcp_ehash_size/2) >> 2)); i++) {
 		struct sock *sk = tcp_ehash[i];
 		while(sk) {
+			struct sock *sk_next = sk->next;
+
 			if(!atomic_read(&sk->sock_readers) && sk->keepopen) {
 				count += tcp_keepopen_proc(sk);
 				if(count == sysctl_tcp_max_ka_probes)
 					goto out;
 			}
-			sk = sk->next;
+			sk = sk_next;
 		}
 	}
 out:
diff -urN linux-2.2.15-pre9/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c
--- linux-2.2.15-pre9/net/irda/ircomm/ircomm_tty.c	Mon Dec  3 21:59:49 2001
+++ linux/net/irda/ircomm/ircomm_tty.c	Mon Dec  3 21:59:55 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Jun  6 21:00:56 1999
- * Modified at:   Tue Jan  4 14:12:06 2000
+ * Modified at:   Mon Feb 21 00:37:28 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       serial.c and previous IrCOMM work by Takahide Higuchi
  * 
@@ -1079,6 +1079,9 @@
 				IRDA_DEBUG(2, __FUNCTION__ 
 					   "(), CTS tx start...\n");
 				tty->hw_stopped = 0;
+
+				/* Wake up processes blocked on open */
+				wake_up_interruptible(&self->open_wait);
 				
 				queue_task(&self->tqueue, &tq_immediate);
 				mark_bh(IMMEDIATE_BH);
