diff -u --recursive --new-file v2.1.45/linux/Makefile linux/Makefile
--- v2.1.45/linux/Makefile	Thu Jul 17 10:06:03 1997
+++ linux/Makefile	Fri Jul 18 17:00:24 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 45
+SUBLEVEL = 46
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.45/linux/drivers/scsi/README.in2000 linux/drivers/scsi/README.in2000
--- v2.1.45/linux/drivers/scsi/README.in2000	Mon Oct 14 23:39:48 1996
+++ linux/drivers/scsi/README.in2000	Thu Jul 17 20:24:38 1997
@@ -1,4 +1,16 @@
 
+UPDATE NEWS: version 1.31 - 6 Jul 97
+
+   Fixed a bug that caused incorrect SCSI status bytes to be
+   returned from commands sent to LUN's greater than 0. This
+   means that CDROM changers work now! Fixed a bug in the
+   handling of command-line arguments when loaded as a module.
+   Also put all the header data in in2000.h where it belongs.
+   There are no longer any differences between this driver in
+   the 2.1.xx source tree and the 2.0.xx tree, as of 2.0.31
+   and 2.1.45 (or is it .46?) - this makes things much easier
+   for me...
+
 UPDATE NEWS: version 1.30 - 14 Oct 96
 
    Fixed a bug in the code that sets the transfer direction
@@ -105,15 +117,10 @@
 There's also a define called 'DEFAULT_SX_PER'; this sets the data
 transfer speed for the asynchronous mode. I've put it at 500 ns
 despite the fact that the card could handle settings of 376 or
-252, because I'm not really sure if certain devices or maybe bad
-cables might have trouble at higher speeds. I couldn't find any
-info in my various SCSI references that talk about this in language
-I could understand, so decided to compromise with 500. This is still
-faster than the old driver was set at (I think). Can someone explain
-the significance of the bus transfer speed setting? Do devices on
-the bus ever care what it is? Is cable quality a factor here?
-Regardless, you can choose your own default through the command-
-line with the 'period' keyword.
+252, because higher speeds may be a problem with poor quality
+cables or improper termination; 500 ns is a compromise. You can
+choose your own default through the command-line with the
+'period' keyword.
 
 
 ------------------------------------------------
diff -u --recursive --new-file v2.1.45/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- v2.1.45/linux/drivers/scsi/in2000.c	Fri Apr  4 08:52:23 1997
+++ linux/drivers/scsi/in2000.c	Thu Jul 17 20:24:38 1997
@@ -104,7 +104,7 @@
  *
  */
 
-
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <linux/sched.h>
@@ -115,46 +115,44 @@
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 
+#include <linux/blk.h>
+#include <linux/stat.h>
+
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
-#include "in2000.h"
 
-#include <linux/blk.h>
-#include <linux/stat.h>
-
-#ifdef MODULE
-#include <linux/module.h>
-#endif
 
-#define uchar unsigned char
+#define IN2000_VERSION    "1.31"
+#define IN2000_DATE       "06/July/1997"
 
-#define IN2000_VERSION    "1.30"
-#define IN2000_DATE       "14/Oct/1996"
+/*
+ * Note - the following defines have been moved to 'in2000.h':
+ *
+ *    PROC_INTERFACE
+ *    PROC_STATISTICS
+ *    SYNC_DEBUG
+ *    DEBUGGING_ON
+ *    DEBUG_DEFAULTS
+ *    FAST_READ_IO
+ *    FAST_WRITE_IO
+ *
+ */
 
-#define PROC_INTERFACE     /* add code for /proc/scsi/in2000/xxx interface */
-#define SYNC_DEBUG         /* extra info on sync negotiation printed */
-#define DEBUGGING_ON       /* enable command-line debugging bitmask */
-#define DEBUG_DEFAULTS 0   /* default bitmask - change from command-line */
 
-#define FAST_READ_IO       /* No problems with these on my machine */
-#define FAST_WRITE_IO
+#include "in2000.h"
 
-#ifdef DEBUGGING_ON
-#define DB(f,a) if (hostdata->args & (f)) a;
-#define CHECK_NULL(p,s) /* if (!(p)) {printk("\n"); while (1) printk("NP:%s\r",(s));} */
-#else
-#define DB(f,a)
-#define CHECK_NULL(p,s)
-#endif
 
 
 /*
- * setup_strings is an array of strings that define some of the operating
- * parameters and settings for this driver. It is used unless a LILO
- * or insmod command line has been specified, in which case those settings
- * are combined with the ones here. The driver recognizes the following
- * keywords (lower case required) and arguments:
+ * 'setup_strings' is a single string used to pass operating parameters and
+ * settings from the kernel/module command-line to the driver. 'setup_args[]'
+ * is an array of strings that define the compile-time default values for
+ * these settings. If Linux boots with a LILO or insmod command-line, those
+ * settings are combined with 'setup_args[]'. Note that LILO command-lines
+ * are prefixed with "in2000=" while insmod uses a "setup_strings=" prefix.
+ * The driver recognizes the following keywords (lower case required) and
+ * arguments:
  *
  * -  ioport:addr    -Where addr is IO address of a (usually ROM-less) card.
  * -  noreset        -No optional args. Prevents SCSI bus reset at boot time.
@@ -179,13 +177,11 @@
  *    _must_ be a colon between a keyword and its numeric argument, with no
  *    spaces.
  * -  Keywords are separated by commas, no spaces, in the standard kernel
- *    command-line manner, except in the case of 'setup_strings[]' (see
- *    below), which is simply a C array of pointers to char. Each element
- *    in the array is a string comprising one keyword & argument.
+ *    command-line manner.
  * -  A keyword in the 'nth' comma-separated command-line member will overwrite
- *    the 'nth' element of setup_strings[]. A blank command-line member (in
+ *    the 'nth' element of setup_args[]. A blank command-line member (in
  *    other words, a comma with no preceding keyword) will _not_ overwrite
- *    the corresponding setup_strings[] element.
+ *    the corresponding setup_args[] element.
  *
  * A few LILO examples (for insmod, use 'setup_strings' instead of 'in2000'):
  * -  in2000=ioport:0x220,noreset
@@ -194,334 +190,20 @@
  * -  in2000=proc:3
  */
 
-static char *setup_strings[] =
-      {"","","","","","","","","","","",""};
+/* Normally, no defaults are specified... */
+static char *setup_args[] =
+      {"","","","","","","","",""};
 
-static struct Scsi_Host *instance_list = 0;
+/* filled in by 'insmod' */
+static char *setup_strings = 0;
 
-#ifdef PROC_INTERFACE
-static unsigned long disc_allowed_total;
-static unsigned long disc_taken_total;
+#ifdef MODULE_PARM
+MODULE_PARM(setup_strings, "s");
 #endif
 
-/* IN2000 io_port offsets */
-#define IO_WD_ASR       0x00     /* R - 3393 auxstat reg */
-#define     ASR_INT        0x80
-#define     ASR_LCI        0x40
-#define     ASR_BSY        0x20
-#define     ASR_CIP        0x10
-#define     ASR_PE         0x02
-#define     ASR_DBR        0x01
-#define IO_WD_ADDR      0x00     /* W - 3393 address reg */
-#define IO_WD_DATA      0x01     /* R/W - rest of 3393 regs */
-#define IO_FIFO         0x02     /* R/W - in2000 dual-port fifo (16 bits) */
-#define IN2000_FIFO_SIZE   2048  /*    fifo capacity in bytes */
-#define IO_CARD_RESET   0x03     /* W - in2000 start master reset */
-#define IO_FIFO_COUNT   0x04     /* R - in2000 fifo counter */
-#define IO_FIFO_WRITE   0x05     /* W - clear fifo counter, start write */
-#define IO_FIFO_READ    0x07     /* W - start fifo read */
-#define IO_LED_OFF      0x08     /* W - turn off in2000 activity LED */
-#define IO_SWITCHES     0x08     /* R - read in2000 dip switch */
-#define     SW_ADDR0       0x01  /*    bit 0 = bit 0 of index to io addr */
-#define     SW_ADDR1       0x02  /*    bit 1 = bit 1 of index io addr */
-#define     SW_DISINT      0x04  /*    bit 2 true if ints disabled */
-#define     SW_INT0        0x08  /*    bit 3 = bit 0 of index to interrupt */
-#define     SW_INT1        0x10  /*    bit 4 = bit 1 of index to interrupt */
-#define     SW_INT_SHIFT   3     /*    shift right this amount to right justify int bits */
-#define     SW_SYNC_DOS5   0x20  /*    bit 5 used by Always BIOS */
-#define     SW_FLOPPY      0x40  /*    bit 6 true if floppy enabled */
-#define     SW_BIT7        0x80  /*    bit 7 hardwired true (ground) */
-#define IO_LED_ON       0x09     /* W - turn on in2000 activity LED */
-#define IO_HARDWARE     0x0a     /* R - read in2000 hardware rev, stop reset */
-#define IO_INTR_MASK    0x0c     /* W - in2000 interrupt mask reg */
-#define     IMASK_WD       0x01  /*    WD33c93 interrupt mask */
-#define     IMASK_FIFO     0x02  /*    FIFO interrupt mask */
-
-/* wd register names */
-#define WD_OWN_ID    0x00
-#define WD_CONTROL   0x01
-#define WD_TIMEOUT_PERIOD  0x02
-#define WD_CDB_1     0x03
-#define WD_CDB_2     0x04
-#define WD_CDB_3     0x05
-#define WD_CDB_4     0x06
-#define WD_CDB_5     0x07
-#define WD_CDB_6     0x08
-#define WD_CDB_7     0x09
-#define WD_CDB_8     0x0a
-#define WD_CDB_9     0x0b
-#define WD_CDB_10    0x0c
-#define WD_CDB_11    0x0d
-#define WD_CDB_12    0x0e
-#define WD_TARGET_LUN      0x0f
-#define WD_COMMAND_PHASE   0x10
-#define WD_SYNCHRONOUS_TRANSFER  0x11
-#define WD_TRANSFER_COUNT_MSB 0x12
-#define WD_TRANSFER_COUNT  0x13
-#define WD_TRANSFER_COUNT_LSB 0x14
-#define WD_DESTINATION_ID  0x15
-#define WD_SOURCE_ID    0x16
-#define WD_SCSI_STATUS     0x17
-#define WD_COMMAND      0x18
-#define WD_DATA      0x19
-#define WD_QUEUE_TAG    0x1a
-#define WD_AUXILIARY_STATUS   0x1f
-
-/* WD commands */
-#define WD_CMD_RESET    0x00
-#define WD_CMD_ABORT    0x01
-#define WD_CMD_ASSERT_ATN  0x02
-#define WD_CMD_NEGATE_ACK  0x03
-#define WD_CMD_DISCONNECT  0x04
-#define WD_CMD_RESELECT    0x05
-#define WD_CMD_SEL_ATN     0x06
-#define WD_CMD_SEL      0x07
-#define WD_CMD_SEL_ATN_XFER   0x08
-#define WD_CMD_SEL_XFER    0x09
-#define WD_CMD_RESEL_RECEIVE  0x0a
-#define WD_CMD_RESEL_SEND  0x0b
-#define WD_CMD_WAIT_SEL_RECEIVE 0x0c
-#define WD_CMD_TRANS_ADDR  0x18
-#define WD_CMD_TRANS_INFO  0x20
-#define WD_CMD_TRANSFER_PAD   0x21
-#define WD_CMD_SBT_MODE    0x80
-
-/* SCSI Bus Phases */
-#define PHS_DATA_OUT    0x00
-#define PHS_DATA_IN     0x01
-#define PHS_COMMAND     0x02
-#define PHS_STATUS      0x03
-#define PHS_MESS_OUT    0x06
-#define PHS_MESS_IN     0x07
-
-/* Command Status Register definitions */
-
-  /* reset state interrupts */
-#define CSR_RESET    0x00
-#define CSR_RESET_AF    0x01
-
-  /* successful completion interrupts */
-#define CSR_RESELECT    0x10
-#define CSR_SELECT      0x11
-#define CSR_SEL_XFER_DONE  0x16
-#define CSR_XFER_DONE      0x18
-
-  /* paused or aborted interrupts */
-#define CSR_MSGIN    0x20
-#define CSR_SDP         0x21
-#define CSR_SEL_ABORT      0x22
-#define CSR_RESEL_ABORT    0x25
-#define CSR_RESEL_ABORT_AM 0x27
-#define CSR_ABORT    0x28
-
-  /* terminated interrupts */
-#define CSR_INVALID     0x40
-#define CSR_UNEXP_DISC     0x41
-#define CSR_TIMEOUT     0x42
-#define CSR_PARITY      0x43
-#define CSR_PARITY_ATN     0x44
-#define CSR_BAD_STATUS     0x45
-#define CSR_UNEXP    0x48
-
-  /* service required interrupts */
-#define CSR_RESEL    0x80
-#define CSR_RESEL_AM    0x81
-#define CSR_DISC     0x85
-#define CSR_SRV_REQ     0x88
-
-   /* Own ID/CDB Size register */
-#define OWNID_EAF    0x08
-#define OWNID_EHP    0x10
-#define OWNID_RAF    0x20
-#define OWNID_FS_8   0x00
-#define OWNID_FS_12  0x40
-#define OWNID_FS_16  0x80
-
-   /* Control register */
-#define CTRL_HSP     0x01
-#define CTRL_HA      0x02
-#define CTRL_IDI     0x04
-#define CTRL_EDI     0x08
-#define CTRL_HHP     0x10
-#define CTRL_POLLED  0x00
-#define CTRL_BURST   0x20
-#define CTRL_BUS     0x40
-#define CTRL_DMA     0x80
-
-   /* Timeout Period register */
-#define TIMEOUT_PERIOD_VALUE  20    /* results in 200 ms. */
-
-   /* Synchronous Transfer Register */
-#define STR_FSS      0x80
-
-   /* Destination ID register */
-#define DSTID_DPD    0x40
-#define DATA_OUT_DIR 0
-#define DATA_IN_DIR  1
-#define DSTID_SCC    0x80
-
-   /* Source ID register */
-#define SRCID_MASK   0x07
-#define SRCID_SIV    0x08
-#define SRCID_DSP    0x20
-#define SRCID_ES     0x40
-#define SRCID_ER     0x80
-
-
-
-#define DEFAULT_SX_PER     500   /* (ns) fairly safe */
-#define DEFAULT_SX_OFF     0     /* aka async */
-
-#define OPTIMUM_SX_PER     252   /* (ns) best we can do (mult-of-4) */
-#define OPTIMUM_SX_OFF     12    /* size of in2000 fifo */
-
-
-/* defines for hostdata->chip */
-
-#define C_WD33C93       0
-#define C_WD33C93A      1
-#define C_WD33C93B      2
-#define C_UNKNOWN_CHIP  100
-
-/* defines for hostdata->state */
-
-#define S_UNCONNECTED         0
-#define S_SELECTING           1
-#define S_RUNNING_LEVEL2      2
-#define S_CONNECTED           3
-#define S_PRE_TMP_DISC        4
-#define S_PRE_CMP_DISC        5
-
-/* defines for hostdata->fifo */
-
-#define FI_FIFO_UNUSED        0
-#define FI_FIFO_READING       1
-#define FI_FIFO_WRITING       2
-
-/* defines for hostdata->level2 */
-/* NOTE: only the first 3 are trustworthy at this point -
- * having trouble when more than 1 device is reading/writing
- * at the same time...
- */
-
-#define L2_NONE      0  /* no combination commands - we get lots of ints */
-#define L2_SELECT    1  /* start with SEL_ATN_XFER, but never resume it */
-#define L2_BASIC     2  /* resume after STATUS ints & RDP messages */
-#define L2_DATA      3  /* resume after DATA_IN/OUT ints */
-#define L2_MOST      4  /* resume after anything except a RESELECT int */
-#define L2_RESELECT  5  /* resume after everything, including RESELECT ints */
-#define L2_ALL       6  /* always resume */
-
-/* defines for hostdata->disconnect */
-
-#define DIS_NEVER    0
-#define DIS_ADAPTIVE 1
-#define DIS_ALWAYS   2
-
-/* defines for hostdata->args */
-
-#define DB_TEST               1<<0
-#define DB_FIFO               1<<1
-#define DB_QUEUE_COMMAND      1<<2
-#define DB_EXECUTE            1<<3
-#define DB_INTR               1<<4
-#define DB_TRANSFER           1<<5
-#define DB_MASK               0x3f
-
-#define A_NO_SCSI_RESET       1<<15
-
-
-/* defines for hostdata->sync_xfer[] */
-
-#define SS_UNSET     0
-#define SS_FIRST     1
-#define SS_WAITING   2
-#define SS_SET       3
-
-/* defines for hostdata->proc */
-
-#define PR_VERSION   1<<0
-#define PR_INFO      1<<1
-#define PR_TOTALS    1<<2
-#define PR_CONNECTED 1<<3
-#define PR_INPUTQ    1<<4
-#define PR_DISCQ     1<<5
-#define PR_TEST      1<<6
-#define PR_STOP      1<<7
-
-
-#define read1_io(a)     (inb(hostdata->io_base+(a)))
-#define read2_io(a)     (inw(hostdata->io_base+(a)))
-#define write1_io(b,a)  (outb((b),hostdata->io_base+(a)))
-#define write2_io(w,a)  (outw((w),hostdata->io_base+(a)))
-
-
-struct sx_period {
-   unsigned int   period_ns;
-   uchar          reg_value;
-   };
 
+static struct Scsi_Host *instance_list = 0;
 
-struct IN2000_hostdata {
-    struct Scsi_Host *next;
-    uchar            chip;             /* what kind of wd33c93 chip? */
-    uchar            microcode;        /* microcode rev if 'B' */
-    unsigned short   io_base;          /* IO port base */
-    unsigned int     dip_switch;       /* dip switch settings */
-    unsigned int     hrev;             /* hardware revision of card */
-    volatile uchar   busy[8];          /* index = target, bit = lun */
-    volatile Scsi_Cmnd *input_Q;       /* commands waiting to be started */
-    volatile Scsi_Cmnd *selecting;     /* trying to select this command */
-    volatile Scsi_Cmnd *connected;     /* currently connected command */
-    volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */
-    uchar            state;            /* what we are currently doing */
-    uchar            fifo;             /* what the FIFO is up to */
-    uchar            level2;           /* extent to which Level-2 commands are used */
-    uchar            disconnect;       /* disconnect/reselect policy */
-    unsigned int     args;             /* set from command-line argument */
-    uchar            incoming_msg[8];  /* filled during message_in phase */
-    int              incoming_ptr;     /* mainly used with EXTENDED messages */
-    uchar            outgoing_msg[8];  /* send this during next message_out */
-    int              outgoing_len;     /* length of outgoing message */
-    unsigned int     default_sx_per;   /* default transfer period for SCSI bus */
-    uchar            sync_xfer[8];     /* sync_xfer reg settings per target */
-    uchar            sync_stat[8];     /* status of sync negotiation per target */
-    uchar            sync_off;         /* bit mask: don't use sync with these targets */
-    uchar            proc;             /* bit mask: what's in proc output */
-    };
-
-/* These inline assembly defines are derived from a patch
- * sent to me by Bill Earnest. He's done a lot of very
- * valuable thinking, testing, and coding during his effort
- * to squeeze more speed out of this driver. I really think
- * that we are doing IO at close to the maximum now with
- * the fifo. (And yes, insw uses 'edi' while outsw uses
- * 'esi'. Thanks Bill!)
- */
-
-#define FAST_READ2_IO()    \
-   __asm__ __volatile__ ("\n \
-   cld                    \n \
-   orl %%ecx, %%ecx       \n \
-   jz 1f                  \n \
-   rep                    \n \
-   insw %%dx              \n \
-1: "                       \
-   : "=D" (sp)                   /* output */   \
-   : "d" (f), "D" (sp), "c" (i)  /* input */    \
-   : "edx", "ecx", "edi" )       /* trashed */
-
-#define FAST_WRITE2_IO()   \
-   __asm__ __volatile__ ("\n \
-   cld                    \n \
-   orl %%ecx, %%ecx       \n \
-   jz 1f                  \n \
-   rep                    \n \
-   outsw %%dx             \n \
-1: "                       \
-   : "=S" (sp)                   /* output */   \
-   : "d" (f), "S" (sp), "c" (i)  /* input */    \
-   : "edx", "ecx", "esi" )       /* trashed */
 
 
 static inline uchar read_3393(struct IN2000_hostdata *hostdata, uchar reg_num)
@@ -596,10 +278,10 @@
    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 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 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:
@@ -624,7 +306,7 @@
    {1000,0x00},
    {0,   0} };
 
-int round_period(unsigned int period)
+static int round_period(unsigned int period)
 {
 int x;
 
@@ -657,7 +339,6 @@
 Scsi_Cmnd *tmp;
 unsigned long flags;
 
-
    hostdata = (struct IN2000_hostdata *)cmd->host->hostdata;
 
 DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld(",cmd->target,cmd->cmnd[0],cmd->pid))
@@ -675,7 +356,7 @@
 /* We use the Scsi_Pointer structure that's included with each command
  * as a scratchpad (as it's intended to be used!). The handy thing about
  * the SCp.xxx fields is that they're always associated with a given
- * cmd, and are preserved across disconnect-reconnect. This means we
+ * cmd, and are preserved across disconnect-reselect. This means we
  * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages
  * if we keep all the critical pointers and counters in SCp:
  *  - SCp.ptr is the pointer into the RAM buffer
@@ -703,9 +384,24 @@
 
 /* We don't set SCp.phase here - that's done in in2000_execute() */
 
-/* Preset the command status to GOOD, since that's the normal case */
+/* WD docs state that at the conclusion of a "LEVEL2" command, the
+ * status byte can be retrieved from the LUN register. Apparently,
+ * this is the case only for *uninterrupted* LEVEL2 commands! If
+ * there are any unexpected phases entered, even if they are 100%
+ * legal (different devices may choose to do things differently),
+ * the LEVEL2 command sequence is exited. This often occurs prior
+ * to receiving the status byte, in which case the driver does a
+ * status phase interrupt and gets the status byte on its own.
+ * While such a command can then be "resumed" (ie restarted to
+ * finish up as a LEVEL2 command), the LUN register will NOT be
+ * a valid status byte at the command's conclusion, and we must
+ * use the byte obtained during the earlier interrupt. Here, we
+ * preset SCp.Status to an illegal value (0xff) so that when
+ * this command finally completes, we can tell where the actual
+ * status byte is stored.
+ */
 
-   cmd->SCp.Status = GOOD;
+   cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
 
    save_flags(flags);
    cli();
@@ -803,6 +499,10 @@
    else
       hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;
 
+#ifdef PROC_STATISTICS
+   hostdata->cmd_cnt[cmd->target]++;
+#endif
+
 /*
  * Start the selection process
  */
@@ -860,8 +560,8 @@
 yes:
    cmd->SCp.phase = 1;
 
-#ifdef PROC_INTERFACE
-   disc_allowed_total++;
+#ifdef PROC_STATISTICS
+   hostdata->disc_allowed_cnt[cmd->target]++;
 #endif
 
 no:
@@ -1094,7 +794,8 @@
 
    if (data_in_dir) {
       write1_io(0,IO_FIFO_READ);
-      if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) {
+      if ((hostdata->level2 >= L2_DATA) ||
+          (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
          write_3393(hostdata,WD_COMMAND_PHASE,0x45);
          write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
          hostdata->state = S_RUNNING_LEVEL2;
@@ -1111,7 +812,8 @@
  * write any bytes that don't make it at this stage.
  */
 
-   if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) {
+      if ((hostdata->level2 >= L2_DATA) ||
+          (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
       write_3393(hostdata,WD_COMMAND_PHASE,0x45);
       write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
       hostdata->state = S_RUNNING_LEVEL2;
@@ -1177,6 +879,10 @@
    save_flags(flags);
    sti();
 
+#ifdef PROC_STATISTICS
+   hostdata->int_cnt++;
+#endif
+
 /* The IN2000 card has 2 interrupt sources OR'ed onto its IRQ line - the
  * WD3393 chip and the 2k fifo (which is actually a dual-port RAM combined
  * with a big logic array, so it's a little different than what you might
@@ -1484,9 +1190,10 @@
       case CSR_XFER_DONE|PHS_STATUS:
       case CSR_UNEXP    |PHS_STATUS:
       case CSR_SRV_REQ  |PHS_STATUS:
-DB(DB_INTR,printk("STATUS"))
+DB(DB_INTR,printk("STATUS="))
 
          cmd->SCp.Status = read_1_byte(hostdata);
+DB(DB_INTR,printk("%02x",cmd->SCp.Status))
          if (hostdata->level2 >= L2_BASIC) {
             sr = read_3393(hostdata,WD_SCSI_STATUS);  /* clear interrupt */
             hostdata->state = S_RUNNING_LEVEL2;
@@ -1494,7 +1201,6 @@
             write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
             }
          else {
-DB(DB_INTR,printk("=%02x",cmd->SCp.Status))
             hostdata->state = S_CONNECTED;
             }
          break;
@@ -1665,15 +1371,16 @@
 DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
             cmd->SCp.Message = COMMAND_COMPLETE;
             lun = read_3393(hostdata,WD_TARGET_LUN);
-            if (cmd->SCp.Status == GOOD)
-               cmd->SCp.Status = lun;
+DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun))
             hostdata->connected = NULL;
-            if (cmd->cmnd[0] != REQUEST_SENSE)
-               cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-            else if (cmd->SCp.Status != GOOD)
-               cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
             hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
             hostdata->state = S_UNCONNECTED;
+            if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
+               cmd->SCp.Status = lun;
+            if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+               cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+            else
+               cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
             cmd->scsi_done(cmd);
 
 /* We are no longer connected to a target - check to see if
@@ -1755,10 +1462,10 @@
          hostdata->connected = NULL;
          hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
          hostdata->state = S_UNCONNECTED;
-         if (cmd->cmnd[0] != REQUEST_SENSE)
-            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-         else if (cmd->SCp.Status != GOOD)
+         if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
             cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+         else
+            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
          cmd->scsi_done(cmd);
 
 /* We are no longer connected to a target - check to see if
@@ -1788,10 +1495,11 @@
                hostdata->connected = NULL;
                hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
                hostdata->state = S_UNCONNECTED;
-               if (cmd->cmnd[0] != REQUEST_SENSE)
-                  cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-               else if (cmd->SCp.Status != GOOD)
+DB(DB_INTR,printk(":%d",cmd->SCp.Status))
+               if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
                   cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+               else
+                  cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
                cmd->scsi_done(cmd);
                break;
             case S_PRE_TMP_DISC:
@@ -1801,8 +1509,8 @@
                hostdata->connected = NULL;
                hostdata->state = S_UNCONNECTED;
 
-#ifdef PROC_INTERFACE
-               disc_taken_total++;
+#ifdef PROC_STATISTICS
+               hostdata->disc_done_cnt[cmd->target]++;
 #endif
 
                break;
@@ -2158,10 +1866,11 @@
 
 
 #define MAX_IN2000_HOSTS 3
-#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *))
+#define MAX_SETUP_ARGS (sizeof(setup_args) / sizeof(char *))
 #define SETUP_BUFFER_SIZE 200
 static char setup_buffer[SETUP_BUFFER_SIZE];
-static char setup_used[MAX_SETUP_STRINGS];
+static char setup_used[MAX_SETUP_ARGS];
+static int done_setup = 0;
 
 void in2000_setup (char *str, int *ints)
 {
@@ -2172,43 +1881,44 @@
    setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
    p1 = setup_buffer;
    i = 0;
-   while (*p1 && (i < MAX_SETUP_STRINGS)) {
+   while (*p1 && (i < MAX_SETUP_ARGS)) {
       p2 = strchr(p1, ',');
       if (p2) {
          *p2 = '\0';
          if (p1 != p2)
-            setup_strings[i] = p1;
+            setup_args[i] = p1;
          p1 = p2 + 1;
          i++;
          }
       else {
-         setup_strings[i] = p1;
+         setup_args[i] = p1;
          break;
          }
       }
-   for (i=0; i<MAX_SETUP_STRINGS; i++)
+   for (i=0; i<MAX_SETUP_ARGS; i++)
       setup_used[i] = 0;
+   done_setup = 1;
 }
 
 
-/* check_setup_strings() returns index if key found, 0 if not
+/* check_setup_args() returns index if key found, 0 if not
  */
 
-static int check_setup_strings(char *key, int *flags, int *val, char *buf)
+static int check_setup_args(char *key, int *flags, int *val, char *buf)
 {
 int x;
 char *cp;
 
-   for  (x=0; x<MAX_SETUP_STRINGS; x++) {
+   for  (x=0; x<MAX_SETUP_ARGS; x++) {
       if (setup_used[x])
          continue;
-      if (!strncmp(setup_strings[x], key, strlen(key)))
+      if (!strncmp(setup_args[x], key, strlen(key)))
          break;
       }
-   if (x == MAX_SETUP_STRINGS)
+   if (x == MAX_SETUP_ARGS)
       return 0;
    setup_used[x] = 1;
-   cp = setup_strings[x] + strlen(key);
+   cp = setup_args[x] + strlen(key);
    *val = -1;
    if (*cp != ':')
       return ++x;
@@ -2221,16 +1931,10 @@
 
 
 
-struct proc_dir_entry proc_scsi_in2000 = {
-   PROC_SCSI_IN2000, 6, "in2000",
-   S_IFDIR | S_IRUGO | S_IXUGO, 2
-   };
-
-
-/* As of the 2.1.x kernel series, memory-mapped hardware such
- * as the IN2000 EPROM and dip switch must be accessed through
- * special macros declared in 'asm/io.h'. We use readb() and
- * readl() when reading from the card's BIOS area in in2000_detect().
+/* The "correct" (ie portable) way to access memory-mapped hardware
+ * such as the IN2000 EPROM and dip switch is through the use of
+ * special macros declared in 'asm/io.h'. We use readb() and readl()
+ * when reading from the card's BIOS area in in2000_detect().
  */
 static const unsigned int *bios_tab[] = {
    (unsigned int *)0xc8000,
@@ -2253,6 +1957,7 @@
    10
    };
 
+
 int in2000_detect(Scsi_Host_Template * tpnt)
 {
 struct Scsi_Host *instance;
@@ -2268,29 +1973,33 @@
 char buf[32];
 
 /* Thanks to help from Bill Earnest, probing for IN2000 cards is a
- * pretty straightforward and fool-proof operation. We do require
- * that cards have their BIOS enabled, although I hope to be able
- * to detect and use BIOS-less cards in the future. There are 3
+ * pretty straightforward and fool-proof operation. There are 3
  * possible locations for the IN2000 EPROM in memory space - if we
  * find a BIOS signature, we can read the dip switch settings from
  * the byte at BIOS+32 (shadowed in by logic on the card). From 2
  * of the switch bits we get the card's address in IO space. There's
  * an image of the dip switch there, also, so we have a way to back-
- * check that this really is an IN2000 card. Very nifty.
- *
- * There have been a couple of BIOS versions with different layouts
- * for the obvious ID strings. We look for the 2 most common ones and
- * hope that they cover all the cases...
+ * check that this really is an IN2000 card. Very nifty. Use the
+ * 'ioport:xx' command-line parameter if your BIOS EPROM is absent
+ * or disabled.
  */
 
+   if (!done_setup && setup_strings)
+      in2000_setup(setup_strings,0);
+
    detect_count = 0;
    for (bios = 0; bios_tab[bios]; bios++) {
-      if (check_setup_strings("ioport",&flags,&val,buf)) {
+      if (check_setup_args("ioport",&flags,&val,buf)) {
          base = val;
          switches = ~inb(base + IO_SWITCHES) & 0xff;
          printk("Forcing IN2000 detection at IOport 0x%x ",base);
          bios = 2;
          }
+/*
+ * There have been a couple of BIOS versions with different layouts
+ * for the obvious ID strings. We look for the 2 most common ones and
+ * hope that they cover all the cases...
+ */
       else if (readl(bios_tab[bios]+0x04) == 0x41564f4e ||
                readl(bios_tab[bios]+0x0c) == 0x61776c41) {
          printk("Found IN2000 BIOS at 0x%x ",(unsigned int)bios_tab[bios]);
@@ -2374,6 +2083,11 @@
          hostdata->busy[x] = 0;
          hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
          hostdata->sync_stat[x] = SS_UNSET;  /* using default sync values */
+#ifdef PROC_STATISTICS
+         hostdata->cmd_cnt[x] = 0;
+         hostdata->disc_allowed_cnt[x] = 0;
+         hostdata->disc_done_cnt[x] = 0;
+#endif
          }
       hostdata->input_Q = NULL;
       hostdata->selecting = NULL;
@@ -2395,36 +2109,42 @@
       else
          hostdata->sync_off = 0xff;    /* sync defaults to off */
 
-      hostdata->proc = PR_VERSION|PR_INFO|PR_TOTALS|
+#ifdef PROC_INTERFACE
+      hostdata->proc = PR_VERSION|PR_INFO|PR_STATISTICS|
                        PR_CONNECTED|PR_INPUTQ|PR_DISCQ|
                        PR_STOP;
-
-#ifdef PROC_INTERFACE
-      disc_allowed_total = 0;
-      disc_taken_total = 0;
+#ifdef PROC_STATISTICS
+      hostdata->int_cnt = 0;
+#endif
 #endif
 
-      if (check_setup_strings("nosync",&flags,&val,buf))
+      if (check_setup_args("nosync",&flags,&val,buf))
          hostdata->sync_off = val;
 
-      if (check_setup_strings("period",&flags,&val,buf))
+      if (check_setup_args("period",&flags,&val,buf))
          hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns;
 
-      if (check_setup_strings("disconnect",&flags,&val,buf)) {
+      if (check_setup_args("disconnect",&flags,&val,buf)) {
          if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
             hostdata->disconnect = val;
          else
             hostdata->disconnect = DIS_ADAPTIVE;
          }
 
-      if (check_setup_strings("noreset",&flags,&val,buf))
+      if (check_setup_args("noreset",&flags,&val,buf))
          hostdata->args ^= A_NO_SCSI_RESET;
 
-      if (check_setup_strings("debug",&flags,&val,buf))
+      if (check_setup_args("level2",&flags,&val,buf))
+         hostdata->level2 = val;
+
+      if (check_setup_args("debug",&flags,&val,buf))
          hostdata->args = (val & DB_MASK);
 
-      if (check_setup_strings("proc",&flags,&val,buf))
+#ifdef PROC_INTERFACE
+      if (check_setup_args("proc",&flags,&val,buf))
          hostdata->proc = val;
+#endif
+
 
       x = reset_hardware(instance,(hostdata->args & A_NO_SCSI_RESET)?RESET_CARD:RESET_CARD_AND_BUS);
 
@@ -2450,9 +2170,9 @@
                   (hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown",
                   hostdata->microcode);
 #ifdef DEBUGGING_ON
-      printk("setup_strings = ");
-      for (x=0; x<8; x++)
-         printk("%s,",setup_strings[x]);
+      printk("setup_args = ");
+      for (x=0; x<MAX_SETUP_ARGS; x++)
+         printk("%s,",setup_args[x]);
       printk("\n");
 #endif
       if (hostdata->sync_off == 0xff)
@@ -2496,23 +2216,18 @@
       iinfo[0] = 255;
       iinfo[1] = 63;
       iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
-
-/* This next little bit of code was intended to prevent the number of
- * tracks from exceeding 1023. As Andries Brouwer (aeb@cwi.nl) pointed
- * out in his "Large Disk HOWTO" (June 1996), this kind of DOS
- * compatibility is pointless. And wasteful on disks larger than 8 gigs.
- */
-
-#if 0
-      if (iinfo[2] > 1023)
-         iinfo[2] = 1023;
-#endif
-
       }
     return 0;
 }
 
 
+
+struct proc_dir_entry proc_scsi_in2000 = {
+   PROC_SCSI_IN2000, 6, "in2000",
+   S_IFDIR | S_IRUGO | S_IXUGO, 2
+   };
+
+
 int in2000_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
 {
 
@@ -2576,6 +2291,10 @@
          bp += 5;
          hd->proc = simple_strtoul(bp,NULL,0);
          }
+      else if (!strncmp(bp,"level2:",7)) {
+         bp += 7;
+         hd->level2 = simple_strtoul(bp,NULL,0);
+         }
       return len;
       }
 
@@ -2594,12 +2313,38 @@
                   (hd->dip_switch & 0x40)?"Yes":"No",
                   (hd->dip_switch & 0x20)?"Yes":"No");
       strcat(bp,tbuf);
-      }
-   if (hd->proc & PR_TOTALS) {
-      sprintf(tbuf,"\n%ld disc_allowed, %ld disc_taken",
-            disc_allowed_total,disc_taken_total);
+      strcat(bp,"\nsync_xfer[] =       ");
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%02x",hd->sync_xfer[x]);
+         strcat(bp,tbuf);
+         }
+      strcat(bp,"\nsync_stat[] =       ");
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%02x",hd->sync_stat[x]);
+         strcat(bp,tbuf);
+         }
+      }
+#ifdef PROC_STATISTICS
+   if (hd->proc & PR_STATISTICS) {
+      strcat(bp,"\ncommands issued:    ");
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%ld",hd->cmd_cnt[x]);
+         strcat(bp,tbuf);
+         }
+      strcat(bp,"\ndisconnects allowed:");
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%ld",hd->disc_allowed_cnt[x]);
+         strcat(bp,tbuf);
+         }
+      strcat(bp,"\ndisconnects done:   ");
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%ld",hd->disc_done_cnt[x]);
+         strcat(bp,tbuf);
+         }
+      sprintf(tbuf,"\ninterrupts:      \t%ld",hd->int_cnt);
       strcat(bp,tbuf);
       }
+#endif
    if (hd->proc & PR_CONNECTED) {
       strcat(bp,"\nconnected:     ");
       if (hd->connected) {
diff -u --recursive --new-file v2.1.45/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h
--- v2.1.45/linux/drivers/scsi/in2000.h	Fri Apr  4 08:52:23 1997
+++ linux/drivers/scsi/in2000.h	Sat Jul 19 12:50:44 1997
@@ -2,7 +2,7 @@
  *    in2000.h -  Linux device driver definitions for the
  *                Always IN2000 ISA SCSI card.
  *
- *    IMPORTANT: This file is for version 1.30 - 14/Oct/1996
+ *    IMPORTANT: This file is for version 1.31 - 06/Jul/1997
  *
  * Copyright (c) 1996 John Shifflett, GeoLog Consulting
  *    john@geolog.com
@@ -23,13 +23,366 @@
 #ifndef IN2000_H
 #define IN2000_H
 
-extern struct proc_dir_entry proc_scsi_in2000;
+#include <asm/io.h>
+
+#define PROC_INTERFACE     /* add code for /proc/scsi/in2000/xxx interface */
+#ifdef  PROC_INTERFACE
+#define PROC_STATISTICS    /* add code for keeping various real time stats */
+#endif
+
+#define SYNC_DEBUG         /* extra info on sync negotiation printed */
+#define DEBUGGING_ON       /* enable command-line debugging bitmask */
+#define DEBUG_DEFAULTS 0   /* default bitmask - change from command-line */
+
+#define FAST_READ_IO       /* No problems with these on my machine */
+#define FAST_WRITE_IO
+
+#ifdef DEBUGGING_ON
+#define DB(f,a) if (hostdata->args & (f)) a;
+#define CHECK_NULL(p,s) /* if (!(p)) {printk("\n"); while (1) printk("NP:%s\r",(s));} */
+#else
+#define DB(f,a)
+#define CHECK_NULL(p,s)
+#endif
+
+#define uchar unsigned char
+
+#define read1_io(a)     (inb(hostdata->io_base+(a)))
+#define read2_io(a)     (inw(hostdata->io_base+(a)))
+#define write1_io(b,a)  (outb((b),hostdata->io_base+(a)))
+#define write2_io(w,a)  (outw((w),hostdata->io_base+(a)))
+
+/* These inline assembly defines are derived from a patch
+ * sent to me by Bill Earnest. He's done a lot of very
+ * valuable thinking, testing, and coding during his effort
+ * to squeeze more speed out of this driver. I really think
+ * that we are doing IO at close to the maximum now with
+ * the fifo. (And yes, insw uses 'edi' while outsw uses
+ * 'esi'. Thanks Bill!)
+ */
+
+#define FAST_READ2_IO()    \
+   __asm__ __volatile__ ("\n \
+   cld                    \n \
+   orl %%ecx, %%ecx       \n \
+   jz 1f                  \n \
+   rep                    \n \
+   insw %%dx              \n \
+1: "                       \
+   : "=D" (sp)                   /* output */   \
+   : "d" (f), "D" (sp), "c" (i)  /* input */    \
+   : "edx", "ecx", "edi" )       /* trashed */
+
+#define FAST_WRITE2_IO()   \
+   __asm__ __volatile__ ("\n \
+   cld                    \n \
+   orl %%ecx, %%ecx       \n \
+   jz 1f                  \n \
+   rep                    \n \
+   outsw %%dx             \n \
+1: "                       \
+   : "=S" (sp)                   /* output */   \
+   : "d" (f), "S" (sp), "c" (i)  /* input */    \
+   : "edx", "ecx", "esi" )       /* trashed */
+
+
+/* IN2000 io_port offsets */
+#define IO_WD_ASR       0x00     /* R - 3393 auxstat reg */
+#define     ASR_INT        0x80
+#define     ASR_LCI        0x40
+#define     ASR_BSY        0x20
+#define     ASR_CIP        0x10
+#define     ASR_PE         0x02
+#define     ASR_DBR        0x01
+#define IO_WD_ADDR      0x00     /* W - 3393 address reg */
+#define IO_WD_DATA      0x01     /* R/W - rest of 3393 regs */
+#define IO_FIFO         0x02     /* R/W - in2000 dual-port fifo (16 bits) */
+#define IN2000_FIFO_SIZE   2048  /*    fifo capacity in bytes */
+#define IO_CARD_RESET   0x03     /* W - in2000 start master reset */
+#define IO_FIFO_COUNT   0x04     /* R - in2000 fifo counter */
+#define IO_FIFO_WRITE   0x05     /* W - clear fifo counter, start write */
+#define IO_FIFO_READ    0x07     /* W - start fifo read */
+#define IO_LED_OFF      0x08     /* W - turn off in2000 activity LED */
+#define IO_SWITCHES     0x08     /* R - read in2000 dip switch */
+#define     SW_ADDR0       0x01  /*    bit 0 = bit 0 of index to io addr */
+#define     SW_ADDR1       0x02  /*    bit 1 = bit 1 of index io addr */
+#define     SW_DISINT      0x04  /*    bit 2 true if ints disabled */
+#define     SW_INT0        0x08  /*    bit 3 = bit 0 of index to interrupt */
+#define     SW_INT1        0x10  /*    bit 4 = bit 1 of index to interrupt */
+#define     SW_INT_SHIFT   3     /*    shift right this amount to right justify int bits */
+#define     SW_SYNC_DOS5   0x20  /*    bit 5 used by Always BIOS */
+#define     SW_FLOPPY      0x40  /*    bit 6 true if floppy enabled */
+#define     SW_BIT7        0x80  /*    bit 7 hardwired true (ground) */
+#define IO_LED_ON       0x09     /* W - turn on in2000 activity LED */
+#define IO_HARDWARE     0x0a     /* R - read in2000 hardware rev, stop reset */
+#define IO_INTR_MASK    0x0c     /* W - in2000 interrupt mask reg */
+#define     IMASK_WD       0x01  /*    WD33c93 interrupt mask */
+#define     IMASK_FIFO     0x02  /*    FIFO interrupt mask */
+
+/* wd register names */
+#define WD_OWN_ID    0x00
+#define WD_CONTROL   0x01
+#define WD_TIMEOUT_PERIOD  0x02
+#define WD_CDB_1     0x03
+#define WD_CDB_2     0x04
+#define WD_CDB_3     0x05
+#define WD_CDB_4     0x06
+#define WD_CDB_5     0x07
+#define WD_CDB_6     0x08
+#define WD_CDB_7     0x09
+#define WD_CDB_8     0x0a
+#define WD_CDB_9     0x0b
+#define WD_CDB_10    0x0c
+#define WD_CDB_11    0x0d
+#define WD_CDB_12    0x0e
+#define WD_TARGET_LUN      0x0f
+#define WD_COMMAND_PHASE   0x10
+#define WD_SYNCHRONOUS_TRANSFER  0x11
+#define WD_TRANSFER_COUNT_MSB 0x12
+#define WD_TRANSFER_COUNT  0x13
+#define WD_TRANSFER_COUNT_LSB 0x14
+#define WD_DESTINATION_ID  0x15
+#define WD_SOURCE_ID    0x16
+#define WD_SCSI_STATUS     0x17
+#define WD_COMMAND      0x18
+#define WD_DATA      0x19
+#define WD_QUEUE_TAG    0x1a
+#define WD_AUXILIARY_STATUS   0x1f
+
+/* WD commands */
+#define WD_CMD_RESET    0x00
+#define WD_CMD_ABORT    0x01
+#define WD_CMD_ASSERT_ATN  0x02
+#define WD_CMD_NEGATE_ACK  0x03
+#define WD_CMD_DISCONNECT  0x04
+#define WD_CMD_RESELECT    0x05
+#define WD_CMD_SEL_ATN     0x06
+#define WD_CMD_SEL      0x07
+#define WD_CMD_SEL_ATN_XFER   0x08
+#define WD_CMD_SEL_XFER    0x09
+#define WD_CMD_RESEL_RECEIVE  0x0a
+#define WD_CMD_RESEL_SEND  0x0b
+#define WD_CMD_WAIT_SEL_RECEIVE 0x0c
+#define WD_CMD_TRANS_ADDR  0x18
+#define WD_CMD_TRANS_INFO  0x20
+#define WD_CMD_TRANSFER_PAD   0x21
+#define WD_CMD_SBT_MODE    0x80
+
+/* SCSI Bus Phases */
+#define PHS_DATA_OUT    0x00
+#define PHS_DATA_IN     0x01
+#define PHS_COMMAND     0x02
+#define PHS_STATUS      0x03
+#define PHS_MESS_OUT    0x06
+#define PHS_MESS_IN     0x07
+
+/* Command Status Register definitions */
+
+  /* reset state interrupts */
+#define CSR_RESET    0x00
+#define CSR_RESET_AF    0x01
+
+  /* successful completion interrupts */
+#define CSR_RESELECT    0x10
+#define CSR_SELECT      0x11
+#define CSR_SEL_XFER_DONE  0x16
+#define CSR_XFER_DONE      0x18
+
+  /* paused or aborted interrupts */
+#define CSR_MSGIN    0x20
+#define CSR_SDP         0x21
+#define CSR_SEL_ABORT      0x22
+#define CSR_RESEL_ABORT    0x25
+#define CSR_RESEL_ABORT_AM 0x27
+#define CSR_ABORT    0x28
+
+  /* terminated interrupts */
+#define CSR_INVALID     0x40
+#define CSR_UNEXP_DISC     0x41
+#define CSR_TIMEOUT     0x42
+#define CSR_PARITY      0x43
+#define CSR_PARITY_ATN     0x44
+#define CSR_BAD_STATUS     0x45
+#define CSR_UNEXP    0x48
+
+  /* service required interrupts */
+#define CSR_RESEL    0x80
+#define CSR_RESEL_AM    0x81
+#define CSR_DISC     0x85
+#define CSR_SRV_REQ     0x88
+
+   /* Own ID/CDB Size register */
+#define OWNID_EAF    0x08
+#define OWNID_EHP    0x10
+#define OWNID_RAF    0x20
+#define OWNID_FS_8   0x00
+#define OWNID_FS_12  0x40
+#define OWNID_FS_16  0x80
+
+   /* Control register */
+#define CTRL_HSP     0x01
+#define CTRL_HA      0x02
+#define CTRL_IDI     0x04
+#define CTRL_EDI     0x08
+#define CTRL_HHP     0x10
+#define CTRL_POLLED  0x00
+#define CTRL_BURST   0x20
+#define CTRL_BUS     0x40
+#define CTRL_DMA     0x80
+
+   /* Timeout Period register */
+#define TIMEOUT_PERIOD_VALUE  20    /* results in 200 ms. */
+
+   /* Synchronous Transfer Register */
+#define STR_FSS      0x80
+
+   /* Destination ID register */
+#define DSTID_DPD    0x40
+#define DATA_OUT_DIR 0
+#define DATA_IN_DIR  1
+#define DSTID_SCC    0x80
+
+   /* Source ID register */
+#define SRCID_MASK   0x07
+#define SRCID_SIV    0x08
+#define SRCID_DSP    0x20
+#define SRCID_ES     0x40
+#define SRCID_ER     0x80
+
+
+
+#define ILLEGAL_STATUS_BYTE   0xff
+
+
+#define DEFAULT_SX_PER     500   /* (ns) fairly safe */
+#define DEFAULT_SX_OFF     0     /* aka async */
+
+#define OPTIMUM_SX_PER     252   /* (ns) best we can do (mult-of-4) */
+#define OPTIMUM_SX_OFF     12    /* size of in2000 fifo */
+
+struct sx_period {
+   unsigned int   period_ns;
+   uchar          reg_value;
+   };
+
+
+struct IN2000_hostdata {
+    struct Scsi_Host *next;
+    uchar            chip;             /* what kind of wd33c93 chip? */
+    uchar            microcode;        /* microcode rev if 'B' */
+    unsigned short   io_base;          /* IO port base */
+    unsigned int     dip_switch;       /* dip switch settings */
+    unsigned int     hrev;             /* hardware revision of card */
+    volatile uchar   busy[8];          /* index = target, bit = lun */
+    volatile Scsi_Cmnd *input_Q;       /* commands waiting to be started */
+    volatile Scsi_Cmnd *selecting;     /* trying to select this command */
+    volatile Scsi_Cmnd *connected;     /* currently connected command */
+    volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */
+    uchar            state;            /* what we are currently doing */
+    uchar            fifo;             /* what the FIFO is up to */
+    uchar            level2;           /* extent to which Level-2 commands are used */
+    uchar            disconnect;       /* disconnect/reselect policy */
+    unsigned int     args;             /* set from command-line argument */
+    uchar            incoming_msg[8];  /* filled during message_in phase */
+    int              incoming_ptr;     /* mainly used with EXTENDED messages */
+    uchar            outgoing_msg[8];  /* send this during next message_out */
+    int              outgoing_len;     /* length of outgoing message */
+    unsigned int     default_sx_per;   /* default transfer period for SCSI bus */
+    uchar            sync_xfer[8];     /* sync_xfer reg settings per target */
+    uchar            sync_stat[8];     /* status of sync negotiation per target */
+    uchar            sync_off;         /* bit mask: don't use sync with these targets */
+#ifdef PROC_INTERFACE
+    uchar            proc;             /* bit mask: what's in proc output */
+#ifdef PROC_STATISTICS
+    unsigned long    cmd_cnt[8];       /* # of commands issued per target */
+    unsigned long    int_cnt;          /* # of interrupts serviced */
+    unsigned long    disc_allowed_cnt[8]; /* # of disconnects allowed per target */
+    unsigned long    disc_done_cnt[8]; /* # of disconnects done per target*/
+#endif
+#endif
+    };
+
+
+/* defines for hostdata->chip */
+
+#define C_WD33C93       0
+#define C_WD33C93A      1
+#define C_WD33C93B      2
+#define C_UNKNOWN_CHIP  100
+
+/* defines for hostdata->state */
+
+#define S_UNCONNECTED         0
+#define S_SELECTING           1
+#define S_RUNNING_LEVEL2      2
+#define S_CONNECTED           3
+#define S_PRE_TMP_DISC        4
+#define S_PRE_CMP_DISC        5
+
+/* defines for hostdata->fifo */
+
+#define FI_FIFO_UNUSED        0
+#define FI_FIFO_READING       1
+#define FI_FIFO_WRITING       2
+
+/* defines for hostdata->level2 */
+/* NOTE: only the first 3 are trustworthy at this point -
+ * having trouble when more than 1 device is reading/writing
+ * at the same time...
+ */
+
+#define L2_NONE      0  /* no combination commands - we get lots of ints */
+#define L2_SELECT    1  /* start with SEL_ATN_XFER, but never resume it */
+#define L2_BASIC     2  /* resume after STATUS ints & RDP messages */
+#define L2_DATA      3  /* resume after DATA_IN/OUT ints */
+#define L2_MOST      4  /* resume after anything except a RESELECT int */
+#define L2_RESELECT  5  /* resume after everything, including RESELECT ints */
+#define L2_ALL       6  /* always resume */
+
+/* defines for hostdata->disconnect */
+
+#define DIS_NEVER    0
+#define DIS_ADAPTIVE 1
+#define DIS_ALWAYS   2
+
+/* defines for hostdata->args */
+
+#define DB_TEST               1<<0
+#define DB_FIFO               1<<1
+#define DB_QUEUE_COMMAND      1<<2
+#define DB_EXECUTE            1<<3
+#define DB_INTR               1<<4
+#define DB_TRANSFER           1<<5
+#define DB_MASK               0x3f
+
+#define A_NO_SCSI_RESET       1<<15
+
+
+/* defines for hostdata->sync_xfer[] */
+
+#define SS_UNSET     0
+#define SS_FIRST     1
+#define SS_WAITING   2
+#define SS_SET       3
+
+/* defines for hostdata->proc */
+
+#define PR_VERSION   1<<0
+#define PR_INFO      1<<1
+#define PR_STATISTICS 1<<2
+#define PR_CONNECTED 1<<3
+#define PR_INPUTQ    1<<4
+#define PR_DISCQ     1<<5
+#define PR_TEST      1<<6
+#define PR_STOP      1<<7
+
 
 int in2000_detect(Scsi_Host_Template *);
 int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int in2000_abort(Scsi_Cmnd *);
 void in2000_setup(char *, int *);
 int in2000_proc_info(char *, char **, off_t, int, int, int);
+struct proc_dir_entry proc_scsi_in2000;
 int in2000_biosparam(struct scsi_disk *, kdev_t, int *);
 int in2000_reset(Scsi_Cmnd *, unsigned int);
 
@@ -40,7 +393,7 @@
 #define IN2000_HOST_ID  7
 
 #define IN2000 {  NULL,                /* link pointer for modules */ \
-                  NULL,                /* module pointer for modules */ \
+                  NULL,                /* usage_count for modules */ \
                   &proc_scsi_in2000,   /* pointer to /proc/scsi directory entry */ \
                   in2000_proc_info,    /* pointer to proc info function */ \
                   "Always IN2000",     /* device name */ \
diff -u --recursive --new-file v2.1.45/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.1.45/linux/fs/binfmt_aout.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/binfmt_aout.c	Sat Jul 19 11:29:59 1997
@@ -127,16 +127,8 @@
 		goto end_coredump;
 	if (get_write_access(inode))
 		goto end_coredump;
-	file.f_mode = 3;
-	file.f_flags = 0;
-	file.f_count = 1;
-	file.f_dentry = dentry;
-	file.f_pos = 0;
-	file.f_reada = 0;
-	file.f_op = inode->i_op->default_file_ops;
-	if (file.f_op->open)
-		if (file.f_op->open(inode,&file))
-			goto done_coredump;
+	if (init_private_file(&file, dentry, 3))
+		goto end_coredump;
 	if (!file.f_op->write)
 		goto close_coredump;
 	has_dumped = 1;
diff -u --recursive --new-file v2.1.45/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.45/linux/fs/binfmt_elf.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/binfmt_elf.c	Sat Jul 19 11:29:59 1997
@@ -1091,16 +1091,8 @@
 		goto end_coredump;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		goto end_coredump;
-	file.f_mode = 3;
-	file.f_flags = 0;
-	file.f_count = 1;
-	file.f_dentry = dentry;
-	file.f_pos = 0;
-	file.f_reada = 0;
-	file.f_op = inode->i_op->default_file_ops;
-	if (file.f_op->open)
-		if (file.f_op->open(inode,&file))
-			goto end_coredump;
+	if (init_private_file(&file, dentry, 3))
+		goto end_coredump;
 	if (!file.f_op->write)
 		goto close_coredump;
 	has_dumped = 1;
diff -u --recursive --new-file v2.1.45/linux/fs/exec.c linux/fs/exec.c
--- v2.1.45/linux/fs/exec.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/exec.c	Sat Jul 19 11:29:59 1997
@@ -352,17 +352,9 @@
 
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		goto end_readexec;
-	file.f_mode = 1;
-	file.f_flags = 0;
-	file.f_count = 1;
-	file.f_dentry = dentry;
-	file.f_pos = 0;
-	file.f_reada = 0;
-	file.f_op = inode->i_op->default_file_ops;
-	if (file.f_op->open)
-		if (file.f_op->open(inode,&file))
-			goto end_readexec;
-	if (!file.f_op || !file.f_op->read)
+	if (init_private_file(&file, dentry, 1))
+		goto end_readexec;
+	if (!file.f_op->read)
 		goto close_readexec;
 	if (file.f_op->llseek) {
 		if (file.f_op->llseek(inode,&file,offset,0) != offset)
diff -u --recursive --new-file v2.1.45/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.1.45/linux/fs/ext2/ialloc.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/ext2/ialloc.c	Fri Jul 18 11:25:38 1997
@@ -154,8 +154,26 @@
 	return 0;
 }
 
+/*
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
+ *
+ * HOWEVER: we must make sure that we get no aliases,
+ * which means that we have to call "clear_inode()"
+ * _before_ we mark the inode not in use in the inode
+ * bitmaps. Otherwise a newly created file might use
+ * the same inode number (not actually the same pointer
+ * though), and then we'd have two inodes sharing the
+ * same inode number and space on the harddisk.
+ */
 void ext2_free_inode (struct inode * inode)
 {
+	int is_directory;
+	unsigned long ino;
 	struct super_block * sb;
 	struct buffer_head * bh;
 	struct buffer_head * bh2;
@@ -185,30 +203,40 @@
 		return;
 	}
 
-	ext2_debug ("freeing inode %lu\n", inode->i_ino);
+	ino = inode->i_ino;
+	ext2_debug ("freeing inode %lu\n", ino);
 
 	sb = inode->i_sb;
 	lock_super (sb);
-	if (inode->i_ino < EXT2_FIRST_INO(sb) ||
-	    inode->i_ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) {
+	if (ino < EXT2_FIRST_INO(sb) ||
+	    ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) {
 		ext2_error (sb, "free_inode",
 			    "reserved inode or nonexistent inode");
 		unlock_super (sb);
 		return;
 	}
 	es = sb->u.ext2_sb.s_es;
-	block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb);
-	bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb);
+	block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
+	bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb);
 	bitmap_nr = load_inode_bitmap (sb, block_group);
 	bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
+
+	is_directory = S_ISDIR(inode->i_mode);
+
+	/* Do this BEFORE marking the inode not in use */
+	if (sb->dq_op)
+		sb->dq_op->free_inode (inode, 1);
+	clear_inode (inode);
+
+	/* Ok, now we can actually update the inode bitmaps.. */
 	if (!ext2_clear_bit (bit, bh->b_data))
 		ext2_warning (sb, "ext2_free_inode",
-			      "bit already cleared for inode %lu", inode->i_ino);
+			      "bit already cleared for inode %lu", ino);
 	else {
 		gdp = get_group_desc (sb, block_group, &bh2);
 		gdp->bg_free_inodes_count =
 			cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
-		if (S_ISDIR(inode->i_mode))
+		if (is_directory)
 			gdp->bg_used_dirs_count =
 				cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
 		mark_buffer_dirty(bh2, 1);
@@ -221,10 +249,7 @@
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
 	}
-	if (sb->dq_op)
-		sb->dq_op->free_inode (inode, 1);
 	sb->s_dirt = 1;
-	clear_inode (inode);
 	unlock_super (sb);
 }
 
diff -u --recursive --new-file v2.1.45/linux/fs/file_table.c linux/fs/file_table.c
--- v2.1.45/linux/fs/file_table.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/file_table.c	Sat Jul 19 11:29:59 1997
@@ -102,6 +102,24 @@
 	return f;
 }
 
+/*
+ * Clear and initialize a (private) struct file for the given dentry,
+ * and call the open function (if any).  The caller must verify that
+ * inode->i_op and inode->i_op->default_file_ops are not NULL.
+ */
+int init_private_file(struct file *filp, struct dentry *dentry, int mode)
+{
+	memset(filp, 0, sizeof(*filp));
+	filp->f_mode   = mode;
+	filp->f_count  = 1;
+	filp->f_dentry = dentry;
+	filp->f_op     = dentry->d_inode->i_op->default_file_ops;
+	if (filp->f_op->open)
+		return filp->f_op->open(dentry->d_inode, filp);
+	else
+		return 0;
+}
+
 #ifdef CONFIG_QUOTA
 
 void add_dquot_ref(kdev_t dev, short type)
diff -u --recursive --new-file v2.1.45/linux/fs/inode.c linux/fs/inode.c
--- v2.1.45/linux/fs/inode.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/inode.c	Fri Jul 18 12:54:33 1997
@@ -296,7 +296,7 @@
 	memset(&inode->u, 0, sizeof(inode->u));
 	inode->i_sock = 0;
 	inode->i_op = NULL;
-	inode->i_nlink = 0;
+	inode->i_nlink = 1;
 	inode->i_writecount = 0;
 	inode->i_size = 0;
 	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
@@ -438,6 +438,8 @@
 			if (!inode->i_nlink) {
 				list_del(&inode->i_hash);
 				INIT_LIST_HEAD(&inode->i_hash);
+				list_del(&inode->i_list);
+				INIT_LIST_HEAD(&inode->i_list);
 				if (op && op->delete_inode) {
 					void (*delete)(struct inode *) = op->delete_inode;
 					spin_unlock(&inode_lock);
diff -u --recursive --new-file v2.1.45/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.1.45/linux/fs/minix/inode.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/minix/inode.c	Fri Jul 18 12:42:29 1997
@@ -24,10 +24,8 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 
-void minix_put_inode(struct inode *inode)
+static void minix_delete_inode(struct inode *inode)
 {
-	if (inode->i_nlink)
-		return;
 	inode->i_size = 0;
 	minix_truncate(inode);
 	minix_free_inode(inode);
@@ -77,9 +75,10 @@
 
 static struct super_operations minix_sops = {
 	minix_read_inode,
-	NULL,
 	minix_write_inode,
-	minix_put_inode,
+	NULL,			/* put_inode */
+	minix_delete_inode,
+	NULL,			/* notify_change */
 	minix_put_super,
 	minix_write_super,
 	minix_statfs,
diff -u --recursive --new-file v2.1.45/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.1.45/linux/fs/minix/namei.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/minix/namei.c	Fri Jul 18 12:45:54 1997
@@ -47,9 +47,6 @@
 	*offset += info->s_dirsize;
 	if (!de->inode || len > info->s_namelen)
 		return 0;
-	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
-	if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
-		return 1;
 	return namecompare(len,info->s_namelen,name,de->name);
 }
 
@@ -104,24 +101,22 @@
 	return NULL;
 }
 
-int minix_lookup(struct inode * dir, struct qstr *name,
-	struct inode ** result)
+int minix_lookup(struct inode * dir, struct dentry *dentry)
 {
-	int ino;
+	struct inode * inode = NULL;
 	struct minix_dir_entry * de;
 	struct buffer_head * bh;
 
-	*result = NULL;
-	if (!dir)
-		return -ENOENT;
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOENT;
-	if (!(bh = minix_find_entry(dir, name->name, name->len, &de)))
-		return -ENOENT;
-	ino = de->inode;
-	brelse(bh);
-	if (!(*result = iget(dir->i_sb,ino)))
-		return -EACCES;
+	bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+	if (bh) {
+		unsigned long ino = le32_to_cpu(de->inode);
+		brelse (bh);
+		inode = iget(dir->i_sb, ino);
+ 
+		if (!inode)
+			return -EACCES;
+	}
+	d_add(dentry, inode);
 	return 0;
 }
 
@@ -602,29 +597,21 @@
 	return 0;
 }
 
-static int subdir(struct inode * new_inode, struct inode * old_inode)
+static int subdir(struct dentry * new_dentry, struct dentry * old_dentry)
 {
-	int ino;
-	int result;
+	int result = 0;
 
-	new_inode->i_count++;
-	result = 0;
 	for (;;) {
-		if (new_inode == old_inode) {
-			result = 1;
-			break;
+		if (new_dentry != old_dentry) {
+			struct dentry * parent = new_dentry->d_parent;
+			if (parent == new_dentry)
+				break;
+			new_dentry = parent;
+			continue;
 		}
-		if (new_inode->i_dev != old_inode->i_dev)
-			break;
-		ino = new_inode->i_ino;
-		if (minix_lookup(new_inode,
-				 &(struct qstr) { "..", 2, 0 },
-				 &new_inode))
-			break;
-		if (new_inode->i_ino == ino)
-			break;
+		result = 1;
+		break;
 	}
-	iput(new_inode);
 	return result;
 }
 
@@ -690,7 +677,7 @@
 		if (!S_ISDIR(old_inode->i_mode))
 			goto end_rename;
 		retval = -EINVAL;
-		if (subdir(new_dir, old_inode))
+		if (subdir(new_dentry, old_dentry))
 			goto end_rename;
 		retval = -ENOTEMPTY;
 		if (!empty_dir(new_inode))
@@ -709,7 +696,7 @@
 		if (new_inode && !S_ISDIR(new_inode->i_mode))
 			goto end_rename;
 		retval = -EINVAL;
-		if (subdir(new_dir, old_inode))
+		if (subdir(new_dentry, old_dentry))
 			goto end_rename;
 		retval = -EIO;
 		dir_bh = minix_bread(old_inode,0,0);
diff -u --recursive --new-file v2.1.45/linux/fs/namei.c linux/fs/namei.c
--- v2.1.45/linux/fs/namei.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/namei.c	Sat Jul 19 11:34:29 1997
@@ -255,7 +255,6 @@
 		}
 		up(&dir->i_sem);
 	}
-	up(&dir->i_sem);
 	return result;
 }
 
@@ -380,7 +379,7 @@
 	}
 
 	if (!*name)
-		return base;
+		goto return_base;
 
 	/* At this point we know we have a real path component. */
 	for(;;) {
@@ -422,9 +421,10 @@
 			break;
 
 		base = do_follow_link(base, dentry);
-		if (c)
+		if (c && !IS_ERR(base))
 			continue;
 
+return_base:
 		return base;
 	}
 	dput(base);
@@ -742,7 +742,7 @@
 	struct inode *dir;
 	struct dentry *dentry;
 
-	dentry = lookup_dentry(name, NULL, 1);
+	dentry = lookup_dentry(name, NULL, 0);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto exit;
@@ -1051,13 +1051,13 @@
 	struct inode * old_dir, * new_dir;
 	struct dentry * old_dentry, *new_dentry;
 
-	old_dentry = lookup_dentry(oldname, NULL, 1);
+	old_dentry = lookup_dentry(oldname, NULL, 0);
 
 	error = PTR_ERR(old_dentry);
 	if (IS_ERR(old_dentry))
 		goto exit;
 
-	new_dentry = lookup_dentry(newname, NULL, 1);
+	new_dentry = lookup_dentry(newname, NULL, 0);
 
 	error = PTR_ERR(new_dentry);
 	if (IS_ERR(new_dentry))
diff -u --recursive --new-file v2.1.45/linux/fs/open.c linux/fs/open.c
--- v2.1.45/linux/fs/open.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/open.c	Sat Jul 19 11:34:29 1997
@@ -487,22 +487,17 @@
 	return error;
 }
 
-asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
 {
 	struct inode * inode;
-	struct dentry * dentry;
-	struct file * file;
 	struct iattr newattrs;
-	int error = -EBADF;
+	int error;
 
-	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		goto out;
 	error = -ENOENT;
-	if (!(dentry = file->f_dentry))
-		goto out;
-	if (!(inode = dentry->d_inode))
+	if (!(inode = dentry->d_inode)) {
+		printk("chown_common: NULL inode\n");
 		goto out;
+	}
 	error = -EROFS;
 	if (IS_RDONLY(inode))
 		goto out;
@@ -545,16 +540,33 @@
 	} else
 		error = notify_change(inode, &newattrs);
 out:
-	unlock_kernel();
 	return error;
 }
 
+asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group)
+{
+	struct dentry * dentry;
+	int error;
+
+	lock_kernel();
+	dentry = lnamei(filename);
+
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
+		goto out;
+
+	error = chown_common(dentry, user, group);
+
+	dput(dentry);
+out:
+	unlock_kernel();
+	return(error);
+}
+
 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
 {
 	struct dentry * dentry;
-	struct inode * inode;
 	int error;
-	struct iattr newattrs;
 
 	lock_kernel();
 	dentry = namei(filename);
@@ -562,56 +574,33 @@
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto out;
-	inode = dentry->d_inode;
-
-	error = -EROFS;
-	if (IS_RDONLY(inode))
-		goto dput_and_out;
 
-	error = -EPERM;
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		goto dput_and_out;
+	error = chown_common(dentry, user, group);
 
-	if (user == (uid_t) -1)
-		user = inode->i_uid;
-	if (group == (gid_t) -1)
-		group = inode->i_gid;
-	newattrs.ia_mode = inode->i_mode;
-	newattrs.ia_uid = user;
-	newattrs.ia_gid = group;
-	newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
-	/*
-	 * If the owner has been changed, remove the setuid bit
-	 */
-	if (inode->i_mode & S_ISUID) {
-		newattrs.ia_mode &= ~S_ISUID;
-		newattrs.ia_valid |= ATTR_MODE;
-	}
-	/*
-	 * If the group has been changed, remove the setgid bit
-	 *
-	 * Don't remove the setgid bit if no group execute bit.
-	 * This is a file marked for mandatory locking.
-	 */
-	if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
-		newattrs.ia_mode &= ~S_ISGID;
-		newattrs.ia_valid |= ATTR_MODE;
-	}
-	if (inode->i_sb->dq_op) {
-		inode->i_sb->dq_op->initialize(inode, -1);
-		error = -EDQUOT;
-		if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
-			goto dput_and_out;
-		error = notify_change(inode, &newattrs);
-		if (error)
-			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
-	} else
-		error = notify_change(inode, &newattrs);
-dput_and_out:
 	dput(dentry);
 out:
 	unlock_kernel();
 	return(error);
+}
+
+asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+{
+	struct dentry * dentry;
+	struct file * file;
+	int error = -EBADF;
+
+	lock_kernel();
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+		goto out;
+	error = -ENOENT;
+	if (!(dentry = file->f_dentry))
+		goto out;
+
+	error = chown_common(dentry, user, group);
+
+out:
+	unlock_kernel();
+	return error;
 }
 
 /*
diff -u --recursive --new-file v2.1.45/linux/fs/pipe.c linux/fs/pipe.c
--- v2.1.45/linux/fs/pipe.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/pipe.c	Thu Jul 17 10:24:24 1997
@@ -391,7 +391,6 @@
 		} else {
 			PIPE_BASE(*inode) = (char *) page;
 			inode->i_op = &pipe_inode_operations;
-			inode->i_count = 1;
 			PIPE_WAIT(*inode) = NULL;
 			PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
 			PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
@@ -404,7 +403,7 @@
 			 * that it already _is_ on the dirty list.
 			 */
 			inode->i_state = 1 << I_DIRTY;
-			inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR;
+			inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
 			inode->i_uid = current->fsuid;
 			inode->i_gid = current->fsgid;
 			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff -u --recursive --new-file v2.1.45/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.45/linux/include/linux/fs.h	Thu Jul 17 10:06:08 1997
+++ linux/include/linux/fs.h	Sat Jul 19 12:49:58 1997
@@ -385,6 +385,8 @@
 	void			*private_data;
 };
 
+extern int init_private_file(struct file *, struct dentry *, int);
+
 #define FL_POSIX	1
 #define FL_FLOCK	2
 #define FL_BROKEN	4	/* broken flock() emulation */
diff -u --recursive --new-file v2.1.45/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v2.1.45/linux/include/linux/minix_fs.h	Thu Jul 17 10:06:08 1997
+++ linux/include/linux/minix_fs.h	Fri Jul 18 12:43:40 1997
@@ -88,8 +88,7 @@
 
 #ifdef __KERNEL__
 
-extern int minix_lookup(struct inode * dir, struct qstr *name,
-                        struct inode ** result);
+extern int minix_lookup(struct inode * dir, struct dentry *dentry);
 extern int minix_create(struct inode * dir, struct dentry *dentry, int mode);
 extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode);
 extern int minix_rmdir(struct inode * dir, struct dentry *dentry);
@@ -120,7 +119,6 @@
 extern int minix_remount (struct super_block * sb, int * flags, char * data);
 extern void minix_read_inode(struct inode *);
 extern void minix_write_inode(struct inode *);
-extern void minix_put_inode(struct inode *);
 extern int minix_statfs(struct super_block *, struct statfs *, int);
 extern int minix_sync_inode(struct inode *);
 extern int minix_sync_file(struct inode *, struct file *);
diff -u --recursive --new-file v2.1.45/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.45/linux/kernel/ksyms.c	Thu Jul 17 10:06:09 1997
+++ linux/kernel/ksyms.c	Fri Jul 18 12:40:13 1997
@@ -150,6 +150,10 @@
 EXPORT_SYMBOL(close_fp);
 EXPORT_SYMBOL(d_alloc_root);
 EXPORT_SYMBOL(d_delete);
+EXPORT_SYMBOL(d_add);
+EXPORT_SYMBOL(d_move);
+EXPORT_SYMBOL(d_instantiate);
+EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(insert_file_free);
 EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(invalidate_buffers);
diff -u --recursive --new-file v2.1.45/linux/net/appletalk/sysctl_net_atalk.c linux/net/appletalk/sysctl_net_atalk.c
--- v2.1.45/linux/net/appletalk/sysctl_net_atalk.c	Thu Jul 17 10:06:09 1997
+++ linux/net/appletalk/sysctl_net_atalk.c	Fri Jul 18 16:10:12 1997
@@ -6,6 +6,7 @@
  * Dynamic registration, added aarp entries. (5/30/97 Chris Horn)
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 
diff -u --recursive --new-file v2.1.45/linux/net/socket.c linux/net/socket.c
--- v2.1.45/linux/net/socket.c	Thu Jul 17 10:06:09 1997
+++ linux/net/socket.c	Thu Jul 17 15:56:33 1997
@@ -227,7 +227,6 @@
 		file->f_op = &socket_file_ops;
 		file->f_mode = 3;
 		file->f_flags = O_RDWR;
-		file->f_dentry = d_alloc_root(inode, NULL);
 		file->f_pos = 0;
 	}
 	return fd;
