]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.37 2.1.37
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:15 +0000 (15:13 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:15 +0000 (15:13 -0500)
42 files changed:
CREDITS
Documentation/Changes
Documentation/locks.txt
arch/i386/defconfig
arch/i386/kernel/ptrace.c
arch/i386/kernel/setup.c
arch/i386/kernel/smp.c
arch/i386/lib/semaphore.S
arch/i386/mm/fault.c
drivers/block/ide-floppy.c
drivers/block/ide-tape.c
drivers/char/keyb_m68k.c
drivers/isdn/hisax/isdnl1.c
drivers/isdn/isdn_net.c
drivers/sbus/char/sunkbd.c
drivers/sbus/char/sunserial.c
drivers/scsi/53c7,8xx.c
drivers/scsi/53c7,8xx.h
drivers/scsi/ChangeLog.ncr53c8xx
drivers/scsi/README.ncr53c8xx
drivers/scsi/ide-scsi.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/ncr53c8xx.h
drivers/scsi/scsi_proc.c
drivers/scsi/seagate.c
drivers/scsi/seagate.h
fs/affs/bitmap.c
fs/binfmt_elf.c
fs/isofs/inode.c
fs/locks.c
fs/nfs/write.c
fs/proc/array.c
fs/proc/mem.c
include/asm-alpha/spinlock.h
include/asm-i386/hardirq.h
include/asm-i386/semaphore.h
include/asm-i386/spinlock.h
include/linux/mm.h
kernel/softirq.c
mm/kmalloc.c
mm/memory.c
mm/page_alloc.c

diff --git a/CREDITS b/CREDITS
index d94810c40d832daa0e4c2fc6fa803ad5cb3605b9..493a6a9daced8e3d25567585f087f8e23b991a32 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -149,12 +149,8 @@ S: 91452 Wilhermsdorf
 S: Germany
 
 N: Bill Bogstad
-E: bogstad@cs.jhu.edu
-D: Wrote /proc/self patch
-S: Johns Hopkins University
-S: Computer Science Department
-S: Baltimore, Maryland 21218
-S: USA
+E: bogstad@pobox.com
+D: wrote /proc/self hack, minor samba & dosemu patches
 
 N: Axel Boldt
 E: boldt@math.ucsb.edu
@@ -468,7 +464,7 @@ S: Carnegie, Pennsylvania 15106-4304
 S: USA
 
 N: Philip Gladstone
-E: philipg@onsett.com
+E: philip@raptor.com
 D: Kernel / timekeeping stuff
 
 N: Michael A. Griffith
index 612fb76b1cdc648763605ab708b8f012ebba5684..0b840fee610ff4f79647e53cd4662ede58e8b597 100644 (file)
@@ -29,7 +29,7 @@ English-language HTML version.
    Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
 needs.
 
-Last updated: April 24, 1997.
+Last updated: May 12, 1997.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Minimal Requirements
@@ -40,13 +40,13 @@ encountered a bug!
 
 - Kernel modules        modutils-2.1.34
 - Gnu C                 2.7.2.1
-- Binutils              2.7.0.9
+- Binutils              2.8.0.3
 - Linux C Library       5.4.23
 - Dynamic Linker (ld.so) 1.8.5
 - Linux C++ Library     2.7.2.1
 - Procps                1.01
 - Mount                  2.6g
-- Net-tools              1.32-alpha
+- Net-tools              1.41
 - Loadlin                1.6a
 - Sh-utils               1.16
 - Autofs                 0.3.0
@@ -131,6 +131,9 @@ presence.
    To run bootpd, you'll need to issue the following command:   echo 1
 >/proc/sys/net/ipv4/ip_boot_agent
 
+   For support for new features like IPv6, upgrade to the latest
+net-tools.
+
 Mount and network file systems
 ==============================
 
@@ -179,8 +182,7 @@ How to know the version of the installed programs
 *************************************************
 
    There are some simple methods useful to know the version of the
-installed programs and libraries.  The SysVinit version display
-requires that you be logged in as root.
+installed programs and libraries.
 
 Binutils: ld -v
 Gnu C: gcc -v or gcc --version
@@ -190,6 +192,7 @@ Libc: ls -l /lib/libc.so.*
 Libc++: ls -l /usr/lib/libg++.so.*
 Modutils: insmod -V
 Mount: mount --version
+Net-tools:  hostname -V
 Procps: ps --version
 RPM:  rpm --version
 Sh-utils:  expr --v
@@ -200,12 +203,12 @@ Where to get the files
 Binutils
 ========
 
-The 2.7.0.9 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.7.0.9.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.7.0.9.bin.tar.gz
+The 2.8.0.3 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.0.3.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.0.3.bin.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.7.0.9
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.7.0.9
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.0.3
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.0.3
 
 Gnu C
 =====
@@ -311,6 +314,13 @@ The 0.4.21 release:
 ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
 ftp://linux.nrao.edu/pub/people/okir/linux-nfs-0.4.21.tar.gz
 
+Net-tools
+=========
+
+The 0.41 release:
+ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz
+ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz
+
 Other Info
 ==========
 
index ea91be8a2fa59955f2acbdca931228f0bc919398..3911417b2fb1e32e4e2cd16b64fefd8b38bb3706 100644 (file)
@@ -2,42 +2,30 @@
 
                Andy Walker <andy@lysaker.kvaerner.no>
 
-                           21 Sep 1996
+                           12 May 1997
 
 
 1. What's New?
 --------------
 
-1.1 Flock Emulation Warnings
-----------------------------
-Many people will have noticed the ugly messages that the file locking
-code started generating with the release of kernel version 1.3.95. The
-messages look something like this:
+1.1 Broken Flock Emulation
+--------------------------
 
-    fcntl_setlk() called by process XX with broken flock() emulation
+The old flock(2) emulation in the kernel was swapped for proper BSD
+compatible flock(2) support in the 1.3.x series of kernels. With the
+release of the 2.1.x kernel series, support for the old emulation has
+been totally removed, so that we don't need to carry this baggage
+forever.
 
-This is a warning for people using older C libraries that those libraries
-are still calling the pre 1.3.x flock() emulation routines, instead of
-the real flock() system call. The old routines are quite badly broken,
-especially with respect to parent-child lock sharing, and can give bad
-results if, for example, sendmail attempts to use them.
+This should not cause problems for anybody, since everybody using a
+2.1.x kernel should have updated their C library to a suitable version
+anyway (see the file "linux/Documentation/Changes".)
 
-Fixed versions of the C libraries have been on public release for many
-months. The latest versions at the time of writing are 5.3.12 (released)
-or 5.4.6 (testing) for ELF. There is also a 4.7.6 release for people
-using a.out systems.
+1.2 Allow Mixed Locks Again
+---------------------------
 
-With the release of Linux 2.0 Linus decided to be lenient on the
-stragglers and changed the warning message so that the kernel will only
-complain once and then shut up. That should make life more bearable even
-for people who, for some reason, don't want to upgrade their libraries.
-
-
-1.2 Disallow Mixed Locks
-------------------------
-
-1.2.1 Sendmail Problems
----------------------
+1.2.1 Typical Problems - Sendmail
+---------------------------------
 Because sendmail was unable to use the old flock() emulation, many sendmail
 installations use fcntl() instead of flock(). This is true of Slackware 3.0
 for example. This gave rise to some other subtle problems if sendmail was
@@ -50,23 +38,17 @@ to lock solid with deadlocked processes.
 
 1.2.2 The Solution
 ------------------
-I have chosen the rather cruel solution of disallowing mixed locking styles
-on a given file at a given time. Attempts to lock a file with flock() when
-fcntl() locks exist, or vice versa, return with an error status of EBUSY.
-This seemed to be the only way to avoid all possible deadlock conditions,
-as flock() locks do not strictly have one owner process and so can't be
-checked for deadlocking in the usual manner.
-
-The process that created a lock with flock() might have forked multiple
-children and exited. Previously the parent process would have been marked
-as the owner of the lock, but deadlocks could just have easily occurred in
-one or more of the children, which we would not have been able to identify
-and avoid.
-
-Some programs may break (again, groan). In particular the aforementioned
-sendmail may have problems running in 'newaliases' mode. It will no longer
-deadlock though. Recompile sendmail to use flock() and your troubles will
-be over.
+The solution I have chosen, after much experimentation and discussion,
+is to make flock() and fcntl() locks oblivious to each other. Both can
+exists, and neither will have any effect on the other.
+
+I wanted the two lock styles to be cooperative, but there were so many
+race and deadlock conditions that the current solution was the only
+practical one. It puts us in the same position as, for example, SunOS
+4.1.x and serveral other commercial Unices. The only OS's that support
+cooperative flock()/fcntl() are those that emulate flock() using
+fcntl(), with all the problems that implies.
+
 
 1.3 Mandatory Locking As A Mount Option
 ---------------------------------------
index e5b5d9f84cac8949039ff643b456dc0f59fc18c8..a27b6ebce4cf37008ae9cf799ba5e2a7c14ca7c0 100644 (file)
@@ -141,6 +141,7 @@ CONFIG_SCSI_OMIT_FLASHPOINT=y
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
index a446304a20d5bbc4648ffc44eff852383e824bc2..208481483cb48a342e05304ae37ab5d9d7038640 100644 (file)
@@ -83,7 +83,7 @@ static unsigned long get_long(struct task_struct * tsk,
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
        if (pgd_none(*pgdir)) {
-               do_no_page(tsk, vma, addr, 0);
+               handle_mm_fault(vma, addr, 0);
                goto repeat;
        }
        if (pgd_bad(*pgdir)) {
@@ -93,7 +93,7 @@ repeat:
        }
        pgmiddle = pmd_offset(pgdir, addr);
        if (pmd_none(*pgmiddle)) {
-               do_no_page(tsk, vma, addr, 0);
+               handle_mm_fault(vma, addr, 0);
                goto repeat;
        }
        if (pmd_bad(*pgmiddle)) {
@@ -103,7 +103,7 @@ repeat:
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               do_no_page(tsk, vma, addr, 0);
+               handle_mm_fault(vma, addr, 0);
                goto repeat;
        }
        page = pte_page(*pgtable);
@@ -134,7 +134,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
        if (!pgd_present(*pgdir)) {
-               do_no_page(tsk, vma, addr, 1);
+               handle_mm_fault(vma, addr, 1);
                goto repeat;
        }
        if (pgd_bad(*pgdir)) {
@@ -144,7 +144,7 @@ repeat:
        }
        pgmiddle = pmd_offset(pgdir, addr);
        if (pmd_none(*pgmiddle)) {
-               do_no_page(tsk, vma, addr, 1);
+               handle_mm_fault(vma, addr, 1);
                goto repeat;
        }
        if (pmd_bad(*pgmiddle)) {
@@ -154,12 +154,12 @@ repeat:
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               do_no_page(tsk, vma, addr, 1);
+               handle_mm_fault(vma, addr, 1);
                goto repeat;
        }
        page = pte_page(*pgtable);
        if (!pte_write(*pgtable)) {
-               do_wp_page(tsk, vma, addr, 1);
+               handle_mm_fault(vma, addr, 1);
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
index ec59547719c56db821c2d2833baa2afac46c66d9..a46b0089753f515605b5d3b5150ff4c20d24a731 100644 (file)
@@ -247,7 +247,7 @@ static const char * i586model(unsigned int nr)
 static const char * i686model(unsigned int nr)
 {
        static const char *model[] = {
-               "PPro A-step", "Pentium Pro"
+               "PPro A-step", "Pentium Pro", "2", "Pentium II"
        };
        if (nr < sizeof(model)/sizeof(char *))
                return model[nr];
@@ -279,9 +279,10 @@ static const char * getmodel(int x86, int model)
 int get_cpuinfo(char * buffer)
 {
         int i, len = 0;
+       int sep_bug;
         static const char *x86_cap_flags[] = {
                 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-                "cx8", "apic", "10", "11", "mtrr", "pge", "mca", "cmov",
+                "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
                 "16", "17", "18", "19", "20", "21", "22", "mmx",
                 "24", "25", "26", "27", "28", "29", "30", "31"
         };
@@ -321,10 +322,16 @@ int get_cpuinfo(char * buffer)
                         else
                                 len += sprintf(buffer+len, 
                                                "stepping\t: unknown\n");
+
+                       sep_bug = CD(have_cpuid) &&
+                                 (CD(x86_capability) & 0x800) &&
+                                 CD(x86_model) < 3 &&
+                                 CD(x86_mask) < 3;
         
                         len += sprintf(buffer+len,
                                        "fdiv_bug\t: %s\n"
                                        "hlt_bug\t\t: %s\n"
+                                      "sep_bug\t\t: %s\n"
                                        "fpu\t\t: %s\n"
                                        "fpu_exception\t: %s\n"
                                        "cpuid\t\t: %s\n"
@@ -332,6 +339,7 @@ int get_cpuinfo(char * buffer)
                                        "flags\t\t:",
                                        CD(fdiv_bug) ? "yes" : "no",
                                        CD(hlt_works_ok) ? "no" : "yes",
+                                      sep_bug ? "yes" : "no",
                                        CD(hard_math) ? "yes" : "no",
                                        (CD(hard_math) && ignore_irq13)
                                          ? "yes" : "no",
index 2869ecda575745318eb9d5f86038c090e0f00e56..1dc615501b51099deec8253252ec19619bd5f627 100644 (file)
@@ -1250,10 +1250,13 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
 void smp_flush_tlb(void)
 {
        unsigned long flags;
+
+#if 0
        if(smp_activated && smp_processor_id()!=active_kernel_processor) {
                printk("CPU #%d:Attempted flush tlb IPI when not AKP(=%d)\n",smp_processor_id(),active_kernel_processor);
                *(char *)0=0;
        }
+#endif
 /*     printk("SMI-");*/
 
        /*
index ff2443c40daf296b368036d835f3caf5267865f3..bb5650317740f3249e8343291d06df50db540099 100644 (file)
  * there is contention on the semaphore.
  */
 ENTRY(__down_failed)
-       pushl %eax      /* return address */
+       pushl %eax      /* save %eax */
        pushl %edx      /* save %edx */
        pushl %ecx      /* save %ecx (and argument) */
        call SYMBOL_NAME(__down)
        popl %ecx       /* restore %ecx (count on __down not changing it) */
        popl %edx       /* restore %edx */
+       popl %eax       /* restore %eax */
        ret
 
 ENTRY(__down_failed_interruptible)
-       pushl %eax      /* return address */
+       pushl %eax      /* save %eax */
        pushl %edx      /* save %edx */
        pushl %ecx      /* save %ecx (and argument) */
        call SYMBOL_NAME(__down_interruptible)
        popl %ecx       /* restore %ecx (count on __down_interruptible not changing it) */
        popl %edx       /* restore %edx */
+       popl %eax       /* restore %eax */
        ret
 
 ENTRY(__up_wakeup)
-       pushl %eax      /* return address */
+       pushl %eax      /* save %eax */
        pushl %edx      /* save %edx */
        pushl %ecx      /* save %ecx (and argument) */
        call SYMBOL_NAME(__up)
        popl %ecx       /* restore %ecx (count on __up not changing it) */
        popl %edx       /* restore %edx */
+       popl %eax       /* restore %eax */
        ret
index e8c3b9f05188169e98b7c616c3454186b8175ccc..f22eb606f724842f4093f9e2c45264f7806b746a 100644 (file)
@@ -49,7 +49,7 @@ good_area:
        start &= PAGE_MASK;
 
        for (;;) {
-               do_wp_page(current, vma, start, 1);
+               handle_mm_fault(vma, start, 1);
                if (!size)
                        break;
                size--;
@@ -86,10 +86,6 @@ bad_area:
  */
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
-       void (*handler)(struct task_struct *,
-                       struct vm_area_struct *,
-                       unsigned long,
-                       int);
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
        struct vm_area_struct * vma;
@@ -128,10 +124,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
  */
 good_area:
        write = 0;
-       handler = do_no_page;
        switch (error_code & 3) {
                default:        /* 3: write, present */
-                       handler = do_wp_page;
 #ifdef TEST_VERIFY_AREA
                        if (regs->cs == KERNEL_CS)
                                printk("WP fault at %08lx\n", regs->eip);
@@ -148,7 +142,7 @@ good_area:
                        if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                                goto bad_area;
        }
-       handler(tsk, vma, address, write);
+       handle_mm_fault(vma, address, write);
        up(&mm->mmap_sem);
        /*
         * Did it hit the DOS screen memory VA from vm86 mode?
index d362dfab4082dee2aab63bb531729ddb2d36b1b3..5a0a603b5f284d1a6934c843886650467c7a64b5 100644 (file)
@@ -726,7 +726,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
                return;
        }
 #ifdef CONFIG_BLK_DEV_TRITON
-       if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+       if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
                printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
                printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n");
                HWIF(drive)->dmaproc(ide_dma_off, drive);
@@ -842,7 +842,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
        bcount.all=pc->request_transfer;                                /* Request to transfer the entire buffer at once */
 
 #ifdef CONFIG_BLK_DEV_TRITON
-       if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+       if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
                printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n");
                HWIF(drive)->dmaproc(ide_dma_off, drive);
        }
@@ -1182,7 +1182,7 @@ static int idefloppy_media_change (ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        
-       return clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+       return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 }
 
 /*
index 537c5dd8289419e66f029b46a284bf41366b6f11..2fc5f0b9d13dce34c17ce63b60a3d2ed924b4df8 100644 (file)
@@ -1777,7 +1777,7 @@ static void idetape_pc_intr (ide_drive_t *drive)
                return;
        }
 #ifdef CONFIG_BLK_DEV_TRITON
-       if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+       if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
                printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
                printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
                HWIF(drive)->dmaproc(ide_dma_off, drive);
@@ -1916,7 +1916,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
        bcount.all=pc->request_transfer;                                /* Request to transfer the entire buffer at once */
 
 #ifdef CONFIG_BLK_DEV_TRITON
-       if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+       if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
                printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
                HWIF(drive)->dmaproc(ide_dma_off, drive);
        }
@@ -2248,7 +2248,7 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned
        status.all = GET_STAT();
        if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
                set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
-       if (!clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+       if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
                if (postponed_rq == NULL) {
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
@@ -2506,7 +2506,7 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
        if (!idetape_pipeline_active (tape) && tape->nr_stages >= (3 * tape->max_stages) / 4)
                idetape_insert_pipeline_into_queue (drive);
 
-       if (clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))           /* Return a deferred error */
+       if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))          /* Return a deferred error */
                return -EIO;
        return blocks;
 }
@@ -3254,7 +3254,7 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
                return -ENXIO;
        tape = drive->driver_data;
 
-       if (set_bit (IDETAPE_BUSY, &tape->flags))
+       if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
                return -EBUSY;
        MOD_INC_USE_COUNT;
        idetape_create_read_position_cmd (&pc);
index 655a37ec6c2544e9f6274bfce2db79f6192f5422..952dfeeee0fd98762ee0b4740790dc2bb9c990f0 100644 (file)
@@ -216,7 +216,7 @@ void process_keycode (int keycode)
 #endif
                }
        } else
-               rep = set_bit(keycode, key_down);
+               rep = test_and_set_bit(keycode, key_down);
 
        if (raw_mode)
                return;
index cbc91e9d6f062a9303866c4c229167d4e99270d7..ebf0957b53bc5c8c602402aa394fc6046d217a31 100644 (file)
@@ -461,11 +461,11 @@ isac_bh(struct IsdnCardState *sp)
        if (!sp)
                return;
 
-       if (clear_bit(ISAC_PHCHANGE, &sp->event))
+       if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event))
                process_new_ph(sp);
-       if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
+       if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event))
                process_rcv(sp);
-       if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
+       if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event))
                process_xmt(sp);
 }
 
@@ -578,9 +578,9 @@ hscx_bh(struct HscxState *hsp)
        if (!hsp)
                return;
 
-       if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
+       if (test_and_clear_bit(HSCX_RCVBUFREADY, &hsp->event))
                hscx_process_rcv(hsp);
-       if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
+       if (test_and_clear_bit(HSCX_XMTBUFREADY, &hsp->event))
                hscx_process_xmt(hsp);
 
 }
index 5d3ab899ed82a9194cd8f29c20cbfb663c035253..b6b076360fdd93027e8a74cea0a8aa609e6888f0 100644 (file)
@@ -934,7 +934,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                return 0;
        }
        /* Avoid timer-based retransmission conflicts. */
-       if (set_bit(0, (void *) &ndev->tbusy) != 0)
+       if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0)
                printk(KERN_WARNING
                       "%s: Transmitter access conflict.\n",
                       ndev->name);
index 87fb0fea49d3d95fb22d9e818d82fd89eeb7504f..8e398f345c1707f650be136179782d6bcde7455f 100644 (file)
@@ -487,7 +487,7 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
                                add_timer (&auto_repeat_timer);
                        }
                }
-               rep = set_bit(keycode, key_down);
+               rep = test_and_set_bit(keycode, key_down);
        }
 
        if(raw_mode)
index 59b9bda8e173d1ef197d1fb43a59679e310e2f15..08fcab8ee48008f3191dac4f2dad3b2c5f44415b 100644 (file)
@@ -687,7 +687,7 @@ static void do_softint(void *private_)
        if (!tty)
                return;
 
-       if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
                if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
                    tty->ldisc.write_wakeup)
                        (tty->ldisc.write_wakeup)(tty);
index 3691108e62f5b21dc75473fb08960692fe216604..44a78b12c6a5549fdfef61adadd8ba3229adb700 100644 (file)
@@ -254,7 +254,6 @@ typedef unsigned int  u32;
 #include <linux/time.h>
 #include <linux/blk.h>
 #include <linux/init.h>
-#undef current
 
 #include "scsi.h"
 #include "hosts.h"
@@ -783,7 +782,7 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     int i, j;
-    u32 *current;
+    u32 *curr;
     for (i = 0; i < 16; ++i) {
        hostdata->request_sense[i] = 0;
        for (j = 0; j < 8; ++j) 
@@ -792,14 +791,14 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
     }
     hostdata->issue_queue = NULL;
     hostdata->running_list = hostdata->finished_queue = 
-       hostdata->current = NULL;
-    for (i = 0, current = (u32 *) hostdata->schedule; 
-       i < host->can_queue; ++i, current += 2) {
-       current[0] = hostdata->NOP_insn;
-       current[1] = 0xdeadbeef;
+       hostdata->curr = NULL;
+    for (i = 0, curr = (u32 *) hostdata->schedule; 
+       i < host->can_queue; ++i, curr += 2) {
+       curr[0] = hostdata->NOP_insn;
+       curr[1] = 0xdeadbeef;
     }
-    current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
-    current[1] = (u32) virt_to_bus (hostdata->script) +
+    curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
+    curr[1] = (u32) virt_to_bus (hostdata->script) +
        hostdata->E_wait_reselect;
     hostdata->reconnect_dsa_head = 0;
     hostdata->addr_reconnect_dsa_head = (u32) 
@@ -2104,7 +2103,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
     int left, found;
     volatile struct NCR53c7x0_cmd * linux_search;
     volatile struct NCR53c7x0_cmd * volatile *linux_prev;
-    volatile u32 *ncr_prev, *current, ncr_search;
+    volatile u32 *ncr_prev, *curr, ncr_search;
 
 #if 0
     printk ("scsi%d: abnormal finished\n", host->host_no);
@@ -2120,13 +2119,13 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
      */
 
 
-    for (found = 0, left = host->can_queue, current = hostdata->schedule; 
-       left > 0; --left, current += 2)
+    for (found = 0, left = host->can_queue, curr = hostdata->schedule; 
+       left > 0; --left, curr += 2)
     {
-       if (issue_to_cmd (host, hostdata, (u32 *) current) == cmd) 
+       if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd) 
        {
-           current[0] = hostdata->NOP_insn;
-           current[1] = 0xdeadbeef;
+           curr[0] = hostdata->NOP_insn;
+           curr[1] = 0xdeadbeef;
            ++found;
            break;
        }
@@ -3964,7 +3963,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
     Scsi_Cmnd *tmp = cmd->cmd;
     unsigned long flags;
     /* dsa start is negative, so subtraction is used */
-    volatile u32 *current;
+    volatile u32 *curr;
 
     int i;
     NCR53c7x0_local_setup(host);
@@ -3991,9 +3990,9 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
        return;
     }
 
-    for (i = host->can_queue, current = hostdata->schedule; 
-       i > 0  && current[0] != hostdata->NOP_insn;
-       --i, current += 2 /* JUMP instructions are two words */);
+    for (i = host->can_queue, curr = hostdata->schedule; 
+       i > 0  && curr[0] != hostdata->NOP_insn;
+       --i, curr += 2 /* JUMP instructions are two words */);
 
     if (i > 0) {
        ++hostdata->busy[tmp->target][tmp->lun];
@@ -4002,13 +4001,13 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
 
        /* Restore this instruction to a NOP once the command starts */
        cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) / 
-           sizeof(u32)] = (u32) virt_to_bus ((void *)current);
+           sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
        /* Replace the current jump operand.  */
-       current[1] =
+       curr[1] =
            virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
            hostdata->E_dsa_code_template;
        /* Replace the NOP instruction with a JUMP */
-       current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+       curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
            DBC_TCI_TRUE;
     }  else {
        printk ("scsi%d: no free slot\n", host->host_no);
@@ -4510,8 +4509,8 @@ restart:
 
                    /*
                     * NCR53c700 and NCR53c700-66 change the current SCSI
-                    * process, hostdata->current, in the Linux driver so
-                    * cmd = hostdata->current.
+                    * process, hostdata->curr, in the Linux driver so
+                    * cmd = hostdata->curr.
                     *
                     * With other chips, we must look through the commands
                     * executing and find the command structure which 
@@ -4519,7 +4518,7 @@ restart:
                     */
 
                    if (hostdata->options & OPTION_700) {
-                       cmd = (struct NCR53c7x0_cmd *) hostdata->current;
+                       cmd = (struct NCR53c7x0_cmd *) hostdata->curr;
                    } else {
                        dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
                        for (cmd = (struct NCR53c7x0_cmd *) 
@@ -5872,7 +5871,7 @@ print_queues (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     u32 *dsa, *next_dsa;
-    volatile u32 *current;
+    volatile u32 *curr;
     int left;
     Scsi_Cmnd *cmd, *next_cmd;
     unsigned long flags;
@@ -5914,11 +5913,11 @@ print_queues (struct Scsi_Host *host) {
      */
 
     printk ("scsi%d : schedule dsa array :\n", host->host_no);
-    for (left = host->can_queue, current = hostdata->schedule;
-           left > 0; current += 2, --left)
-       if (current[0] != hostdata->NOP_insn) 
+    for (left = host->can_queue, curr = hostdata->schedule;
+           left > 0; curr += 2, --left)
+       if (curr[0] != hostdata->NOP_insn) 
 /* FIXME : convert pointer to dsa_begin to pointer to dsa. */
-           print_dsa (host, bus_to_virt (current[1] - 
+           print_dsa (host, bus_to_virt (curr[1] - 
                (hostdata->E_dsa_code_begin - 
                hostdata->E_dsa_code_template)), "");
     printk ("scsi%d : end schedule dsa array\n", host->host_no);
@@ -6108,7 +6107,7 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
        host->hostdata;
     struct NCR53c7x0_cmd *c;
     int i;
-    u32 *current;
+    u32 *curr;
     Scsi_Cmnd *list = NULL, *tmp;
     for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c; 
        c = (struct NCR53c7x0_cmd *) c->next)  {
@@ -6129,12 +6128,12 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
     }
 
     if (free) { 
-       for (i = 0, current = (u32 *) hostdata->schedule; 
-           i < host->can_queue; ++i, current += 2) {
-           current[0] = hostdata->NOP_insn;
-           current[1] = 0xdeadbeef;
+       for (i = 0, curr = (u32 *) hostdata->schedule; 
+           i < host->can_queue; ++i, curr += 2) {
+           curr[0] = hostdata->NOP_insn;
+           curr[1] = 0xdeadbeef;
        }
-       hostdata->current = NULL;
+       hostdata->curr = NULL;
     }
 
     if (issue) {
index 80fbad3b51e00ec4a36af2e920ef91fbc8bc38f9..cfddfa6815d44740636b804bb751809b523e41ae 100644 (file)
@@ -1394,7 +1394,7 @@ struct NCR53c7x0_hostdata {
                                                /* commands running, maintained
                                                   by Linux driver */
 
-    volatile struct NCR53c7x0_cmd *current;    /* currently connected 
+    volatile struct NCR53c7x0_cmd *curr;       /* currently connected 
                                                   nexus, ONLY valid for
                                                   NCR53c700/NCR53c700-66
                                                 */
index ccf31d453879ecfc2b41cb0c374523eaf047cfde..edc8f395c08a16b07b21ca5abadbccf7ba4dd13a 100644 (file)
@@ -1,3 +1,75 @@
+Sun May 11 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+       * revision 2.1b
+       - Cosmetic changes.
+       - Some heavy testings under pre-linux-2.1.37-6
+
+Sun May 4 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+       * revision 2.1a
+       - PFEN wrongly used for PREFETCH feature bit testing.
+         Changed to _F_PFEN.
+       - 2 SCR_COPY that need NO FLUSH bit to be removed had been missed 
+         in tp->getscr[] script (loads SXFER and SCNTL3 on reselection).
+
+Sat May 3 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+       * revision 2.1
+       - Use the NO FLUSH option for MOVE MEMORY (COPY) each time it is 
+         possible. More than 100 COPY with NO FLUSH and 6 with FLUSH for  
+         my configuration (max queued command / device = 8).
+         This option bit is removed from the script instance for chips 
+         that donnot support prefetching.
+       - Rewrite the ncr_exception() routine more simple (I think) and 
+         remove useless code.
+       - Change the data_in and data_out script management.
+         Use the bottom part of these scripts instead of the beginning.
+         That avoids to zero the scatter/gather array when a command is 
+         queued (1k) and to deal with some weird IID on MOVE 0 bytes when 
+         a target wants to transfer more bytes than expected.
+       - Misc. improvements in the init code.
+       - Remove IOMAPPED/MMIO automatic switching option.
+         Was useless and reported not reliable.
+       - Fix a double read of DSTAT and remove DFE testing in the 
+         Phase mismatch service routine.
+       - Etc...
+
+Fri Apr 26 20:00 1997 Gerard Roudier (groudier@club-internet.fr)
+       * revision 2.0a
+       - Add support if the Diamond FirePort 40 (SYM53C875J chip)
+
+Mon Apr 22 22:00 1997 Gerard Roudier (groudier@club-internet.fr)
+       * revision 2.0
+       - incorporate __initdata and __initfunc directives in order to 
+         allow 'init' to free unused memory after driver initialisations.
+         Patch sent by Roberto Fichera.
+       - rewrite the init code of the driver. Now a feature descriptor 
+         is used for each real chip types. The code is a lot more clean,
+         since the driver uses device and revision ids only in the 
+         detection procedure.
+       - add 'pcifix' boot command line. This command allows to fix up PCI 
+         config space for new chips which support features based on the 
+         cache line size and 'write and invalidate'.
+       - incorporate in the driver, the code used for error recovery  
+         testing. This code is normally not compiled; have to define 
+         SCSI_NCR_DEBUG_ERROR_RECOVERY in order to compile it.
+       - take into account actual SCSI bus mode for 53C895 LVD/SE controller.
+         In single ended mode only fast20 is supported.
+          (Just to not be late since such controllers are not yet available)
+          
+
+Sat Apr 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr)
+       * revision 1.18f
+       - fix an old bug included in the initial port (version 0.0).
+         The driver allocated 10 bytes of static data and uses 12 bytes.
+         No danger, since data are generally aligned on 4 bytes boundary 
+         and so byte 10 and 11 are free (I hope ...)
+
+Wed Apr 16 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+       * revision 1.18e
+       - reset all when an unexpected data cycle is detected while 
+         disconnecting.
+       - make changes to abort() ans reset() functions according to 
+         Leonard's documentation.
+       - small fix in some message for hard errors.
+
 Sat Apr 5  13:00 1997 Gerard Roudier (groudier@club-internet.fr)
        * revision 1.18d
        - Probe NCR pci device ids in reverse order if asked by user from 
index 53b690f7cdce27302a5399ff46787c5ce1d72451..d93492a83dde783d6e05592e4e45b4971895f810 100644 (file)
@@ -1,10 +1,10 @@
-The linux NCR53C8XX driver README file
+The Linux NCR53C8XX driver README file
 
 Written by Gerard Roudier <groudier@club-internet.fr>
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-6 April 1997
+9 May 1997
 ===============================================================================
 
 1.  Introduction
@@ -22,6 +22,7 @@ Written by Gerard Roudier <groudier@club-internet.fr>
       8.5  Set debug mode
       8.6  Clear profile counters
       8.7  Set flag (no_sync)
+      8.8  Debug error recovery
 9.  Configuration parameters
 10. Boot setup commands
       10.1 Syntax
@@ -203,7 +204,6 @@ General information:
   IO port address 0x6000, IRQ number 10
   Using memory mapped IO at virtual address 0x282c000
   Synchronous transfer period 25, max commands per lun 4
-
 Profiling information:
   num_trans    = 18014
   num_kbytes   = 671314
@@ -390,6 +390,57 @@ Available commands:
     - setflag all
       will allow disconnection for all devices on the SCSI bus.
 
+
+8.8 Debug error recovery
+
+    debug_error_recovery <error to trigger>
+
+    Available error type to trigger:
+        sge:     SCSI gross error
+        abort:   abort command from the middle-level driver
+        reset:   reset command from the middle-level driver
+        parity:  scsi parity detected in DATA IN phase
+        none:    restore driver normal behaviour
+
+    The code corresponding to this feature is normally not compiled.
+    Its purpose is driver testing only. In order to compile the code 
+    that allows to trigger error recovery you must define at compile time 
+    SCSI_NCR_DEBUG_ERROR_RECOVERY.
+    If you have compiled the driver with this option, nothing will happen 
+    as long as you donnot use the control command 'debug_error_recovery' 
+    with sge, abort, reset or parity as argument.
+    If you select an error type, it will be triggered by the driver every 
+    30 seconds.
+
+8.9 PCI configuration fix-up
+
+    pcifix <option bits>
+
+    Available option bits:
+        0x1:     Set PCI cache-line size register if not set.
+        0x2:     Set write and invalidate bit in PCI command register.
+
+    Use 'pcifix:3' in order to allow the driver to fix both PCI features.
+
+    These options only apply to new SYMBIOS chips 810A, 825A, 860 and 875 
+    and are only supported for Pentium and 486 class processors.
+    Recent SYMBIOS 53C8XX scsi processors are able to use PCI read multiple 
+    and PCI write and invalidate commands. These features require the 
+    cache line size register to be properly set in the PCI configuration 
+    space of the chips. On the other hand, chips will use PCI write and 
+    invalidate commands only if the corresponding bit is set to 1 in the 
+    PCI command register.
+
+    Not all PCI bioses set the PCI cache line register and the PCI write and 
+    invalidate bit in the PCI configuration space of 53C8XX chips.
+    Optimized PCI accesses may be broken for some PCI/memory controllers or 
+    make problems with some PCI boards.
+
+    This fix-up works flawlessly on my system.
+    (MB Triton HX / 53C875 / 53C810A)
+    I use these options at my own risks as you will do if you decide to 
+    use them too.
+
 9. Configuration parameters
 
 If the firmware of all your devices is perfect enough, all the
@@ -736,9 +787,9 @@ Driver and common files:
 
 You must untar the distribution with the following command:
 
-       tar zxvf ncrBsd2Linux-1.18d-src.tar.gz
+       tar zxvf ncrBsd2Linux-2.1b-src.tar.gz
 
-The sub-directory ncr53c8xx-1.18d will be created. Change to this directory.
+The sub-directory ncr53c8xx-2.1b will be created. Change to this directory.
 
 
 12.2 Installation procedure
index 7cbb86070eb67f300a5c7c3cc0e13eccef6f79d6..efd6568f1648f79e8f69926a79a6ff019d4aa13c 100644 (file)
@@ -242,7 +242,7 @@ static void idescsi_pc_intr (ide_drive_t *drive)
        printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
 #endif /* IDESCSI_DEBUG_LOG */
 
-       if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+       if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 #if IDESCSI_DEBUG_LOG
                printk ("ide-scsi: %s: DMA complete\n", drive->name);
 #endif /* IDESCSI_DEBUG_LOG */
index f82bb2aa4817a3568ecad69ef3b111626e814e24..2da1ea5e428e17b4329f01fa007454cd059afa9d 100644 (file)
@@ -40,7 +40,7 @@
 */
 
 /*
-**     16 April 1997, version 1.18e
+**     9 May 1997, version 2.1b
 **
 **     Supported SCSI-II features:
 **         Synchronous negotiation
@@ -56,7 +56,7 @@
 **             53C820          (Wide, NCR BIOS in flash bios required)
 **             53C825          (Wide, ~53C820 with on board rom BIOS)
 **             53C860          (Narrow fast 20, BIOS required)
-**             53C875          (Wide fast 40 with on board rom BIOS)
+**             53C875          (Wide fast 20 with on board rom BIOS)
 **             53C895          (Ultra2 80 MB/s with on board rom BIOS)
 **
 **     Other features:
@@ -65,7 +65,6 @@
 **             Shared IRQ (since linux-1.3.72)
 */
 
-#define SCSI_NCR_DEBUG
 #define SCSI_NCR_DEBUG_FLAGS   (0)             
 
 #define NCR_DATE "pl24 96/12/14"
 #include "../block/blk.h"
 #endif
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
+#include <linux/init.h>
+#else
+#ifndef        __initdata
+#define        __initdata
+#endif
+#ifndef        __initfunc
+#define        __initfunc(__arginit) __arginit
+#endif
+#endif
+
 #include "scsi.h"
 #include "hosts.h"
 #include "constants.h"
@@ -132,15 +142,6 @@ typedef u32 u_int32;
 **==========================================================
 */
 
-/*
-**     Proc info and user command support
-*/
-
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-#define SCSI_NCR_PROFILE
-#define SCSI_NCR_USER_COMMAND
-#endif
-
 /*
 **    SCSI address of this device.
 **    The boot routines should have set it.
@@ -212,8 +213,6 @@ typedef u32 u_int32;
 
 #if defined(SCSI_NCR_IOMAPPED)
 #define NCR_IOMAPPED
-#else
-#define NCR_MEMORYMAPPED
 #endif
 
 /*
@@ -292,6 +291,7 @@ static inline vm_offset_t remap_pci_mem(u_long base, u_long size)
 
        return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL);
 }
+
 static inline void unmap_pci_mem(vm_offset_t vaddr, u_long size)
 {
        if (vaddr)
@@ -422,6 +422,8 @@ static int guess_xfer_direction(int opcode);
 **     Head of list of NCR boards
 **
 **     Host is retrieved by its irq level.
+**     If interrupts are shared, the internal host control block 
+**     address (struct ncb) is used as device id.
 */
 
 static struct Scsi_Host                *first_host     = NULL;
@@ -470,6 +472,7 @@ struct ncr_driver_setup {
        unsigned ultra_scsi     : 2;
        unsigned force_sync_nego: 1;
        unsigned reverse_probe: 1;
+       unsigned pci_fix_up: 2;
        u_char  verbose;
        u_char  default_tags;
        u_short default_sync;
@@ -482,8 +485,13 @@ struct ncr_driver_setup {
        u_char  irqm;
 };
 
-static struct ncr_driver_setup driver_setup    = SCSI_NCR_DRIVER_SETUP;
-static struct ncr_driver_setup driver_safe_setup= SCSI_NCR_DRIVER_SAFE_SETUP;
+static struct ncr_driver_setup
+       driver_setup                    = SCSI_NCR_DRIVER_SETUP;
+
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+       driver_safe_setup __initdata    = SCSI_NCR_DRIVER_SAFE_SETUP;
+#endif
 
 /*
 **     Other Linux definitions
@@ -531,7 +539,7 @@ static void ncr53c8xx_timeout(unsigned long np);
 **    Can be changed at runtime too.
 */
 
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
        #define DEBUG_FLAGS ncr_debug
 #else
        #define DEBUG_FLAGS     SCSI_NCR_DEBUG_FLAGS
@@ -569,37 +577,37 @@ static void ncr53c8xx_timeout(unsigned long np);
 */
 
 /*
-**     IO mapped input / ouput
+**     IO mapped only input / ouput
 */
 
-#define        IOM_INB(r)         inb (np->port + offsetof(struct ncr_reg, r))
-#define        IOM_INB_OFF(o)     inb (np->port + (o))
-#define        IOM_INW(r)         inw (np->port + offsetof(struct ncr_reg, r))
-#define        IOM_INL(r)         inl (np->port + offsetof(struct ncr_reg, r))
-#define        IOM_INL_OFF(o)     inl (np->port + (o))
+#define        IOM_INB(r)              inb (np->port + offsetof(struct ncr_reg, r))
+#define        IOM_INB_OFF(o)          inb (np->port + (o))
+#define        IOM_INW(r)              inw (np->port + offsetof(struct ncr_reg, r))
+#define        IOM_INL(r)              inl (np->port + offsetof(struct ncr_reg, r))
+#define        IOM_INL_OFF(o)          inl (np->port + (o))
 
-#define        IOM_OUTB(r, val)     outb ((val), np->port+offsetof(struct ncr_reg,r))
-#define        IOM_OUTW(r, val)     outw ((val), np->port+offsetof(struct ncr_reg,r))
-#define        IOM_OUTL(r, val)     outl ((val), np->port+offsetof(struct ncr_reg,r))
-#define        IOM_OUTL_OFF(o, val) outl ((val), np->port + (o))
+#define        IOM_OUTB(r, val)        outb ((val), np->port+offsetof(struct ncr_reg,r))
+#define        IOM_OUTW(r, val)        outw ((val), np->port+offsetof(struct ncr_reg,r))
+#define        IOM_OUTL(r, val)        outl ((val), np->port+offsetof(struct ncr_reg,r))
+#define        IOM_OUTL_OFF(o, val)    outl ((val), np->port + (o))
 
 /*
 **     MEMORY mapped IO input / output
 */
 
-#define MMIO_INB(r)        readb(&np->reg->r)
-#define MMIO_INB_OFF(o)    readb((char *)np->reg + (o))
-#define MMIO_INW(r)        readw(&np->reg->r)
-#define MMIO_INL(r)        readl(&np->reg->r)
-#define MMIO_INL_OFF(o)    readl((char *)np->reg + (o))
+#define MMIO_INB(r)            readb(&np->reg->r)
+#define MMIO_INB_OFF(o)                readb((char *)np->reg + (o))
+#define MMIO_INW(r)            readw(&np->reg->r)
+#define MMIO_INL(r)            readl(&np->reg->r)
+#define MMIO_INL_OFF(o)                readl((char *)np->reg + (o))
 
-#define MMIO_OUTB(r, val)     writeb((val), &np->reg->r)
-#define MMIO_OUTW(r, val)     writew((val), &np->reg->r)
-#define MMIO_OUTL(r, val)     writel((val), &np->reg->r)
-#define MMIO_OUTL_OFF(o, val) writel((val), (char *)np->reg + (o))
+#define MMIO_OUTB(r, val)      writeb((val), &np->reg->r)
+#define MMIO_OUTW(r, val)      writew((val), &np->reg->r)
+#define MMIO_OUTL(r, val)      writel((val), &np->reg->r)
+#define MMIO_OUTL_OFF(o, val)  writel((val), (char *)np->reg + (o))
 
 /*
-**     IO mapped only input / output
+**     IO mapped input / output
 */
 
 #if defined(NCR_IOMAPPED)
@@ -619,7 +627,7 @@ static void ncr53c8xx_timeout(unsigned long np);
 **     MEMORY mapped only input / output
 */
 
-#elif defined(NCR_MEMORYMAPPED)
+#else
 
 #define INB(r)             MMIO_INB(r)
 #define INB_OFF(o)         MMIO_INB_OFF(o)
@@ -632,23 +640,6 @@ static void ncr53c8xx_timeout(unsigned long np);
 #define OUTL(r, val)       MMIO_OUTL(r, val)
 #define OUTL_OFF(o, val)   MMIO_OUTL_OFF(o, val)
 
-/*
-**     IO mapped or MEMORY mapped 
-*/
-
-#else
-
-#define        INB(r)             (np->reg ? MMIO_INB(r) : IOM_INB(r))
-#define        INB_OFF(o)         (np->reg ? MMIO_INB_OFF(o) : IOM_INB_OFF(o))
-#define        INW(r)             (np->reg ? MMIO_INW(r) : IOM_INW(r))
-#define        INL(r)             (np->reg ? MMIO_INL(r) : IOM_INL(r))
-#define        INL_OFF(o)         (np->reg ? MMIO_INL_OFF(o) : IOM_INL_OFF(o))
-
-#define        OUTB(r, val)       (np->reg ? MMIO_OUTB(r, val) : IOM_OUTB(r, val))
-#define        OUTW(r, val)       (np->reg ? MMIO_OUTW(r, val) : IOM_OUTW(r, val))
-#define        OUTL(r, val)       (np->reg ? MMIO_OUTL(r, val) : IOM_OUTL(r, val))
-#define        OUTL_OFF(o, val)   (np->reg ? MMIO_OUTL_OFF(o, val) : IOM_OUTL_OFF(o, val))
-
 #endif
 
 /*
@@ -657,6 +648,10 @@ static void ncr53c8xx_timeout(unsigned long np);
 
 #define OUTONB(r, m)   OUTB(r, INB(r) | (m))
 #define OUTOFFB(r, m)  OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m)   OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m)  OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m)   OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m)  OUTL(r, INL(r) & ~(m))
 
 /*==========================================================
 **
@@ -700,7 +695,8 @@ static void ncr53c8xx_timeout(unsigned long np);
 #define        SIR_IGN_RESIDUE         (11)
 #define        SIR_MISSING_SAVE        (12)
 #define        SIR_DATA_IO_IS_OUT      (13)
-#define        SIR_MAX                 (13)
+#define        SIR_DATA_IO_IS_IN       (14)
+#define        SIR_MAX                 (14)
 
 /*==========================================================
 **
@@ -798,6 +794,10 @@ struct     usrcmd {
 #define UC_SETFLAG     15
 #define UC_CLEARPROF   16
 
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+#define UC_DEBUG_ERROR_RECOVERY 17
+#endif
+
 #define        UF_TRACE        (0x01)
 #define        UF_NODISC       (0x02)
 
@@ -813,7 +813,6 @@ struct tstamp {
        u_long end;
        u_long select;
        u_long command;
-       u_long data;
        u_long status;
        u_long disconnect;
        u_long reselect;
@@ -1340,13 +1339,20 @@ struct ncb {
        **-----------------------------------------------
        */
        int    unit;                    /* Unit number                       */
-       int    chip;                    /* Chip number                       */
+       char   chip_name[8];            /* Chip name                         */
+       char   inst_name[16];           /* Instance name                     */
+       u_int  features;                /* Chip features map                 */
        struct timer_list timer;        /* Timer link header                 */
        int     ncr_cache;              /* Cache test variable               */
        Scsi_Cmnd *waiting_list;        /* Waiting list header for commands  */
                                        /* that we can't put into the squeue */
        u_long  settle_time;            /* Reset in progess                  */
        u_char  release_stage;          /* Synchronisation stage on release  */
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+       u_char  debug_error_recovery;
+       u_char  stalling;
+       u_char  assert_atn;
+#endif
 
        /*-----------------------------------------------
        **      Added field to support differences
@@ -1359,9 +1365,6 @@ struct ncb {
        */
        u_short device_id;
        u_char  revision_id;
-#define ChipDevice     ((np)->device_id)
-#define ChipVersion    ((np)->revision_id & 0xf0)
-
        u_char  sv_scntl3;
        u_char  sv_dmode;
        u_char  sv_dcntl;
@@ -1370,6 +1373,7 @@ struct ncb {
        u_char  sv_ctest5;
        u_char  sv_gpcntl;
        u_char  sv_stest2;
+       u_char  sv_stest4;
 
        u_char  rv_dmode;
        u_char  rv_dcntl;
@@ -1377,6 +1381,9 @@ struct ncb {
        u_char  rv_ctest4;
        u_char  rv_ctest5;
        u_char  rv_stest2;
+
+       u_char  maxburst;
+       u_char  scsi_mode;
        u_char  multiplier;
 
        /*-----------------------------------------------
@@ -1616,8 +1623,8 @@ struct script {
        ncrcmd  resel_tmp       [  5];
        ncrcmd  resel_lun       [ 18];
        ncrcmd  resel_tag       [ 24];
-       ncrcmd  data_io         [  2];  /* MUST be just before data_in */
-       ncrcmd  data_in         [MAX_SCATTER * 4 + 7];
+       ncrcmd  data_io         [  6];
+       ncrcmd  data_in         [MAX_SCATTER * 4 + 4];
 };
 
 /*
@@ -1642,7 +1649,7 @@ struct scripth {
        ncrcmd  getcc2          [ 14];
 #endif
        ncrcmd  getcc3          [ 10];
-       ncrcmd  data_out        [MAX_SCATTER * 4 + 7];
+       ncrcmd  data_out        [MAX_SCATTER * 4 + 4];
        ncrcmd  aborttag        [  4];
        ncrcmd  abort           [ 22];
        ncrcmd  snooptest       [  9];
@@ -1664,10 +1671,10 @@ static  void    ncr_exception   (ncb_p np);
 static void    ncr_free_ccb    (ncb_p np, ccb_p cp, u_long t, u_long l);
 static void    ncr_getclock    (ncb_p np, int mult);
 static void    ncr_selectclock (ncb_p np, u_char scntl3);
-static void    ncr_save_bios_setting   (ncb_p np);
 static ccb_p   ncr_get_ccb     (ncb_p np, u_long t,u_long l);
 static void    ncr_init        (ncb_p np, char * msg, u_long code);
-static int     ncr_intr        (ncb_p np);
+static int     ncr_int_sbmc    (ncb_p np);
+static int     ncr_int_par     (ncb_p np);
 static void    ncr_int_ma      (ncb_p np);
 static void    ncr_int_sir     (ncb_p np);
 static  void    ncr_int_sto     (ncb_p np);
@@ -1675,7 +1682,7 @@ static    u_long  ncr_lookup      (char* id);
 static void    ncr_negotiate   (struct ncb* np, struct tcb* tp);
 static void    ncr_opennings   (ncb_p np, lcb_p lp, Scsi_Cmnd * xp);
 
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 static void    ncb_profile     (ncb_p np, ccb_p cp);
 #endif
 
@@ -1694,12 +1701,12 @@ static  void    ncr_timeout     (ncb_p np);
 static  void    ncr_wakeup      (ncb_p np, u_long code);
 static void    ncr_start_reset (ncb_p np, int settle_delay);
 
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 static void    ncr_usercmd     (ncb_p np);
 #endif
 
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, u_short device_id,
-                      u_char revision_id, int chip, u_int base, u_int io_port, 
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit, 
+                      ncr_chip *chip, u_int base, u_int io_port, 
                       int irq, int bus, u_char device_fn);
 
 static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
@@ -1720,24 +1727,13 @@ static void process_waiting_list(ncb_p np, int sts);
 **==========================================================
 */
 
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
 #endif
 
-/*==========================================================
-**
-**
-**      Global static data:    auto configure
-**
-**
-**==========================================================
-*/
-
-static char *ncr_name (ncb_p np)
+static inline char *ncr_name (ncb_p np)
 {
-       static char name[16];
-       sprintf(name, "ncr53c%d-%d", np->chip, np->unit);
-       return (name);
+       return np->inst_name;
 }
 
 
@@ -1783,10 +1779,10 @@ static char *ncr_name (ncb_p np)
  * Kernel variables referenced in the scripts.
  * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
  */
-static void *script_kvars[] =
+static void *script_kvars[] __initdata =
        { (void *)&jiffies };
 
-static struct script script0 = {
+static struct script script0 __initdata = {
 /*--------------------------< START >-----------------------*/ {
        /*
        **      Claim to be still alive ...
@@ -1881,7 +1877,7 @@ static    struct script script0 = {
        **      patch the launch field.
        **      should look like an idle process.
        */
-       SCR_COPY (4),
+       SCR_COPY_F (4),
                RADDR (dsa),
                PADDR (skip2),
        SCR_COPY (8),
@@ -1987,7 +1983,7 @@ static    struct script script0 = {
        **      We patch the address part of a
        **      COPY command with the DSA-register.
        */
-       SCR_COPY (4),
+       SCR_COPY_F (4),
                RADDR (dsa),
                PADDR (loadpos),
        /*
@@ -2376,7 +2372,7 @@ static    struct script script0 = {
        /*
        **      and copy back the header to the ccb.
        */
-       SCR_COPY (4),
+       SCR_COPY_F (4),
                RADDR (dsa),
                PADDR (cleanup0),
        SCR_COPY (sizeof (struct head)),
@@ -2482,7 +2478,7 @@ static    struct script script0 = {
        **
        **      CAUTION: only little endian architectures supported! XXX
        */
-       SCR_COPY (1),
+       SCR_COPY_F (1),
                NADDR (header.savep),
                PADDR (disconnect0),
 }/*-------------------------< DISCONNECT0 >--------------*/,{
@@ -2491,7 +2487,7 @@ static    struct script script0 = {
        /*
        **      neither this
        */
-       SCR_COPY (1),
+       SCR_COPY_F (1),
                NADDR (header.goalp),
                PADDR (disconnect1),
 }/*-------------------------< DISCONNECT1 >--------------*/,{
@@ -2587,7 +2583,7 @@ static    struct script script0 = {
        **      This NOP will be patched with LED OFF
        **      SCR_REG_REG (gpreg, SCR_OR, 0x01)
        */
-       SCR_JUMP ^ IFFALSE (0),
+       SCR_NO_OP,
                0,
        /*
        **      make the DSA invalid.
@@ -2609,7 +2605,7 @@ static    struct script script0 = {
        **      This NOP will be patched with LED ON
        **      SCR_REG_REG (gpreg, SCR_AND, 0xfe)
        */
-       SCR_JUMP ^ IFFALSE (0),
+       SCR_NO_OP,
                0,
        /*
        **      ... zu nichts zu gebrauchen ?
@@ -2635,7 +2631,7 @@ static    struct script script0 = {
        **      This NOP will be patched with LED ON
        **      SCR_REG_REG (gpreg, SCR_AND, 0xfe)
        */
-       SCR_JUMP ^ IFFALSE (0),
+       SCR_NO_OP,
                0,
        /*
        **      If it's not connected :(
@@ -2758,10 +2754,14 @@ static  struct script script0 = {
 **     to low-level scsi drivers, we must trust the target 
 **     for actual data direction when we cannot guess it.
 **     The programmed interrupt patches savep, lastp, goalp,
-**     etc.., and restarts the scsi script at data_out.
+**     etc.., and restarts the scsi script at data_out/in.
 */
        SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
                SIR_DATA_IO_IS_OUT,
+       SCR_INT ^ IFTRUE (WHEN (SCR_DATA_IN)),
+               SIR_DATA_IO_IS_IN,
+       SCR_JUMP,
+               PADDR (no_data),
 
 }/*-------------------------< DATA_IN >--------------------*/,{
 /*
@@ -2769,15 +2769,7 @@ static   struct script script0 = {
 **     #define MAX_SCATTER parameter,
 **     it is filled in at runtime.
 **
-**     SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**             PADDR (no_data),
-**     SCR_COPY (sizeof (u_long)),
-**             KVAR(SCRIPT_KVAR_JIFFIES),
-**             NADDR (header.stamp.data),
-**     SCR_MOVE_TBL ^ SCR_DATA_IN,
-**             offsetof (struct dsb, data[ 0]),
-**
-**  ##===========< i=1; i<MAX_SCATTER >=========
+**  ##===========< i=0; i<MAX_SCATTER >=========
 **  || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
 **  ||         PADDR (checkatn),
 **  || SCR_MOVE_TBL ^ SCR_DATA_IN,
@@ -2793,7 +2785,7 @@ static    struct script script0 = {
 }/*--------------------------------------------------------*/
 };
 
-static struct scripth scripth0 = {
+static struct scripth scripth0 __initdata = {
 /*-------------------------< TRYLOOP >---------------------*/{
 /*
 **     Load an entry of the start queue into dsa
@@ -3109,7 +3101,7 @@ static    struct scripth scripth0 = {
        **      We patch the address part of a COPY command
        **      with the address of the dsa register ...
        */
-       SCR_COPY (4),
+       SCR_COPY_F (4),
                RADDR (dsa),
                PADDRH (getcc1),
        /*
@@ -3247,15 +3239,7 @@ static   struct scripth scripth0 = {
 **     #define MAX_SCATTER parameter,
 **     it is filled in at runtime.
 **
-**     SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**             PADDR (no_data),
-**     SCR_COPY (sizeof (u_long)),
-**             KVAR(SCRIPT_KVAR_JIFFIES),
-**             NADDR (header.stamp.data),
-**     SCR_MOVE_TBL ^ SCR_DATA_OUT,
-**             offsetof (struct dsb, data[ 0]),
-**
-**  ##===========< i=1; i<MAX_SCATTER >=========
+**  ##===========< i=0; i<MAX_SCATTER >=========
 **  || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
 **  ||         PADDR (dispatch),
 **  || SCR_MOVE_TBL ^ SCR_DATA_OUT,
@@ -3269,7 +3253,7 @@ static    struct scripth scripth0 = {
 **
 **---------------------------------------------------------
 */
-0      /* was (u_long)&ident ? */
+0
 }/*-------------------------< ABORTTAG >-------------------*/,{
        /*
        **      Abort a bad reselection.
@@ -3343,7 +3327,9 @@ static    struct scripth scripth0 = {
 **==========================================================
 */
 
+__initfunc(
 void ncr_script_fill (struct script * scr, struct scripth * scrh)
+)
 {
        int     i;
        ncrcmd  *p;
@@ -3363,15 +3349,7 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
 
        p = scr->data_in;
 
-       *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN));
-       *p++ =PADDR (no_data);
-       *p++ =SCR_COPY (sizeof (u_long));
-       *p++ =KVAR(SCRIPT_KVAR_JIFFIES);
-       *p++ =NADDR (header.stamp.data);
-       *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
-       *p++ =offsetof (struct dsb, data[ 0]);
-
-       for (i=1; i<MAX_SCATTER; i++) {
+       for (i=0; i<MAX_SCATTER; i++) {
                *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
                *p++ =PADDR (checkatn);
                *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
@@ -3387,15 +3365,7 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
 
        p = scrh->data_out;
 
-       *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT));
-       *p++ =PADDR (no_data);
-       *p++ =SCR_COPY (sizeof (u_long));
-       *p++ =KVAR(SCRIPT_KVAR_JIFFIES);
-       *p++ =NADDR (header.stamp.data);
-       *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
-       *p++ =offsetof (struct dsb, data[ 0]);
-
-       for (i=1; i<MAX_SCATTER; i++) {
+       for (i=0; i<MAX_SCATTER; i++) {
                *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
                *p++ =PADDR (dispatch);
                *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
@@ -3419,11 +3389,14 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh)
 **==========================================================
 */
 
+__initfunc(
 static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
+)
 {
        ncrcmd  opcode, new, old, tmp1, tmp2;
        ncrcmd  *start, *end;
        int relocs;
+       int opchanged = 0;
 
        start = src;
        end = src + len/4;
@@ -3470,6 +3443,14 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le
                                        ncr_name(np), (int) (src-start-1));
                                DELAY (1000000);
                        }
+                       /*
+                       **      If PREFETCH feature not enabled, remove 
+                       **      the NO FLUSH bit if present.
+                       */
+                       if ((opcode & SCR_NO_FLUSH) && !(np->features & _F_PFEN)) {
+                               dst[-1] = (opcode & ~SCR_NO_FLUSH);
+                               ++opchanged;
+                       }
                        break;
 
                case 0x0:
@@ -3546,6 +3527,9 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le
                        *dst++ = *src++;
 
        };
+       if (bootverbose > 1 && opchanged)
+               printf("%s: NO FLUSH bit removed from %d script instructions\n",
+                       ncr_name(np), opchanged); 
 }
 
 /*==========================================================
@@ -3595,6 +3579,218 @@ static void PRINT_ADDR(Scsi_Cmnd *cmd)
        if (np) PRINT_LUN(np, cmd->target, cmd->lun);
 }
 
+/*===============================================================
+**
+**     Prepare io register values used by ncr_init() according 
+**     to selected and supported features.
+**
+**     NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
+**     transfers. 32,64,128 are only supported by 875 and 895 chips.
+**     We use log base 2 (burst length) as internal code, with 
+**     value 0 meaning "burst disabled".
+**
+**===============================================================
+*/
+
+/*
+ *     Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ *     Burst code from io register bits.
+ */
+#define burst_code(dmode, ctest4, ctest5) \
+       (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
+
+/*
+ *     Set initial io register bits from burst code.
+ */
+static inline void ncr_init_burst(ncb_p np, u_char bc)
+{
+       np->rv_ctest4   &= ~0x80;
+       np->rv_dmode    &= ~(0x3 << 6);
+       np->rv_ctest5   &= ~0x4;
+
+       if (!bc) {
+               np->rv_ctest4   |= 0x80;
+       }
+       else {
+               --bc;
+               np->rv_dmode    |= ((bc & 0x3) << 6);
+               np->rv_ctest5   |= (bc & 0x4);
+       }
+}
+
+__initfunc(
+static int ncr_prepare_setting(ncb_p np)
+)
+{
+       u_char  burst_max;
+
+       /*
+       **      Save assumed BIOS setting
+       */
+
+       np->sv_scntl3   = INB(nc_scntl3) & 0x07;
+       np->sv_dmode    = INB(nc_dmode)  & 0xce;
+       np->sv_dcntl    = INB(nc_dcntl)  & 0xa8;
+       np->sv_ctest3   = INB(nc_ctest3) & 0x01;
+       np->sv_ctest4   = INB(nc_ctest4) & 0x80;
+       np->sv_ctest5   = INB(nc_ctest5) & 0x24;
+       np->sv_gpcntl   = INB(nc_gpcntl);
+       np->sv_stest2   = INB(nc_stest2) & 0x20;
+       np->sv_stest4   = INB(nc_stest4);
+
+       /*
+       **      Get the frequency of the chip's clock.
+       **      Find the right value for scntl3.
+       */
+
+       if      (np->features & _F_QUAD)
+               np->multiplier  = 4;
+       else if (np->features & _F_DBLR)
+               np->multiplier  = 2;
+       else
+               np->multiplier  = 1;
+
+       np->clock_khz   = (np->features & _F_CLK80)? 80000 : 40000;
+       np->clock_khz   *= np->multiplier;
+
+       if (np->clock_khz != 40000)
+               ncr_getclock(np, np->multiplier);
+
+       if      (np->clock_khz <=  25000)       np->rv_scntl3 = 0x01;
+       else if (np->clock_khz <=  37500)       np->rv_scntl3 = 0x02;
+       else if (np->clock_khz <=  50000)       np->rv_scntl3 = 0x03;
+       else if (np->clock_khz <=  75000)       np->rv_scntl3 = 0x04;
+       else if (np->clock_khz <= 100000)       np->rv_scntl3 = 0x05;
+       else if (np->clock_khz <= 150000)       np->rv_scntl3 = 0x06;
+       else                                    np->rv_scntl3 = 0x07;
+
+       /*
+       **      Get on-board RAM bus address when supported
+       */
+       if (np->features & _F_RAM) {
+               OUTONB(nc_ctest2, 0x8);
+               np->paddr2 = INL(nc_scr0);
+               OUTOFFB(nc_ctest2, 0x8);
+       }
+
+       /*
+       **      Prepare initial value of other IO registers
+       */
+#if defined SCSI_NCR_TRUST_BIOS_SETTING
+       np->rv_dmode    = np->sv_dmode;
+       np->rv_dcntl    = np->sv_dcntl;
+       np->rv_ctest3   = np->sv_ctest3;
+       np->rv_ctest4   = np->sv_ctest4;
+       np->rv_ctest5   = np->sv_ctest5;
+       burst_max       = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+#else
+       np->rv_dmode    = 0;
+       np->rv_dcntl    = 0;
+       np->rv_ctest3   = 0;
+       np->rv_ctest4   = 0;
+       np->rv_ctest5   = 0;
+       np->rv_stest2   = 0;
+
+       /*
+       **      Select burst length (dwords)
+       */
+       burst_max       = driver_setup.burst_max;
+       if (burst_max == 255)
+               burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+       if (burst_max > 7)
+               burst_max = 7;
+       if (burst_max > np->maxburst)
+               burst_max = np->maxburst;
+
+       /*
+       **      Select all supported special features
+       */
+       if (np->features & _F_ERL)
+               np->rv_dmode    |= ERL;         /* Enable Read Line */
+       if (np->features & _F_BOF)
+               np->rv_dmode    |= BOF;         /* Burst Opcode Fetch */
+       if (np->features & _F_ERMP)
+               np->rv_dmode    |= ERMP;        /* Enable Read Multiple */
+       if (np->features & _F_PFEN)
+               np->rv_dcntl    |= PFEN;        /* Prefetch Enable */
+       if (np->features & _F_CLSE)
+               np->rv_dcntl    |= CLSE;        /* Cache Line Size Enable */
+       if (np->features & _F_WRIE)
+               np->rv_ctest3   |= WRIE;        /* Write and Invalidate */
+       if (np->features & _F_DFS)
+               np->rv_ctest5   |= DFS;         /* Dma Fifo Size */
+
+       /*
+       **      Select some other
+       */
+       if (driver_setup.master_parity)
+               np->rv_ctest4   |= MPEE;        /* Master parity checking */
+
+#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
+
+       /*
+        *      Prepare initial io register bits for burst length
+        */
+       ncr_init_burst(np, burst_max);
+
+       /*
+       **      Set differential mode.
+       */
+       switch(driver_setup.diff_support) {
+       case 3:
+               if (INB(nc_gpreg) & 0x08)
+                       break;
+       case 2:
+               np->rv_stest2   |= 0x20;
+               break;
+       case 1:
+               np->rv_stest2   |= (np->sv_stest2 & 0x20);
+               break;
+       default:
+               break;
+       }
+
+       /*
+       **      Set irq mode.
+       */
+       switch(driver_setup.irqm) {
+       case 2:
+               np->rv_dcntl    |= IRQM;
+               break;
+       case 1:
+               np->rv_stest2   |= (np->sv_dcntl & IRQM);
+               break;
+       default:
+               break;
+       }
+
+       /*
+       **      Announce all that stuff to user.
+       */
+       if (bootverbose > 1) {
+               printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
+                       ncr_name(np), np->sv_scntl3, np->rv_scntl3);
+               printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+                       ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+               printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+                       ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+               if (np->rv_stest2 & 0x20)
+                       printf ("%s: DIFF mode set\n", ncr_name(np));
+       }
+
+       if (bootverbose && np->paddr2)
+               printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
+
+       if (bootverbose && np->ns_sync < 25)
+               printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
+                       np->ns_sync < 12 ? "-2": "");
+
+       return 0;
+}
 
 /*
 **     Host attach and initialisations.
@@ -3602,25 +3798,23 @@ static void PRINT_ADDR(Scsi_Cmnd *cmd)
 **     Allocate host data and ncb structure.
 **     Request IO region and remap MMIO region.
 **     Do chip initialization.
-**     Try with mmio.
-**     If mmio not possible (misconfigured cache),
-**     retry with io mapped.
 **     If all is OK, install interrupt handling and
 **     start the timer daemon.
 */
 
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ushort device_id,
-                      u_char revision_id, int chip, u_int base, u_int io_port, 
+__initfunc(
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit, 
+                      ncr_chip *chip, u_int base, u_int io_port, 
                       int irq, int bus, u_char device_fn)
-
+)
 {
         struct host_data *host_data;
        ncb_p np;
         struct Scsi_Host *instance = 0;
        u_long flags = 0;
 
-printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
-       unit, chiprevision_id, base, io_port, irq);
+printf("ncr53c8xx: unit=%d chip=%s rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
+       unit, chip->name, chip->revision_id, base, io_port, irq);
 
        /*
        **      Allocate host_data structure
@@ -3645,10 +3839,21 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
        np->ccb   = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK);
        bzero (np->ccb, sizeof (*np->ccb));
 
-       np->unit = unit;
-       np->chip = chip;
-       np->device_id   = device_id;
-       np->revision_id = revision_id;
+       /*
+       **      Store input informations in the host data structure.
+       */
+       strncpy(np->chip_name, chip->name, sizeof(np->chip_name) - 1);
+       np->unit        = unit;
+       sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit);
+       np->device_id   = chip->device_id;
+       np->revision_id = chip->revision_id;
+       np->features    = chip->features;
+       np->maxwide     = (np->features & _F_WIDE)? 1 : 0;
+       np->ns_sync     = 25;
+       np->clock_khz   = 40000;
+       np->clock_divn  = chip->nr_divisor;
+       np->maxoffs     = chip->offset_max;
+       np->maxburst    = chip->burst_max;
 
        np->script0  =
        (struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK);
@@ -3673,9 +3878,7 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
        np->vaddr = remap_pci_mem((u_long) base, (u_long) 128);
        if (!np->vaddr) {
                printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-#ifdef NCR_MEMORYMAPPED
                goto attach_error;
-#endif
        }
        else
                if (bootverbose > 1)
@@ -3698,98 +3901,17 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
        request_region(io_port, 128, "ncr53c8xx");
        np->port = io_port;
 
-       /*
-       **      Save initial value of some io registers.
-       */
-
-       ncr_save_bios_setting(np);
-
        /*
        **      Do chip dependent initialization.
        */
-
-       np->maxwide = 0;
-       np->rv_scntl3 = 0x13;   /* default: 40MHz clock */
-       np->ns_sync   = 25;
-       np->clock_khz   = 40000;
-       np->clock_divn  = 4;
-       np->maxoffs   = 8;
-       np->multiplier = 1;
-
-       /*
-       **      Get the frequency of the chip's clock.
-       **      Find the right value for scntl3.
-       */
-
-       switch (device_id) {
-       case PCI_DEVICE_ID_NCR_53C825:
-               np->maxwide = 1;
-               break;
-       case PCI_DEVICE_ID_NCR_53C860:
-               if (driver_setup.ultra_scsi) {
-                       np->rv_scntl3 = 0x15;
-                       np->clock_khz = 80000;
-                       np->ns_sync   = 12;
-               }
-               else
-                       np->rv_scntl3 = 0x35;   /* always assume 80MHz clock for 860 */
-               np->clock_divn  = 5;
-               break;
-       case PCI_DEVICE_ID_NCR_53C875:
-       case PCI_DEVICE_ID_NCR_53C885:
-               np->maxwide = 1;
-               if (driver_setup.special_features)
-                       np->maxoffs = 16;
-               np->clock_divn  = 5;
-               if (device_id == PCI_DEVICE_ID_NCR_53C875)
-                       ncr_getclock(np, revision_id >= 2 ? 2 : 1);
-               else
-                       ncr_getclock(np, 2);
-               break;
-       case PCI_DEVICE_ID_NCR_53C895:
-       case PCI_DEVICE_ID_NCR_53C896:
-               np->maxwide = 1;
-               if (driver_setup.special_features)
-                       np->maxoffs = 31;
-               np->clock_divn  = 7;
-               ncr_getclock(np, 4);
-               break;
-       }
-
-       /*
-       **      Get on-board RAM bus address when supported
-       */
-       switch (device_id) {
-       case PCI_DEVICE_ID_NCR_53C825:
-               if (revision_id < 0x10)
-                       break;
-       case PCI_DEVICE_ID_NCR_53C875:
-       case PCI_DEVICE_ID_NCR_53C885:
-       case PCI_DEVICE_ID_NCR_53C895:
-       case PCI_DEVICE_ID_NCR_53C896:
-               if (driver_setup.special_features) {
-                       OUTONB(nc_ctest2, 0x8);
-                       np->paddr2 = INL(nc_scr0);
-                       OUTOFFB(nc_ctest2, 0x8);
-               }
-               break;
-       }
-
-       if (bootverbose && np->paddr2)
-               printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
-
-       if (bootverbose && np->ns_sync < 25)
-               printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
-                       np->ns_sync < 12 ? "-2": "");
+       (void)ncr_prepare_setting(np);
 
 #ifndef NCR_IOMAPPED
        if (np->paddr2 && sizeof(struct script) <= 4096) {
                np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096);
                if (!np->vaddr2) {
                        printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-#ifdef NCR_MEMORYMAPPED
                        goto attach_error;
-#endif
                }
                else
                        if (bootverbose > 1)
@@ -3830,6 +3952,17 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
        ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
        np->ccb->p_ccb          = vtophys (np->ccb);
 
+       /*
+       **    Patch the script for LED support.
+       */
+
+       if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+               np->features |= _F_LED0;
+               np->script0->reselect[0]  = SCR_REG_REG(gpreg, SCR_OR,  0x01);
+               np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+               np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+       }
+
        /*
        **      init data structure
        */
@@ -3837,10 +3970,6 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
        np->jump_tcb.l_cmd      = SCR_JUMP;
        np->jump_tcb.l_paddr    = NCB_SCRIPTH_PHYS (np, abort);
 
-#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
-retry_chip_init:
-#endif
-
        /*
        **  Get SCSI addr of host adapter (set by bios?).
        */
@@ -3864,14 +3993,6 @@ retry_chip_init:
        */
 
        if (ncr_snooptest (np)) {
-#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
-               if (np->reg) {
-printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
-       ncr_name(np), (u_long) np->port);
-                       np->reg = 0;
-                       goto retry_chip_init;
-               }
-#endif
                printf ("CACHE INCORRECTLY CONFIGURED.\n");
                goto attach_error;
        };
@@ -3962,18 +4083,25 @@ printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
 
 attach_error:
        if (!instance) return -1;
+       printf("%s: detaching...\n", ncr_name(np));
 #ifndef NCR_IOMAPPED
        if (np->vaddr) {
+#ifdef DEBUG_NCR53C8XX
                printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+#endif
                unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
        }
        if (np->vaddr2) {
+#ifdef DEBUG_NCR53C8XX
                printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
+#endif
                unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
        }
 #endif
        if (np->port) {
+#ifdef DEBUG_NCR53C8XX
                printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+#endif
                release_region(np->port, 128);
        }
        scsi_unregister(instance);
@@ -3981,47 +4109,6 @@ attach_error:
         return -1;
  }
 
-/*==========================================================
-**
-**
-**     Process pending device interrupts.
-**
-**
-**==========================================================
-*/
-int ncr_intr(np)
-       ncb_p np;
-{
-       int n = 0;
-       u_long flags;
-
-       save_flags(flags); cli();
-
-       if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-
-#ifdef SCSI_NCR_PARANOIA
-       if (INB(nc_istat) & (INTF|SIP|DIP)) {
-               /*
-               **      Repeat until no outstanding ints
-               */
-               do {
-#endif
-                       ncr_exception (np);
-#ifdef SCSI_NCR_PARANOIA
-               } while (INB(nc_istat) & (INTF|SIP|DIP));
-
-               n=1;
-               np->ticks = 5 * HZ;
-       };
-#endif
-
-       if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-
-       restore_flags(flags);
-
-       return (n);
-}
-
 /*==========================================================
 **
 **
@@ -4107,7 +4194,7 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
        **
        **----------------------------------------------------
        */
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
        bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
        cp->phys.header.stamp.start = jiffies;
 #endif
@@ -4337,25 +4424,30 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
        */
 
        cp->segments = segments;
+       if (!cp->data_len)
+               xfer_direction = XferNone;
 
        switch (xfer_direction) {
+               u_long endp;
        default:
        case XferBoth:
-            cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
-            cp->phys.header.goalp = cp->phys.header.savep +8 +20 +segments*16;
-            break;
+               cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
+               cp->phys.header.goalp = cp->phys.header.savep;
+               break;
        case XferIn:
-            cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in);
-            cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
-            break;
+               endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
+               cp->phys.header.goalp = endp + 8;
+               cp->phys.header.savep = endp - segments*16;
+               break;
        case XferOut:
-            cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out);
-            cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
-            break;
+               endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+               cp->phys.header.goalp = endp + 8;
+               cp->phys.header.savep = endp - segments*16;
+               break;
        case XferNone:
-            cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
-            cp->phys.header.goalp = cp->phys.header.savep;
-            break;
+               cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
+               cp->phys.header.goalp = cp->phys.header.savep;
+               break;
        }
 
        cp->phys.header.lastp = cp->phys.header.savep;
@@ -4463,6 +4555,9 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
        **      Script processor may be waiting for reselect.
        **      Wake it up.
        */
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+       if (!np->stalling)
+#endif
        OUTB (nc_istat, SIGP);
 
        /*
@@ -4530,6 +4625,11 @@ int ncr_reset_bus (Scsi_Cmnd *cmd, int sync_reset)
        u_long flags;
        int found;
 
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+       if (np->stalling)
+               np->stalling = 0;
+#endif
+
        save_flags(flags); cli();
 /*
  * Return immediately if reset is in progress.
@@ -4607,6 +4707,11 @@ static int ncr_abort_command (Scsi_Cmnd *cmd)
        int found;
        int retv;
 
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+       if (np->stalling == 2)
+               np->stalling = 0;
+#endif
+
        save_flags(flags); cli();
 /*
  * First, look for the scsi command in the waiting list
@@ -4663,6 +4768,9 @@ static int ncr_abort_command (Scsi_Cmnd *cmd)
        **      processor will sleep on SEL_WAIT_RESEL.
        **      Let's wake it up, since it may have to work.
        */
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+       if (!np->stalling)
+#endif
        OUTB (nc_istat, SIGP);
 
        restore_flags(flags);
@@ -4697,7 +4805,7 @@ static int ncr_detach(ncb_p np, int irq)
 **     Set release_stage to 1 and wait that ncr_timeout() set it to 2.
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
        printf("%s: stopping the timer\n", ncr_name(np));
 #endif
        np->release_stage = 1;
@@ -4710,7 +4818,7 @@ static int ncr_detach(ncb_p np, int irq)
 **     Disable chip interrupts
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
        printf("%s: disabling chip interrupts\n", ncr_name(np));
 #endif
        OUTW (nc_sien , 0);
@@ -4720,7 +4828,7 @@ static int ncr_detach(ncb_p np, int irq)
 **     Free irq
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
        printf("%s: freeing irq %d\n", ncr_name(np), irq);
 #endif
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
@@ -4758,17 +4866,17 @@ static int ncr_detach(ncb_p np, int irq)
        */
 
 #ifndef NCR_IOMAPPED
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
        printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
 #endif
        unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
        printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
 #endif
        unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
 #endif
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
        printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
 #endif
        release_region(np->port, 128);
@@ -4783,7 +4891,7 @@ static int ncr_detach(ncb_p np, int irq)
                printf("%s: shall free an active ccb (host_status=%d)\n",
                        ncr_name(np), cp->host_status);
                }
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
        printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
 #endif
                m_free(cp, sizeof(*cp));
@@ -4798,7 +4906,7 @@ static int ncr_detach(ncb_p np, int irq)
                for (lun = 0 ; lun < MAX_LUN ; lun++) {
                        lp = tp->lp[lun];
                        if (lp) {
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
        printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
 #endif
                                m_free(lp, sizeof(*lp));
@@ -4851,7 +4959,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
        **      timestamp
        **      Optional, spare some CPU time
        */
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
        ncb_profile (np, cp);
 #endif
 
@@ -5158,46 +5266,6 @@ void ncr_wakeup (ncb_p np, u_long code)
        };
 }
 
-/*===============================================================
-**
-**     NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
-**     transfers. 32,64,128 are only supported by 875 and 895 chips.
-**     We use log base 2 (burst length) as internal code, with 
-**     value 0 meaning "burst disabled".
-**
-**===============================================================
-*/
-
-/*
- *     Burst length from burst code.
- */
-#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
-
-/*
- *     Burst code from io register bits.
- */
-#define burst_code(dmode, ctest4, ctest5) \
-       (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
-
-/*
- *     Set initial io register bits from burst code.
- */
-static void ncr_init_burst(ncb_p np, u_char bc)
-{
-       np->rv_ctest4   &= ~0x80;
-       np->rv_dmode    &= ~(0x3 << 6);
-       np->rv_ctest5   &= ~0x4;
-
-       if (!bc) {
-               np->rv_ctest4   |= 0x80;
-       }
-       else {
-               --bc;
-               np->rv_dmode    |= ((bc & 0x3) << 6);
-               np->rv_ctest5   |= (bc & 0x4);
-       }
-}
-
 /*==========================================================
 **
 **
@@ -5212,7 +5280,6 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        int     i;
        u_long  usrsync;
        u_char  usrwide;
-       u_char  burst_max;
 
        /*
        **      Reset chip.
@@ -5236,7 +5303,6 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        /*
        **      Start at first entry.
        */
-
        np->squeueput = 0;
        np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop);
        np->script0->start0  [0] = SCR_INT ^ IFFALSE (0);
@@ -5249,161 +5315,30 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        /*
        **      Init chip.
        */
-#if defined SCSI_NCR_TRUST_BIOS_SETTING
-       np->rv_dmode    = np->sv_dmode;
-       np->rv_dcntl    = np->sv_dcntl;
-       np->rv_ctest3   = np->sv_ctest3;
-       np->rv_ctest4   = np->sv_ctest4;
-       np->rv_ctest5   = np->sv_ctest5;
-       burst_max       = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
-#else
-       np->rv_dmode    = 0;
-       np->rv_dcntl    = 0;
-       np->rv_ctest3   = 0;
-       np->rv_ctest4   = 0;
-       burst_max       = driver_setup.burst_max;
-       if (burst_max == 255)
-               burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
-       if (burst_max > 7)
-               burst_max = 7;
 
-/**    NCR53C810                       **/
-       if (ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion == 0) {
-               burst_max       = burst_max < 4 ? burst_max : 4;
-               if (driver_setup.special_features)
-                       np->rv_dmode    =  ERL;         /* read line */
-       }
-       else
-/**    NCR53C815                       **/
-       if (ChipDevice == PCI_DEVICE_ID_NCR_53C815) {
-               burst_max       = burst_max < 4 ? burst_max : 4;
-               if (driver_setup.special_features)
-                       np->rv_dmode    = BOF | ERL;    /* burst opcode fetch, read line */
-       }
-       else
-/**    NCR53C825                       **/
-       if (ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion == 0) {
-               burst_max       = burst_max < 4 ? burst_max : 4;
-               if (driver_setup.special_features)
-                       np->rv_dmode    = BOF | ERL;    /* burst opcode fetch, read line */
-       }
-       else
-/**    NCR53C810A or NCR53C860         **/
-       if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) ||
-           ChipDevice == PCI_DEVICE_ID_NCR_53C860) {
-               burst_max       = burst_max < 4 ? burst_max : 4;
-               if (driver_setup.special_features) {
-                       np->rv_dmode    = BOF | ERMP | ERL;
-                                               /* burst op-code fetch, read multiple */
-                                               /* read line */
-                       np->rv_dcntl    = PFEN | CLSE;
-                                               /* prefetch, cache line size */
-                       np->rv_ctest3   = WRIE; /* write and invalidate */
-               }
-       }
-       else
-/**    NCR53C825A or NCR53C875 or NCR53C885 or NCR53C895 or NCR53C896  **/
-       if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) ||
-           ChipDevice == PCI_DEVICE_ID_NCR_53C875 ||
-           ChipDevice == PCI_DEVICE_ID_NCR_53C885 ||
-           ChipDevice == PCI_DEVICE_ID_NCR_53C895 ||
-           ChipDevice == PCI_DEVICE_ID_NCR_53C896) {
-               if (!driver_setup.special_features)
-                       burst_max       = burst_max < 4 ? burst_max : 4;
-               else {
-                       burst_max       = burst_max < 7 ? burst_max : 7;
-                       np->rv_dmode    = BOF | ERMP | ERL;
-                                               /* burst op-code fetch, read multiple */
-                                               /* read line, burst 128 (ctest5&4) */
-                       np->rv_dcntl    = PFEN | CLSE;
-                                               /* prefetch, cache line size */
-                       np->rv_ctest3   = WRIE; /* write and invalidate */
-                       np->rv_ctest5   = DFS;  /* large dma fifo (0x20) */
-               }
-       }
-/**    OTHERS                          **/
-       else {
-               burst_max       = burst_max < 4 ? burst_max : 4;
-       }
-#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
-
-       /*
-        *      Prepare initial io register bits for burst length
-        */
-       ncr_init_burst(np, burst_max);
-
-       /*
-       **      Set differential mode.
-       */
-       switch(driver_setup.diff_support) {
-       case 3:
-               if (INB(nc_gpreg) & 0x08)
-                       break;
-       case 2:
-               np->rv_stest2   |= 0x20;
-               break;
-       case 1:
-               np->rv_stest2   |= (np->sv_stest2 & 0x20);
-               break;
-       default:
-               break;
-       }
-
-       /*
-       **      Set irq mode.
-       */
-       switch(driver_setup.irqm) {
-       case 2:
-               np->rv_dcntl    |= IRQM;
-               break;
-       case 1:
-               np->rv_stest2   |= (np->sv_dcntl & IRQM);
-               break;
-       default:
-               break;
-       }
-
-       if (bootverbose > 1) {
-               printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
-                       ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
-       }
-       if (bootverbose > 1) {
-               printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
-                       ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
-               if (np->rv_stest2 & 0x20)
-                       printf ("%s: setting up differential mode\n", ncr_name(np));
-       }
-
-       OUTB (nc_istat,  0x00   );      /*  Remove Reset, abort ...          */
+       OUTB (nc_istat,  0x00   );      /*  Remove Reset, abort */
        if (driver_setup.scsi_parity)
-               OUTB (nc_scntl0, 0xca   );      /*  full arb., ena parity, par->ATN  */
+               OUTB (nc_scntl0, 0xca); /*  full arb., ena parity, par->ATN  */
        else
-               OUTB (nc_scntl0, 0xc0   );      /*  full arb., (no parity)           */
-
-       OUTB (nc_scntl1, 0x00   );      /*  odd parity, and remove CRST!!    */
-
-       ncr_selectclock(np, np->rv_scntl3);
+               OUTB (nc_scntl0, 0xc0); /*  full arb., (no parity) */
 
-       OUTB (nc_scid  , RRE|np->myaddr);/*  host adapter SCSI address       */
-       OUTW (nc_respid, 1ul<<np->myaddr);/*  id to respond to               */
-       OUTB (nc_istat , SIGP   );      /*  Signal Process                   */
-       OUTB (nc_dmode , np->rv_dmode); /*  Burst length = 2 .. 16 transfers */
+       OUTB (nc_scntl1, 0x00);         /*  odd parity, and remove CRST!! */
 
-       if (driver_setup.special_features && np->rv_ctest5)
-               OUTB (nc_ctest5, np->rv_ctest5);     /*  large fifo + large burst */
+       ncr_selectclock(np, np->rv_scntl3);     /* Select SCSI clock */
 
-       OUTB (nc_dcntl , NOCOM|np->rv_dcntl);/* no single step mode, protect SFBR*/
-       OUTB (nc_ctest3, np->rv_ctest3);     /* write and invalidate       */
+       OUTB (nc_scid  , RRE|np->myaddr);       /* Adapter SCSI address */
+       OUTW (nc_respid, 1ul<<np->myaddr);      /* Id to respond to */
+       OUTB (nc_istat , SIGP   );              /*  Signal Process */
+       OUTB (nc_dmode , np->rv_dmode);         /* Burst length, dma mode */
+       OUTB (nc_ctest5, np->rv_ctest5);        /* Large fifo + large burst */
 
-       if (driver_setup.master_parity)
-               OUTB (nc_ctest4, MPEE|np->rv_ctest4);   /*  enable master parity checking    */
-       else
-               OUTB (nc_ctest4, 0x00|np->rv_ctest4);   /*  disable master parity checking   */
+       OUTB (nc_dcntl , NOCOM|np->rv_dcntl);   /* Protect SFBR */
+       OUTB (nc_ctest3, np->rv_ctest3);        /* Write and invalidate */
+       OUTB (nc_ctest4, np->rv_ctest4);        /* Master parity checking */
 
-       OUTB (nc_stest2, EXT|np->rv_stest2);    /*  Extended Sreq/Sack filtering     */
-       OUTB (nc_stest3, TE     );      /*  TolerANT enable                  */
-       OUTB (nc_stime0, 0x0d   );      /*  HTH = disable  STO = 0.4 sec.    */
-                                       /*  0.25 sec recommended for scsi 1  */
+       OUTB (nc_stest2, EXT|np->rv_stest2);    /* Extended Sreq/Sack filtering */
+       OUTB (nc_stest3, TE);                   /* TolerANT enable */
+       OUTB (nc_stime0, 0x0d   );              /* HTH disabled  STO 0.4 sec. */
 
        /*
        **      Reinitialize usrsync.
@@ -5436,31 +5371,11 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        np->disc = 0;
 
        /*
-       **      Fill in target structure.
+       **    Enable GPIO0 pin for writing if LED support.
        */
 
-       for (i=0;i<MAX_TARGET;i++) {
-               tcb_p tp = &np->target[i];
-
-               tp->sval    = 0;
-               tp->wval    = np->rv_scntl3;
-
-               tp->usrsync = usrsync;
-               tp->usrwide = usrwide;
-
-               ncr_negotiate (np, tp);
-       }
-
-       /*
-       **    Enable GPIO0 pin for writing.
-       **    Patch the script for LED support.
-       */
-
-       if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+       if (np->features & _F_LED0) {
                OUTOFFB (nc_gpcntl, 0x01);
-               np->script0->reselect[0]  = SCR_REG_REG(gpreg, SCR_OR,  0x01);
-               np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
-               np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
        }
 
        /*
@@ -5479,6 +5394,31 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST);
        OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
 
+       /*
+       **      For 895/6 enable SBMC interrupt and save current SCSI bus mode.
+       */
+       if (np->features & _F_ULTRA2) {
+               OUTONW (nc_sien, SBMC);
+               np->scsi_mode = INB (nc_stest4) & SMODE;
+       }
+
+       /*
+       **      Fill in target structure.
+       **      Prepare sync negotiation according to actual SCSI bus mode.
+       */
+
+       for (i=0;i<MAX_TARGET;i++) {
+               tcb_p tp = &np->target[i];
+
+               tp->sval    = 0;
+               tp->wval    = np->rv_scntl3;
+
+               tp->usrsync = usrsync;
+               tp->usrwide = usrwide;
+
+               ncr_negotiate (np, tp);
+       }
+
        /*
        **    Start script processor.
        */
@@ -5502,14 +5442,12 @@ static void ncr_negotiate (struct ncb* np, struct tcb* tp)
 
        u_long minsync = tp->usrsync;
 
-       if      (driver_setup.ultra_scsi >= 2) {
-               if (minsync < 10) minsync=10;
-       }
-       else if (driver_setup.ultra_scsi == 1) {
-               if (minsync < 12) minsync=12;
-       }
-       else {
-               if (minsync < 25) minsync=25;
+       /*
+       **      SCSI bus mode limit
+       */
+
+       if (np->scsi_mode && np->scsi_mode == SMODE_SE) {
+               if (minsync < 12) minsync = 12;
        }
 
        /*
@@ -5628,7 +5566,7 @@ static int ncr_getsync(ncb_p np, u_char fac, u_char *fakp, u_char *scntl3p)
        *fakp           = fak - 4;
        *scntl3p        = ((idiv+1) << 4) + (fac < 25 ? ULTRA : 0);
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printf("fac=%d idiv=%d per=%d fak=%x ", fac, idiv, per, *fakp);
 #endif
 
@@ -5867,7 +5805,7 @@ static void ncr_settags (tcb_p tp, lcb_p lp)
 **----------------------------------------------------
 */
 
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 
 static void ncr_usercmd (ncb_p np)
 {
@@ -5897,7 +5835,7 @@ static void ncr_usercmd (ncb_p np)
                break;
 
        case UC_SETDEBUG:
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
                ncr_debug = np->user.data;
 #endif
                break;
@@ -5929,12 +5867,106 @@ static void ncr_usercmd (ncb_p np)
        case UC_CLEARPROF:
                bzero(&np->profile, sizeof(np->profile));
                break;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+       case UC_DEBUG_ERROR_RECOVERY:
+               np->debug_error_recovery = np->user.data;
+               break;
+#endif
        }
        np->user.cmd=0;
 }
 #endif
 
 
+/*=====================================================================
+**
+**    Embedded error recovery debugging code.
+**
+**=====================================================================
+**
+**    This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT.
+**    It only can be enabled after boot-up with a control command.
+**
+**    Every 30 seconds the timer handler of the driver decides to 
+**    change the behaviour of the driver in order to trigger errors.
+**
+**    If last command was "debug_error_recovery sge", the driver 
+**    sets sync offset of all targets that use sync transfers to 2, 
+**    and so hopes a SCSI gross error at the next read operation.
+**
+**    If last command was "debug_error_recovery abort", the driver 
+**    does not signal new scsi commands to the script processor, until 
+**    it is asked to abort or reset a command by the mid-level driver.
+**
+**    If last command was "debug_error_recovery reset", the driver 
+**    does not signal new scsi commands to the script processor, until 
+**    it is asked to reset a command by the mid-level driver.
+**
+**    If last command was "debug_error_recovery parity", the driver 
+**    will assert ATN on the next DATA IN phase mismatch, and so will 
+**    behave as if a parity error had been detected.
+**
+**    The command "debug_error_recovery none" makes the driver behave 
+**    normaly.
+**
+**=====================================================================
+*/
+
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+static void ncr_trigger_errors (ncb_p np)
+{
+       /*
+       **      If np->debug_error_recovery is not zero, we want to 
+       **      simulate common errors in order to test error recovery.
+       */
+       do {
+               static u_long last = 0l;
+
+               if (!np->debug_error_recovery)
+                       break;
+               if (!last)
+                       last = jiffies;
+               else if (jiffies < last + 30*HZ)
+                       break;
+               last = jiffies;
+               /*
+                * This one triggers SCSI gross errors.
+                */
+               if (np->debug_error_recovery == 1) {
+                       int i;
+                       printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np));
+                       for (i = 0 ; i < MAX_TARGET ; i++) {
+                               if (np->target[i].sval & 0x1f) {
+                                       np->target[i].sval &= ~0x1f;
+                                       np->target[i].sval += 2;
+                               }
+                       }
+               }
+               /*
+                * This one triggers abort from the mid-level driver.
+                */
+               else if (np->debug_error_recovery == 2) {
+                       printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np));
+                       np->stalling = 2;
+               }
+               /*
+                * This one triggers reset from the mid-level driver.
+                */
+               else if (np->debug_error_recovery == 3) {
+                       printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np));
+                       np->stalling = 3;
+               }
+               /*
+                * This one set ATN on phase mismatch in DATA IN phase and so 
+                * will behave as on scsi parity error detected.
+                */
+               else if (np->debug_error_recovery == 4) {
+                       printf("%s: testing data in parity error...\n", ncr_name(np));
+                       np->assert_atn = 1;
+               }
+       } while (0);
+}
+#endif
 
 /*==========================================================
 **
@@ -5977,6 +6009,10 @@ static void ncr_timeout (ncb_p np)
 
        add_timer(&np->timer);
 
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+       ncr_trigger_errors (np);
+#endif
+
        /*
        **      If we are resetting the ncr, wait for settle_time before 
        **      clearing it. Then command processing will be resumed.
@@ -6084,6 +6120,9 @@ static void ncr_timeout (ncb_p np)
                        */
                        ncr_complete (np, cp);
 
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+                       if (!np->stalling)
+#endif
                        OUTB (nc_istat, SIGP);
                }
                restore_flags(flags);
@@ -6138,6 +6177,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
 {
        u_int32 dsp;
        int     script_ofs;
+       int     script_size;
        char    *script_name;
        u_char  *script_base;
        int     i;
@@ -6146,11 +6186,13 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
 
        if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
                script_ofs      = dsp - np->p_script;
+               script_size     = sizeof(struct script);
                script_base     = (u_char *) np->script;
                script_name     = "script";
        }
        else {
                script_ofs      = dsp - np->p_scripth;
+               script_size     = sizeof(struct scripth);
                script_base     = (u_char *) np->scripth;
                script_name     = "scripth";
        }
@@ -6162,7 +6204,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
                (unsigned)INL (nc_dbc));
 
        if (((script_ofs & 3) == 0) &&
-           (unsigned)script_ofs < sizeof(struct script)) {
+           (unsigned)script_ofs < script_size) {
                printf ("%s: script cmd = %08x\n", ncr_name(np),
                        (int) *(ncrcmd *)(script_base + script_ofs));
        }
@@ -6173,13 +6215,36 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
         printf (".\n");
 }
 
-/*==========================================================
-**
+/*============================================================
 **
 **     ncr chip exception handler.
 **
+**============================================================
 **
-**==========================================================
+**     In normal cases, interrupt conditions occur one at a 
+**     time. The ncr is able to stack in some extra registers 
+**     other interrupts that will occurs after the first one.
+**     But severall interrupts may occur at the same time.
+**
+**     We probably should only try to deal with the normal 
+**     case, but it seems that multiple interrupts occur in 
+**     some cases that are not abnormal at all.
+**
+**     The most frequent interrupt condition is Phase Mismatch.
+**     We should want to service this interrupt quickly.
+**     A SCSI parity error may be delivered at the same time.
+**     The SIR interrupt is not very frequent in this driver, 
+**     since the INTFLY is likely used for command completion 
+**     signaling.
+**     The Selection Timeout interrupt may be triggered with 
+**     IID and/or UDC.
+**     The SBMC interrupt (SCSI Bus Mode Change) may probably 
+**     occur at any time.
+**
+**     This handler try to deal as cleverly as possible with all
+**     the above.
+**
+**============================================================
 */
 
 void ncr_exception (ncb_p np)
@@ -6193,14 +6258,23 @@ void ncr_exception (ncb_p np)
        */
        while ((istat = INB (nc_istat)) & INTF) {
                if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+       if (np->stalling)
+               OUTB (nc_istat, INTF);
+       else
+#endif
                OUTB (nc_istat, (istat & SIGP) | INTF);
                np->profile.num_fly++;
                ncr_wakeup (np, 0);
        };
 
-       if (!(istat & (SIP|DIP))) {
+       if (!(istat & (SIP|DIP)))
                return;
-       }
+
+       np->profile.num_int++;
+
+       if (istat & CABRT)
+               OUTB (nc_istat, CABRT);
 
        /*
        **      Steinbach's Guideline for Systems Programming:
@@ -6209,7 +6283,6 @@ void ncr_exception (ncb_p np)
 
        sist  = (istat & SIP) ? INW (nc_sist)  : 0;
        dstat = (istat & DIP) ? INB (nc_dstat) : 0;
-       np->profile.num_int++;
 
        if (DEBUG_FLAGS & DEBUG_TINY)
                printf ("<%d|%x:%x|%x:%x>",
@@ -6217,234 +6290,121 @@ void ncr_exception (ncb_p np)
                        dstat,sist,
                        (unsigned)INL(nc_dsp),
                        (unsigned)INL(nc_dbc));
-       if ((dstat==DFE) && (sist==PAR)) return;
 
-/*==========================================================
-**
-**     First the normal cases.
-**
-**==========================================================
-*/
-       /*-------------------------------------------
-       **      SCSI reset
-       **-------------------------------------------
-       */
-
-       if (sist & RST) {
-               ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
-               return;
-       };
-
-       /*-------------------------------------------
-       **      selection timeout
+       /*========================================================
+       **      First, interrupts we want to service cleanly.
        **
-       **      IID excluded from dstat mask!
-       **      (chip bug)
-       **-------------------------------------------
-       */
-
-       if ((sist  & STO) &&
-               !(sist  & (GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-               !(dstat & (MDPE|BF|ABRT|SIR))) {
-               ncr_int_sto (np);
-               return;
-       };
-
-       /*-------------------------------------------
-       **      Phase mismatch.
-       **-------------------------------------------
-       */
-
-       if ((sist  & MA) &&
-               !(sist  & (STO|GEN|HTH|SGE|UDC|RST|PAR)) &&
-               !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-               ncr_int_ma (np);
+       **      Phase mismatch is the most frequent interrupt, and 
+       **      so we have to service it as quickly and as cleanly 
+       **      as possible.
+       **      Programmed interrupts are rarely used in this driver,
+       **      but we must handle them cleanly anyway.
+       **      We try to deal with PAR and SBMC combined with 
+       **      some other interrupt(s).
+       **=========================================================
+       */
+
+       if (!(sist  & (STO|GEN|HTH|SGE|UDC|RST)) &&
+           !(dstat & (MDPE|BF|ABRT|IID))) {
+               if ((sist & SBMC) && ncr_int_sbmc (np))
+                       return;
+               if ((sist & PAR)  && ncr_int_par  (np))
+                       return;
+               if (sist & MA) {
+                       ncr_int_ma (np);
+                       return;
+               }
+               if (dstat & SIR) {
+                       ncr_int_sir (np);
+                       return;
+               }
+               if (!(sist & (SBMC|PAR)) && !(dstat & SSI))
+                       printf("%s: unknown interrupt(s) ignored sist=%x dstat=%x\n",
+                               ncr_name(np), sist, dstat);
+               OUTONB (nc_dcntl, (STD|NOCOM));
                return;
        };
 
-       /*----------------------------------------
-       **      move command with length 0
-       **----------------------------------------
+       /*========================================================
+       **      Now, interrupts that need some fixing up.
+       **      Order and multiple interrupts is so less important.
+       **
+       **      If SRST has been asserted, we just reset the chip.
+       **
+       **      Selection is intirely handled by the chip. If the 
+       **      chip says STO, we trust it. Seems some other 
+       **      interrupts may occur at the same time (UDC, IID), so 
+       **      we ignore them. In any case we do enough fix-up 
+       **      in the service routine.
+       **      We just exclude some fatal dma errors.
+       **=========================================================
        */
 
-       if ((dstat & IID) &&
-               !(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-               !(dstat & (MDPE|BF|ABRT|SIR)) &&
-               ((INL(nc_dbc) & 0xf8000000) == SCR_MOVE_TBL)) {
-               /*
-               **      Target wants more data than available.
-               **      The "no_data" script will do it.
-               */
-               OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, no_data));
+       if (sist & RST) {
+               ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
                return;
        };
 
-       /*-------------------------------------------
-       **      Programmed interrupt
-       **-------------------------------------------
-       */
-
-       if ((dstat & SIR) &&
-               !(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-               !(dstat & (MDPE|BF|ABRT|IID)) &&
-               (INB(nc_dsps) <= SIR_MAX)) {
-               ncr_int_sir (np);
+       if ((sist & STO) &&
+               !(dstat & (MDPE|BF|ABRT))) {
+               ncr_int_sto (np);
                return;
        };
 
-       /*========================================
-       **      do the register dump
-       **========================================
+       /*=========================================================
+       **      Now, interrupts we are not able to recover cleanly.
+       **      (At least for the moment).
+       **
+       **      Do the register dump.
+       **      Log message for real hard errors.
+       **      Clear all fifos.
+       **      For MDPE, BF, ABORT, IID, SGE and HTH we reset the 
+       **      BUS and the chip.
+       **      We are more soft for UDC.
+       **=========================================================
        */
        if (jiffies - np->regtime > 10*HZ) {
-               int i;
                np->regtime = jiffies;
-               for (i=0; i<sizeof(np->regdump); i++)
+               for (i = 0; i<sizeof(np->regdump); i++)
                        ((char*)&np->regdump)[i] = INB_OFF(i);
                np->regdump.nc_dstat = dstat;
                np->regdump.nc_sist  = sist;
-       };
-
-       /*=========================================
-       **      log message for real hard errors
-       **=========================================
-       */
-       ncr_log_hard_error(np, sist, dstat);
-
-       /*----------------------------------------
-       **      clean up the dma fifo
-       **----------------------------------------
-       */
-
-       if ( (INB(nc_sstat0) & (ILF|ORF|OLF)   ) ||
-            (INB(nc_sstat1) & (FF3210) ) ||
-            (INB(nc_sstat2) & (ILF1|ORF1|OLF1)) ||     /* wide .. */
-            !(dstat & DFE)) {
-               printf ("%s: have to clear fifos.\n", ncr_name (np));
-               OUTB (nc_stest3, TE|CSF);               /* clear scsi fifo */
-               OUTONB (nc_ctest3, CLF);                /* clear dma fifo  */
-       }
-
-       /*----------------------------------------
-       **      handshake timeout
-       **----------------------------------------
-       */
-
-       if (sist & HTH) {
-               printf ("%s: handshake timeout\n", ncr_name(np));
-               OUTB (nc_scntl1, CRST);
-               DELAY (1000);
-               OUTB (nc_scntl1, 0x00);
-               OUTB (nc_scr0, HS_FAIL);
-               OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
-               return;
-       }
-
-       /*----------------------------------------
-       **      unexpected disconnect
-       **----------------------------------------
-       */
-
-       if ((sist  & UDC) &&
-               !(sist  & (STO|GEN|HTH|MA|SGE|RST|PAR)) &&
-               !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-               OUTB (nc_scr0, HS_UNEXPECTED);
-               OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
-               return;
-       };
-
-       /*----------------------------------------
-       **      cannot disconnect
-       **----------------------------------------
-       */
-
-       if ((dstat & IID) &&
-               !(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-               !(dstat & (MDPE|BF|ABRT|SIR)) &&
-               ((INL(nc_dbc) & 0xf8000000) == SCR_WAIT_DISC)) {
-               /*
-               **      Unexpected data cycle while waiting for disconnect.
-               **      LDSC and CON bits may help in order to understand 
-               **      what really happened. Print some info message and let 
-               **      the reset function reset the BUS and the NCR.
-               */
-               printf("%s:%d: data cycle while waiting for disconnect, LDSC=%d CON=%d\n",
-                       ncr_name (np), (int)(INB(nc_ctest0)&0x0f),
-                       (0!=(INB(nc_sstat2)&LDSC)), (0!=(INB(nc_scntl1)&ISCON)));
-       };
-
-       /*----------------------------------------
-       **      single step
-       **----------------------------------------
-       */
-
-       if ((dstat & SSI) &&
-               !(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-               !(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-               OUTONB (nc_dcntl, (STD|NOCOM));
-               return;
-       };
-
-/*
-**     @RECOVER@ HTH, SGE, ABRT.
-**
-**     We should try to recover from these interrupts.
-**     They may occur if there are problems with synch transfers, or 
-**     if targets are switched on or off while the driver is running.
-*/
-
-       if (sist & SGE) {
-               OUTONB (nc_ctest3, CLF);        /* clear scsi offsets */
-       }
-
-       /*
-       **      Freeze controller to be able to read the messages.
-       */
+       };
 
-       if (DEBUG_FLAGS & DEBUG_FREEZE) {
-               unsigned char val;
-               for (i=0; i<0x60; i++) {
-                       switch (i%16) {
+       ncr_log_hard_error(np, sist, dstat);
 
-                       case 0:
-                               printf ("%s: reg[%d0]: ",
-                                       ncr_name(np),i/16);
-                               break;
-                       case 4:
-                       case 8:
-                       case 12:
-                               printf (" ");
-                               break;
-                       };
-                       val = INB_OFF(i);
-                       printf (" %x%x", val/16, val%16);
-                       if (i%16==15) printf (".\n");
-               }
+       printf ("%s: have to clear fifos.\n", ncr_name (np));
+       OUTB (nc_stest3, TE|CSF);
+       OUTONB (nc_ctest3, CLF);
 
-               del_timer(&np->timer);
+       if ((sist & (SGE)) ||
+               (dstat & (MDPE|BF|ABORT|IID))) {
+               ncr_start_reset(np, 2);
+               return;
+       };
 
-               printf ("%s: halted!\n", ncr_name(np));
-               /*
-               **      don't restart controller ...
-               */
-               OUTB (nc_istat,  SRST);
+       if (sist & HTH) {
+               printf ("%s: handshake timeout\n", ncr_name(np));
+               ncr_start_reset(np, 2);
                return;
        };
 
-#ifdef NCR_FREEZE
-       /*
-       **      Freeze system to be able to read the messages.
-       */
-       printf ("ncr: fatal error: system halted - press reset to reboot ...");
-       cli();
-       for (;;);
-#endif
+       if (sist & UDC) {
+               printf ("%s: unexpected disconnect\n", ncr_name(np));
+               if (INB (nc_scr1) != 0xff) {
+                       OUTB (nc_scr1, HS_UNEXPECTED);
+                       OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+               };
+               ncr_start_reset(np, 2);
+               return;
+       };
 
-       /*
-       **      sorry, have to kill ALL jobs ...
+       /*=========================================================
+       **      We just miss the cause of the interrupt. :(
+       **      Print a message. The timeout will do the real work.
+       **=========================================================
        */
-
-       ncr_start_reset(np, 2);
+       printf ("%s: unknown interrupt\n", ncr_name(np));
 }
 
 /*==========================================================
@@ -6501,6 +6461,70 @@ void ncr_int_sto (ncb_p np)
        np->disc = 1;
 }
 
+/*==========================================================
+**
+**     ncr chip exception handler for SCSI bus mode change
+**
+**==========================================================
+**
+**     I'm not quite sure of what is to be done in such a
+**     situation.
+**     For now,
+**     Reset the bus if some devices use too fast sync transfers.
+**     Otherwise, just try to renegotiate sync with targets. 
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_sbmc (ncb_p np)
+{
+       u_char scsi_mode = INB (nc_stest4) & SMODE;
+       int i;
+       int oversync;
+
+       printf("%s: SCSI bus mode change from %x to %x\n", ncr_name(np),
+               np->scsi_mode, scsi_mode);
+
+       if (scsi_mode == np->scsi_mode)
+               return 0;
+
+       np->scsi_mode = scsi_mode;
+       oversync = 0;
+       for (i = 0; i < MAX_TARGET; i++) {
+               tcb_p tp = &np->target[i];
+
+               if (np->ns_sync < 12 && tp->maxoffs && tp->usrsync < 12) {
+                       if (scsi_mode != SMODE_SE)
+                               ncr_negotiate(np, tp);
+                       else
+                               ++oversync;
+               }
+       }
+
+       if (oversync)
+               ncr_start_reset(np, 2);
+
+       return oversync;
+}
+
+/*==========================================================
+**
+**     ncr chip exception handler for SCSI parity error.
+**
+**==========================================================
+**
+**     SCSI parity errors are handled by the SCSI script.
+**     So, we just print some message.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_par (ncb_p np)
+{
+       printf("%s: SCSI parity error detected\n", ncr_name(np));
+       return 0;
+}
+
 /*==========================================================
 **
 **
@@ -6538,22 +6562,18 @@ static void ncr_int_ma (ncb_p np)
 
        /*
        **      Take into account dma fifo and various buffers and latches,
-       **      only if the interrupted phase in an OUTPUT phase.
+       **      only if the interrupted phase was DATA OUT.
        */
 
-       if ((cmd & 1) == 0) {
+       if ((cmd & 7) == 0) {
                u_char  ctest5, ss0, ss2;
                u_short delta;
 
-               if (!(INB(nc_dstat) & DFE)) {
-                       ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
-                       if (ctest5 & DFS)
-                               delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
-                       else
-                               delta=(INB (nc_dfifo) - rest) & 0x7f;
-               } else {
-                       delta = 0;
-               }
+               ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
+               if (ctest5 & DFS)
+                       delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
+               else
+                       delta=(INB (nc_dfifo) - rest) & 0x7f;
 
                /*
                **      The data in the dma fifo has not been transfered to
@@ -6582,9 +6602,10 @@ static void ncr_int_ma (ncb_p np)
        } else  {
                if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
                        printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
-               if (!(INB(nc_dstat) & DFE))
-                       printf("INPUT phase mismatch with DMA fifo not empty, P%x%x RL=%d\n",
-                               cmd&7, sbcl&7, rest);
+               if ((cmd & 7) != 1) {
+                       OUTONB (nc_ctest3, CLF );
+                       OUTB (nc_stest3, TE|CSF);
+               }
        }
 
        /*
@@ -6660,7 +6681,7 @@ static void ncr_int_ma (ncb_p np)
        };
 
        /*
-       **      if old phase not dataphase, leave here.
+       **      check cmd against assumed interrupted script command.
        */
 
        if (cmd != (vdsp[0] >> 24)) {
@@ -6670,6 +6691,18 @@ static void ncr_int_ma (ncb_p np)
                
                return;
        }
+
+#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+       if ((cmd & 7) == 1 && np->assert_atn) {
+               np->assert_atn = 0;
+               OUTONB(nc_socl, CATN);
+       }
+#endif
+
+       /*
+       **      if old phase not dataphase, leave here.
+       */
+
        if (cmd & 0x06) {
                PRINT_ADDR(cp->cmd);
                printf ("phase change %x-%x %d@%08x resid=%d.\n",
@@ -6712,7 +6745,10 @@ static void ncr_int_ma (ncb_p np)
        */
        np->profile.num_break++;
        OUTL (nc_temp, vtophys (newcmd));
-       OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+       if ((cmd & 7) == 0)
+               OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+       else
+               OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn));
 }
 
 /*==========================================================
@@ -6778,15 +6814,24 @@ void ncr_int_sir (ncb_p np)
        }
 
        switch (num) {
+               u_long endp;
        case SIR_DATA_IO_IS_OUT:
+       case SIR_DATA_IO_IS_IN:
 /*
-**     We did not guess the direction of transfer. We assumed DATA IN,
-**     but the the target drove DATA OUT.
-**     We have to patch the script context with DATA OUT context and 
-**     restart processing at data out script address.
-*/
-               cp->phys.header.savep   = NCB_SCRIPTH_PHYS (np, data_out);
-               cp->phys.header.goalp   = cp->phys.header.savep +20 +cp->segments*16;
+**     We did not guess the direction of transfer. We have to wait for 
+**     actual data direction driven by the target before setting 
+**     pointers. We must patch the global header too.
+*/
+               if (num == SIR_DATA_IO_IS_OUT) {
+                       endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+                       cp->phys.header.goalp = endp + 8;
+                       cp->phys.header.savep = endp - cp->segments*16;
+               } else {
+                       endp = NCB_SCRIPT_PHYS (np, data_in)  + MAX_SCATTER*16;
+                       cp->phys.header.goalp = endp + 8;
+                       cp->phys.header.savep = endp - cp->segments*16;
+               }
+
                cp->phys.header.lastp   = cp->phys.header.savep;
                np->header.savep        = cp->phys.header.savep;
                np->header.goalp        = cp->phys.header.goalp;
@@ -7276,6 +7321,7 @@ void ncr_int_sir (ncb_p np)
                        (unsigned) np->header.goalp);
                break;
 
+#if 0   /* This stuff does not work */
 /*--------------------------------------------------------------------
 **
 **     Processing of a "S_QUEUE_FULL" status.
@@ -7353,6 +7399,7 @@ void ncr_int_sir (ncb_p np)
                printf ("%s: queue empty.\n", ncr_name (np));
                np->script->start1[0] =  SCR_INT ^ IFFALSE (0);
                break;
+#endif   /* This stuff does not work */
        };
 
 out:
@@ -7362,7 +7409,7 @@ out:
 /*==========================================================
 **
 **
-**     Acquire a control block
+**     Aquire a control block
 **
 **
 **==========================================================
@@ -7496,10 +7543,10 @@ static  void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun)
                tp->jump_tcb.l_cmd   = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
                tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
 
-               tp->getscr[0] = SCR_COPY (1);
+               tp->getscr[0] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
                tp->getscr[1] = vtophys (&tp->sval);
                tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
-               tp->getscr[3] = SCR_COPY (1);
+               tp->getscr[3] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
                tp->getscr[4] = vtophys (&tp->wval);
                tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3);
 
@@ -7712,12 +7759,15 @@ static  int     ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
        int segment     = 0;
        int use_sg      = (int) cmd->use_sg;
 
+#if 0
        bzero (cp->phys.data, sizeof (cp->phys.data));
+#endif
        data            = cp->phys.data;
        cp->data_len    = 0;
 
        if (!use_sg) {
                if (cmd->request_bufflen) {
+                       data = &data[MAX_SCATTER - 1];
                        data[0].addr    = vtophys(cmd->request_buffer);
                        data[0].size    = cmd->request_bufflen;
                        cp->data_len    = data[0].size;
@@ -7727,6 +7777,7 @@ static    int     ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
        else if (use_sg <= MAX_SCATTER) {
                struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
 
+               data = &data[MAX_SCATTER - use_sg];
                while (segment < use_sg) {
                        data[segment].addr = vtophys(scatter[segment].address);
                        data[segment].size = scatter[segment].length;
@@ -7753,7 +7804,9 @@ static    int     ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
 */
 
 #ifndef NCR_IOMAPPED
+__initfunc(
 static int ncr_regtest (struct ncb* np)
+)
 {
        register volatile u_long data;
        /*
@@ -7777,7 +7830,9 @@ static int ncr_regtest (struct ncb* np)
 }
 #endif
 
+__initfunc(
 static int ncr_snooptest (struct ncb* np)
+)
 {
        u_long  ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0;
        int     i;
@@ -7871,7 +7926,7 @@ static int ncr_snooptest (struct ncb* np)
 **==========================================================
 */
 
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 
 /*
 **     Compute the difference in jiffies ticks.
@@ -7883,7 +7938,7 @@ static int ncr_snooptest (struct ncb* np)
 #define PROFILE  cp->phys.header.stamp
 static void ncb_profile (ncb_p np, ccb_p cp)
 {
-       int co, da, st, en, di, se, post,work,disc;
+       int co, st, en, di, se, post,work,disc;
        u_long diff;
 
        PROFILE.end = jiffies;
@@ -7891,9 +7946,6 @@ static    void ncb_profile (ncb_p np, ccb_p cp)
        st = ncr_delta (PROFILE.start,PROFILE.status);
        if (st<0) return;       /* status  not reached  */
 
-       da = ncr_delta (PROFILE.start,PROFILE.data);
-       if (da<0) return;       /* No data transfer phase */
-
        co = ncr_delta (PROFILE.start,PROFILE.command);
        if (co<0) return;       /* command not executed */
 
@@ -7930,7 +7982,7 @@ static    void ncb_profile (ncb_p np, ccb_p cp)
 }
 #undef PROFILE
 
-#endif /* SCSI_NCR_PROFILE */
+#endif /* SCSI_NCR_PROFILE_SUPPORT */
 
 /*==========================================================
 **
@@ -7991,7 +8043,7 @@ static u_long ncr_lookup(char * id)
 /*==========================================================
 **
 **     Determine the ncr's clock frequency.
-**     This is important for the negotiation
+**     This is essential for the negotiation
 **     of the synchronous transfer rate.
 **
 **==========================================================
@@ -7999,20 +8051,53 @@ static u_long ncr_lookup(char * id)
 **     Note: we have to return the correct value.
 **     THERE IS NO SAVE DEFAULT VALUE.
 **
-**     We assume that all NCR based boards are delivered
-**     with a 40Mhz clock. Because we have to divide
-**     by an integer value greater than 3, only clock
-**     frequencies of 40Mhz (/4) or 50MHz (/5) permit
-**     the FAST-SCSI rate of 10MHz.
+**     Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
+**     53C860 and 53C875 rev. 1 support fast20 transfers but 
+**     do not have a clock doubler and so are provided with a 
+**     80 MHz clock. All other fast20 boards incorporate a doubler 
+**     and so should be delivered with a 40 MHz clock.
+**     The future fast40 chips (895/895) use a 40 Mhz base clock 
+**     and provide a clock quadrupler (160 Mhz). The code below 
+**     tries to deal as cleverly as possible with all this stuff.
 **
 **----------------------------------------------------------
 */
 
+/*
+ *     Select NCR SCSI clock frequency
+ */
+static void ncr_selectclock(ncb_p np, u_char scntl3)
+{
+       if (np->multiplier < 2) {
+               OUTB(nc_scntl3, scntl3);
+               return;
+       }
+
+       if (bootverbose >= 2)
+               printf ("%s: enabling clock multiplier\n", ncr_name(np));
+
+       OUTB(nc_stest1, DBLEN);    /* Enable clock multiplier             */
+       if (np->multiplier > 2) {  /* Poll bit 5 of stest4 for quadrupler */
+               int i = 20;
+               while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
+                       DELAY(20);
+               if (!i)
+                       printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+       } else                  /* Wait 20 micro-seconds for doubler    */
+               DELAY(20);
+       OUTB(nc_stest3, HSC);           /* Halt the scsi clock          */
+       OUTB(nc_scntl3, scntl3);
+       OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier      */
+       OUTB(nc_stest3, 0x00);          /* Restart scsi clock           */
+}
+
+
 /*
  *     calculate NCR SCSI clock frequency (in KHz)
  */
-static unsigned
-ncrgetfreq (ncb_p np, int gen)
+__initfunc(
+static unsigned ncrgetfreq (ncb_p np, int gen)
+)
 {
        unsigned ms = 0;
 
@@ -8057,39 +8142,12 @@ ncrgetfreq (ncb_p np, int gen)
        return ms ? ((1 << gen) * 4340) / ms : 0;
 }
 
-/*
- *     Select NCR SCSI clock frequency
- */
-static void ncr_selectclock(ncb_p np, u_char scntl3)
-{
-       if (np->multiplier < 2) {
-               OUTB(nc_scntl3, scntl3);
-               return;
-       }
-
-       if (bootverbose >= 2)
-               printf ("%s: enabling clock multiplier\n", ncr_name(np));
-
-       OUTB(nc_stest1, DBLEN);    /* Enable clock multiplier             */
-       if (np->multiplier > 2) {  /* Poll bit 5 of stest4 for quadrupler */
-               int i = 20;
-               while (!(INB(nc_stest4) & 0x20) && --i > 0)
-                       DELAY(20);
-               if (!i)
-                       printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
-       } else                  /* Wait 20 micro-seconds for doubler    */
-               DELAY(20);
-       OUTB(nc_stest3, 0x20);          /* Halt the scsi clock          */
-       OUTB(nc_scntl3, scntl3);
-       OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier      */
-       OUTB(nc_stest3, 0x00);          /* Restart scsi clock           */
-}
-
-
 /*
  *     Get/probe NCR SCSI clock frequency
  */
+__initfunc(
 static void ncr_getclock (ncb_p np, int mult)
+)
 {
        unsigned char scntl3 = INB(nc_scntl3);
        unsigned char stest1 = INB(nc_stest1);
@@ -8151,56 +8209,12 @@ static void ncr_getclock (ncb_p np, int mult)
        np->ns_sync     = 25;
 
        if      (f1 >= 160000) {
-               if (driver_setup.ultra_scsi) np->ns_sync = 10;
-               np->rv_scntl3 = 7;
+               if      (np->features & _F_ULTRA2)      np->ns_sync = 10;
+               else if (np->features & _F_ULTRA)       np->ns_sync = 12;
        }
        else if (f1 >= 80000) {
-               if (driver_setup.ultra_scsi) np->ns_sync = 12;
-               np->rv_scntl3 = 5;
+               if (np->features & _F_ULTRA)            np->ns_sync = 12;
        }
-       else {
-               np->rv_scntl3 = 3;
-       }
-
-       if (bootverbose > 1) {
-               printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
-                       ncr_name(np), scntl3, np->rv_scntl3);
-       }
-}
-
-/*
-**     Save some features set by bios
-**
-**     DMODE   0xce
-**             0x02    burst op-code fetch
-**             0x04    enable read multiple
-**             0x08    enable read line
-**             0xc0    burst length 16/8/2
-**     DCNTL   0xa8
-**             0x08    totem pole irq
-**             0x20    enable pre-fetch
-**             0x80    enable cache line size
-**     CTEST3  0x01
-**             0x01    set write and invalidate
-**     CTEST4  0x80
-**             0x80    burst disabled
-**     CTEST5  0x24
-**             0x20    large dma fifo          (875 and 895 only)
-**             0x04    burst len 32/64/128     (875 and 895 only)
-**     GPCNTL          general purpose control register
-**     STEST2  0x20    differential mode
-*/
-
-static void ncr_save_bios_setting(ncb_p np)
-{
-       np->sv_scntl3   = INB(nc_scntl3) & 0x07;
-       np->sv_dmode    = INB(nc_dmode)  & 0xce;
-       np->sv_dcntl    = INB(nc_dcntl)  & 0xa8;
-       np->sv_ctest3   = INB(nc_ctest3) & 0x01;
-       np->sv_ctest4   = INB(nc_ctest4) & 0x80;
-       np->sv_ctest5   = INB(nc_ctest5) & 0x24;
-       np->sv_gpcntl   = INB(nc_gpcntl);
-       np->sv_stest2   = INB(nc_stest2) & 0x20;
 }
 
 /*===================== LINUX ENTRY POINTS SECTION ==========================*/
@@ -8224,8 +8238,11 @@ static void ncr_save_bios_setting(ncb_p np)
 ** ---------------------------------------------------------------------
 */
 
+__initfunc(
 void ncr53c8xx_setup(char *str, int *ints)
+)
 {
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
        char *cur = str;
        char *pv;
        int val;
@@ -8295,6 +8312,8 @@ void ncr53c8xx_setup(char *str, int *ints)
                        driver_setup.diff_support= val;
                else if (!strncmp(cur, "irqm:", 5))
                        driver_setup.irqm       = val;
+               else if (!strncmp(cur, "pcifix:", 7))
+                       driver_setup.pci_fix_up = val;
 
                else if (!strncmp(cur, "safe:", 5) && val)
                        memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
@@ -8302,34 +8321,11 @@ void ncr53c8xx_setup(char *str, int *ints)
                if ((cur = strchr(cur, ',')) != NULL)
                        ++cur;
        }
+#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
 }
 
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip,
-            uchar bus, uchar device_fn, int options);
-
-/*
-**   NCR53C8XX devices description table
-*/
-
-static struct {
-     ushort pci_device_id;
-     int chip;
-     int max_revision;
-     int min_revision;
-} pci_chip_ids[] = { 
-     {PCI_DEVICE_ID_NCR_53C810,   810, -1, -1}, 
-/*   {PCI_DEVICE_ID_NCR_53C810AP, 810, -1, -1}, */
-     {PCI_DEVICE_ID_NCR_53C815,   815, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C820,   820, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C825,   825, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C860,   860, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C875,   875, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C885,   885, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C895,   895, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C896,   896, -1, -1}
-};
-
-#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0]))
+static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit,
+            uchar bus, uchar device_fn);
 
 /*
 **   Linux entry point for NCR53C8XX devices detection routine.
@@ -8343,16 +8339,12 @@ static struct {
 **   Returns the number of boards successfully attached.
 */
 
-int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+__initfunc(
+static void ncr_print_driver_setup(void)
+)
 {
-     int i, j;
-     int count = 0;                    /* Number of boards detected */
-     uchar pci_bus, pci_device_fn;
-     short pci_index;  /* Device index to PCI BIOS calls */
-
 #define YesNo(y)       y ? 'y' : 'n'
-    if (bootverbose >= 2) {
-         printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
+       printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
                        YesNo(driver_setup.disconnection),
                        YesNo(driver_setup.special_features),
                        YesNo(driver_setup.ultra_scsi),
@@ -8361,7 +8353,7 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
                        driver_setup.burst_max,
                        YesNo(driver_setup.max_wide),
                        driver_setup.diff_support);
-         printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
+       printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
                        YesNo(driver_setup.master_parity),
                        YesNo(driver_setup.scsi_parity),
                        YesNo(driver_setup.force_sync_nego),
@@ -8370,10 +8362,30 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
                        YesNo(driver_setup.led_pin),
                        driver_setup.settle_delay,
                        driver_setup.irqm);
-   }
 #undef YesNo
+}
+
+/*
+**   NCR53C8XX devices description table and chip ids list.
+*/
+
+static ncr_chip        ncr_chip_table[] __initdata     = SCSI_NCR_CHIP_TABLE;
+static ushort  ncr_chip_ids[]   __initdata     = SCSI_NCR_CHIP_IDS;
 
-#ifdef SCSI_NCR_DEBUG
+__initfunc(
+int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+)
+{
+       int i, j;
+       int chips;
+       int count = 0;
+       uchar bus, device_fn;
+       short index;
+
+       if (bootverbose >= 2)
+               ncr_print_driver_setup();
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
        ncr_debug = driver_setup.debug;
 #endif
 
@@ -8384,21 +8396,21 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
 # endif
 #endif
 
-     if (pcibios_present()) {
-         for (j = 0; j < NPCI_CHIP_IDS; ++j) {
-              i = driver_setup.reverse_probe ? NPCI_CHIP_IDS-1 - j : j;
-              for (pci_index = 0;
-                   !pcibios_find_device(PCI_VENDOR_ID_NCR, 
-                                        pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, 
-                                        &pci_device_fn);
-                    ++pci_index)
-                   if (!ncr53c8xx_pci_init(tpnt, count, 0, pci_chip_ids[i].chip, 
-                             pci_bus, pci_device_fn, /* no options */ 0))
-                   ++count;
-        }
-     }
+       if (!pcibios_present())
+               return 0;
 
-     return count;
+       chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]);
+       for (j = 0; j < chips ; ++j) {
+               i = driver_setup.reverse_probe ? chips-1 - j : j;
+               for (index = 0; ; index++) {
+                       if (pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
+                                               index, &bus, &device_fn))
+                               break;
+                       if (!ncr53c8xx_pci_init(tpnt, count, bus, device_fn))
+                               ++count;
+               }
+       }
+       return count;
 }
 
 
@@ -8407,103 +8419,165 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
 **   try yo attach it.
 */
 
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip,
-                   uchar bus, uchar device_fn, int options)
+__initfunc(
+static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit,
+                             uchar bus, uchar device_fn)
+)
 {
-     ushort vendor_id, device_id, command;
+       ushort vendor_id, device_id, command;
+       uchar cache_line_size, latency_timer;
+       uchar irq, revision;
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-     uint base, io_port; 
+       uint base, io_port; 
 #else
-     ulong base, io_port; 
+       ulong base, io_port; 
 #endif
-     uchar irq, revision;
-     int error, expected_chip;
-     int expected_id = -1, max_revision = -1, min_revision = -1;
-     int i;
+       int i, error;
+       ncr_chip ncrchip, *chip;
 
-     printk("ncr53c8xx: at PCI bus %d, device %d, function %d\n",
-           bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
+       printk("ncr53c8xx: at PCI bus %d, device %d, function %d\n",
+               bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
+       /*
+        * Read info from the PCI config space
+        */
+       if (
+(error=pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id))    ||
+(error=pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id))    ||
+(error=pcibios_read_config_word( bus, device_fn, PCI_COMMAND, &command))               ||
+(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,&io_port)) || 
+(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base))   ||
+(error=pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION,&revision)) ||
+(error=pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq))     ||
+(error=pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, &cache_line_size)) ||
+(error=pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER, &latency_timer))
+       )
+               goto err_pcibios;
+
+       /*
+        *      Check if the chip is supported
+        */
+       chip = 0;
+       for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) {
+               if (device_id != ncr_chip_table[i].device_id)
+                       continue;
+               if (revision > ncr_chip_table[i].revision_id)
+                       continue;
+               chip = &ncrchip;
+               memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
+               chip->revision_id = revision;
+               break;
+       }
+       if (!chip) {
+               printk("ncr53c8xx: not initializing, device not supported\n");
+               return -1;
+       }
 
-     if (!pcibios_present()) {
-         printk("ncr53c8xx: not initializing due to lack of PCI BIOS,\n");
-         return -1;
-     }
+       /*
+        * Check availability of IO space, memory space and master capability.
+        */
+       if (command & PCI_COMMAND_IO) { 
+               if ((io_port & 3) != 1) {
+                       printk("ncr53c8xx: disabling I/O mapping since base address 0 (0x%x)\n"
+                               "           bits 0..1 indicate a non-IO mapping\n", (int) io_port);
+                       io_port = 0;
+               }
+               else
+                       io_port &= PCI_BASE_ADDRESS_IO_MASK;
+       }
+       else
+               io_port = 0;
 
-     if ((error = pcibios_read_config_word( bus, device_fn, PCI_VENDOR_ID,      &vendor_id)) ||
-        (error = pcibios_read_config_word( bus, device_fn, PCI_DEVICE_ID,      &device_id)) ||
-        (error = pcibios_read_config_word( bus, device_fn, PCI_COMMAND,        &command))   ||
-        (error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, &io_port))   || 
-        (error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base))      ||
-        (error = pcibios_read_config_byte (bus, device_fn, PCI_CLASS_REVISION, &revision))  ||
-        (error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE, &irq))) {
-         printk("ncr53c8xx: error %s not initializing due to error reading configuration space\n",
-                pcibios_strerror(error));
-         return -1;
-     }
+       if (command & PCI_COMMAND_MEMORY) {
+               if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+                       printk("ncr53c8xx: disabling memory mapping since base address 1\n"
+                               "            contains a non-memory mapping\n");
+                       base = 0;
+               }
+               else 
+                       base &= PCI_BASE_ADDRESS_MEM_MASK;
+       }
+       else
+               base = 0;
+       
+       if (!io_port && !base) {
+               printk("ncr53c8xx: not initializing, both I/O and memory mappings disabled\n");
+               return -1;
+       }
 
-     if (vendor_id != PCI_VENDOR_ID_NCR) {
-         printk("ncr53c8xx: not initializing, 0x%04x is not NCR vendor ID\n", (int) vendor_id);
-         return -1;
-     }
+       if (io_port && check_region (io_port, 128)) {
+               printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
+                       (int) io_port, (int) (io_port + 127));
+               return -1;
+       }
+       
+       if (!(command & PCI_COMMAND_MASTER)) {
+               printk("ncr53c8xx: not initializing, BUS MASTERING was disabled\n");
+               return -1;
+       }
 
+       /*
+        * Remove not wished features.
+        */
+       if (!driver_setup.special_features)
+               chip->features &= ~_F_SPECIAL_SET;
+       if (driver_setup.ultra_scsi < 2 && chip->features & _F_ULTRA2)
+               chip->features &= ~(_F_ULTRA2 | _F_ULTRA);
+       if (driver_setup.ultra_scsi < 1)
+               chip->features &= ~_F_ULTRA;
+       if (!driver_setup.max_wide)
+               chip->features &= ~_F_WIDE;
 
-     if (command & PCI_COMMAND_IO) { 
-         if ((io_port & 3) != 1) {
-              printk("ncr53c8xx : disabling I/O mapping since base address 0 (0x%x)\n"
-                     "            bits 0..1 indicate a non-IO mapping\n", (int) io_port);
-              io_port = 0;
-         }
-         else
-              io_port &= PCI_BASE_ADDRESS_IO_MASK;
-     }
-     else
-         io_port = 0;
-
-     if (command & PCI_COMMAND_MEMORY) {
-         if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
-              printk("ncr53c8xx: disabling memory mapping since base address 1\n"
-                     "            contains a non-memory mapping\n");
-              base = 0;
-         }
-         else 
-              base &= PCI_BASE_ADDRESS_MEM_MASK;
-     }
-     else
-         base = 0;
-       
-     if (!io_port && !base) {
-         printk("ncr53c8xx: not initializing, both I/O and memory mappings disabled\n");
-         return -1;
-     }
-       
-     if (!(command & PCI_COMMAND_MASTER)) {
-         printk ("ncr53c8xx: not initializing, BUS MASTERING was disabled\n");
-         return -1;
-     }
+       /*
+        * Try to fix up PCI config according to wished features.
+        */
+#ifdef __i386
+       if ((driver_setup.pci_fix_up & 1) &&
+           (chip->features & _F_CLSE) && cache_line_size == 0) {
+               extern char x86;
+               switch(x86) {
+               case 4: cache_line_size = 4; break;
+               case 5: cache_line_size = 8; break;
+               }
+               if (cache_line_size)
+                       error = pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size);
+               if (error)
+                       goto err_pcibios;
+               if (bootverbose)
+                       printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fix-up).\n", cache_line_size);
+       }
 
-     for (i = 0; i < NPCI_CHIP_IDS; ++i) {
-         if (device_id == pci_chip_ids[i].pci_device_id) {
-              max_revision  = pci_chip_ids[i].max_revision;
-              min_revision  = pci_chip_ids[i].min_revision;
-              expected_chip = pci_chip_ids[i].chip;
-         }
-         if (chip == pci_chip_ids[i].chip)
-              expected_id = pci_chip_ids[i].pci_device_id;
-     }
+       if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
+           (chip->features & _F_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+               command |= PCI_COMMAND_INVALIDATE;
+               error=pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+               if (error)
+                       goto err_pcibios;
+               if (bootverbose)
+                       printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fix-up).\n");
+       }
+#endif
+       /*
+        * Remove features that will not work
+        */
+       if ((chip->features & _F_CLSE) && cache_line_size == 0) {
+               chip->features &= ~_F_CACHE_SET;
+               printk("ncr53c8xx: PCI_CACHE_LINE_SIZE not set, features based on CACHE LINE SIZE not used.\n");
+       }
 
-     if (chip && device_id != expected_id) 
-         printk("ncr53c8xx: warning : device id of 0x%04x doesn't\n"
-                "            match expected 0x%04x\n",
-                 (unsigned int) device_id, (unsigned int) expected_id );
-    
-     if (io_port && check_region (io_port, 128)) {
-         printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
-                (int) io_port, (int) (io_port + 127));
-         return -1;
-     }
+       if ((chip->features & _F_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+               chip->features &= ~_F_WRIE;
+               printk("ncr53c8xx: PCI_COMMAND_INVALIDATE not set, WRITE AND INVALIDATE not used\n");
+       }
 
-     return ncr_attach (tpnt, unit, device_id, revision, chip, base, io_port, 
-                      (int) irq, bus, (uchar) device_fn);
+       /*
+        * Try to attach the controller
+        */
+       return ncr_attach (tpnt, unit, chip, base, io_port, (int) irq, 
+                       bus, (uchar) device_fn);
+err_pcibios:
+       printk("ncr53c8xx: error %s reading configuration space\n",
+               pcibios_strerror(error));
+       return -1;
 }
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
@@ -8527,7 +8601,7 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
                        device->queue_depth = 1;
 #endif
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
        device->id, device->lun, device->queue_depth);
 #endif
@@ -8543,19 +8617,19 @@ printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
 int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
      int sts;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx_queue_command\n");
 #endif
 
      if ((sts = ncr_queue_command(cmd, done)) != DID_OK) {
          cmd->result = ScsiResult(sts, 0);
          done(cmd);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : command not queued - result=%d\n", sts);
 #endif
           return sts;
      }
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : command successfully queued\n");
 #endif
      return sts;
@@ -8573,8 +8647,13 @@ static void ncr53c8xx_intr(int irq, struct pt_regs * regs)
 {
      struct Scsi_Host *host;
      struct host_data *host_data;
+#if 0
+     u_long flags;
+
+     save_flags(flags); cli();
+#endif
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : interrupt received\n");
 #endif
 
@@ -8583,12 +8662,20 @@ printk("ncr53c8xx : interrupt received\n");
               host_data = (struct host_data *) host->hostdata;
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 #   ifdef SCSI_NCR_SHARE_IRQ
-               if (dev_id == host_data->ncb)
+               if (dev_id == host_data->ncb) {
+#else
+               if (1) {
 #   endif
 #endif
-              ncr_intr(host_data->ncb);
+                    if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
+                   ncr_exception(host_data->ncb);
+                    if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
+               }
          }
      }
+#if 0
+     restore_flags(flags);
+#endif
 }
 
 /*
@@ -8696,7 +8783,7 @@ int ncr53c8xx_abort(Scsi_Cmnd *cmd)
 int ncr53c8xx_release(struct Scsi_Host *host)
 {
      struct host_data *host_data;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : release\n");
 #endif
 
@@ -8847,6 +8934,8 @@ static int guess_xfer_direction(int opcode)
 **=========================================================================
 */
 
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
+
 #define is_digit(c)    ((c) >= '0' && (c) <= '9')
 #define digit_to_bin(c)        ((c) - '0')
 #define is_space(c)    ((c) == ' ' || (c) == '\t')
@@ -8928,6 +9017,10 @@ static int ncr_user_command(ncb_p np, char *buffer, int length)
                uc->cmd = UC_SETFLAG;
        else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
                uc->cmd = UC_CLEARPROF;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+       else if ((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0)
+               uc->cmd = UC_DEBUG_ERROR_RECOVERY;
+#endif
        else
                arg_len = 0;
 
@@ -9028,13 +9121,30 @@ printf("ncr_user_command: data=%ld\n", uc->data);
                        ptr += arg_len; len -= arg_len;
                }
                break;
+#ifdef UC_DEBUG_ERROR_RECOVERY
+       case UC_DEBUG_ERROR_RECOVERY:
+               SKIP_SPACES(1);
+               if      ((arg_len = is_keyword(ptr, len, "sge")))
+                       uc->data = 1;
+               else if ((arg_len = is_keyword(ptr, len, "abort")))
+                       uc->data = 2;
+               else if ((arg_len = is_keyword(ptr, len, "reset")))
+                       uc->data = 3;
+               else if ((arg_len = is_keyword(ptr, len, "parity")))
+                       uc->data = 4;
+               else if ((arg_len = is_keyword(ptr, len, "none")))
+                       uc->data = 0;
+               else
+                       return -EINVAL;
+               ptr += arg_len; len -= arg_len;
+               break;
+#endif
        default:
                break;
        }
 
        if (len)
                return -EINVAL;
-#ifdef SCSI_NCR_USER_COMMAND
        else {
                long flags;
 
@@ -9042,10 +9152,13 @@ printf("ncr_user_command: data=%ld\n", uc->data);
                ncr_usercmd (np);
                restore_flags(flags);
        }
-#endif
        return length;
 }
 
+#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */
+
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
+
 struct info_str
 {
        char *buffer;
@@ -9104,7 +9217,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
        info.pos        = 0;
 
        copy_info(&info, "General information:\n");
-       copy_info(&info, "  Chip NCR53C%03d, ", np->chip);
+       copy_info(&info, "  Chip NCR53C%s, ",   np->chip_name);
        copy_info(&info, "device id 0x%x, ",    np->device_id);
        copy_info(&info, "revision id 0x%x\n",  np->revision_id);
 
@@ -9124,7 +9237,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
                copy_info(&info, "verbosity level %d\n", driver_setup.verbose);
        }
 
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
        copy_info(&info, "Profiling information:\n");
        copy_info(&info, "  %-12s = %lu\n", "num_trans",np->profile.num_trans);
        copy_info(&info, "  %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes);
@@ -9141,6 +9254,8 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
        return info.pos > info.offset? info.pos - info.offset : 0;
 }
 
+#endif /* SCSI_NCR_USER_INFO_SUPPORT */
+
 /*
 **     Entry point of the scsi proc fs of the driver.
 **     - func = 0 means read  (returns profile data)
@@ -9171,20 +9286,26 @@ printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
                return -EINVAL;
 
        if (func) {
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
                retv = ncr_user_command(ncb, buffer, length);
-#ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: retv=%d\n", retv);
+#else
+               retv = -EINVAL;
 #endif
        }
        else {
                if (start)
                        *start = buffer;
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
                retv = ncr_host_info(ncb, buffer, offset, length);
+#else
+               retv = -EINVAL;
+#endif
        }
 
        return retv;
 }
 
+
 /*=========================================================================
 **     End of proc file system stuff
 **=========================================================================
index 3c0c7fb03751b3bface38b06657c6a274f54436b..412c66a373fd7d83baea927b0d6ab7cbcd795733 100644 (file)
 /*
 **     Name and revision of the driver
 */
-#define SCSI_NCR_DRIVER_NAME           "ncr53c8xx - revision 1.18f"
-/*
-**     If SCSI_NCR_SETUP_SPECIAL_FEATURES is defined,
-**     the driver enables or not the following features according to chip id 
-**     revision id:
-**     DMODE   0xce
-**             0x02    burst op-code fetch
-**             0x04    enable read multiple
-**             0x08    enable read line
-**             0xc0    burst length 16/8/2
-**     DCNTL   0xa0
-**             0x20    enable pre-fetch
-**             0x80    enable cache line size
-**     CTEST3  0x01
-**             0x01    set write and invalidate
-**     CTEST4  0x80
-**             0x80    burst disabled
-**     CTEST5  0x24    (825a and 875 only)
-**             0x04    burst 128
-**             0x80    large dma fifo
-**
-**     If SCSI_NCR_TRUST_BIOS_SETTING is defined, the driver will use the 
-**     initial value of corresponding bit fields, assuming they have been 
-**     set by the SDMS BIOS.
-**     When Linux is booted from another O/S, these assertion is false and 
-**     the driver will not be able to guess it. 
-*/
-
-/*********** LINUX SPECIFIC SECTION ******************/
+#define SCSI_NCR_DRIVER_NAME           "ncr53c8xx - revision 2.1b"
 
 /*
 **     Check supported Linux versions
 #define LINUX_VERSION_CODE LinuxVersionCode(1,2,13)
 #endif
 
-#if !defined(VERSION)
-#define VERSION                ((LINUX_VERSION_CODE >> 16) & 0xff)
-#define PATCHLEVEL     ((LINUX_VERSION_CODE >> 8)  & 0xff)
-#define SUBLEVEL       ((LINUX_VERSION_CODE >> 0)  & 0xff)
-#endif
-
-#if    VERSION == 0 || VERSION > 3
-#      error Only Linux version 1 and probable 2 or 3 supported.
-#endif
-
-#if    VERSION == 1 && PATCHLEVEL == 2
-#      if      SUBLEVEL != 13
-#              error Only sublevel 13 of Linux 1.2 is supported.
-#      endif
-#endif
-
-#if    VERSION == 1 && PATCHLEVEL == 3
-#      if      SUBLEVEL < 45
-#              error Only sublevels >=45 of Linux 1.3 are supported.
-#      endif
-#endif
-
 /*
 **     Normal IO or memory mapped IO.
 **
 #      define SCSI_NCR_SHARE_IRQ
 #endif
 
+/*
+**     If you want a driver as small as possible, donnot define the 
+**     following options.
+*/
+
+#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+#define SCSI_NCR_DEBUG_INFO_SUPPORT
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
+#      define  SCSI_NCR_PROFILE_SUPPORT
+#      define  SCSI_NCR_USER_COMMAND_SUPPORT
+#      define  SCSI_NCR_USER_INFO_SUPPORT
+/* #   define  SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT */
+#endif
+
 /* ---------------------------------------------------------------------
 ** Take into account kernel configured parameters.
 ** Most of these options can be overridden at startup by a command line.
 #define        SCSI_NCR_SETUP_DEFAULT_SYNC     (10)
 #endif
 
-/*
- * Default sync to 0 will force asynchronous at startup
- */
-#ifdef CONFIG_SCSI_FORCE_ASYNCHRONOUS
-#undef SCSI_NCR_SETUP_DEFAULT_SYNC
-#define SCSI_NCR_SETUP_DEFAULT_SYNC    (255)
-#endif
-
 /*
  * Disallow disconnections at boot-up
  */
 #define SCSI_NCR_MAX_LUN       (1)
 #endif
 
-/*
-**     Initial setup.
-**     Can be overriden at startup by a command line.
-*/
-#define SCSI_NCR_DRIVER_SETUP                  \
-{                                              \
-       SCSI_NCR_SETUP_MASTER_PARITY,           \
-       SCSI_NCR_SETUP_SCSI_PARITY,             \
-       SCSI_NCR_SETUP_DISCONNECTION,           \
-       SCSI_NCR_SETUP_SPECIAL_FEATURES,        \
-       SCSI_NCR_SETUP_ULTRA_SCSI,              \
-       SCSI_NCR_SETUP_FORCE_SYNC_NEGO,         \
-       0,                                      \
-       1,                                      \
-       SCSI_NCR_SETUP_DEFAULT_TAGS,            \
-       SCSI_NCR_SETUP_DEFAULT_SYNC,            \
-       0x00,                                   \
-       7,                                      \
-       SCSI_NCR_SETUP_LED_PIN,                 \
-       1,                                      \
-       SCSI_NCR_SETUP_SETTLE_TIME,             \
-       SCSI_NCR_SETUP_DIFF_SUPPORT,            \
-       0                                       \
-}
-
-/*
-**     Boot fail safe setup.
-**     Override initial setup from boot command line:
-**     ncr53c8xx=safe:y
-*/
-#define SCSI_NCR_DRIVER_SAFE_SETUP             \
-{                                              \
-       0,                                      \
-       1,                                      \
-       0,                                      \
-       0,                                      \
-       0,                                      \
-       0,                                      \
-       0,                                      \
-       2,                                      \
-       0,                                      \
-       255,                                    \
-       0x00,                                   \
-       255,                                    \
-       0,                                      \
-       0,                                      \
-       10,                                     \
-       1,                                      \
-       1                                       \
-}
-
 /*
 **     Define Scsi_Host_Template parameters
 **
@@ -398,6 +302,198 @@ int ncr53c8xx_release(struct Scsi_Host *);
 
 #ifndef HOSTS_C
 
+/*
+**     NCR53C8XX Device Ids
+*/
+
+#ifndef PCI_DEVICE_ID_NCR_53C810
+#define PCI_DEVICE_ID_NCR_53C810 1
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C810AP
+#define PCI_DEVICE_ID_NCR_53C810AP 5
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C815
+#define PCI_DEVICE_ID_NCR_53C815 4
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C820
+#define PCI_DEVICE_ID_NCR_53C820 2
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C825
+#define PCI_DEVICE_ID_NCR_53C825 3
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C860
+#define PCI_DEVICE_ID_NCR_53C860 6
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875
+#define PCI_DEVICE_ID_NCR_53C875 0xf
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875J
+#define PCI_DEVICE_ID_NCR_53C875J 0x8f
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C885
+#define PCI_DEVICE_ID_NCR_53C885 0xd
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C895
+#define PCI_DEVICE_ID_NCR_53C895 0xc
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C896
+#define PCI_DEVICE_ID_NCR_53C896 0xb
+#endif
+
+/*
+**   NCR53C8XX devices features table.
+*/
+typedef struct {
+       unsigned short  device_id;
+       unsigned short  revision_id;
+       char    *name;
+       unsigned char   burst_max;
+       unsigned char   offset_max;
+       unsigned char   nr_divisor;
+       unsigned int    features;
+#define _F_LED0                (1<<0)
+#define _F_WIDE                (1<<1)
+#define _F_ULTRA       (1<<2)
+#define _F_ULTRA2      (1<<3)
+#define _F_DBLR                (1<<4)
+#define _F_QUAD                (1<<5)
+#define _F_ERL         (1<<6)
+#define _F_CLSE                (1<<7)
+#define _F_WRIE                (1<<8)
+#define _F_ERMP                (1<<9)
+#define _F_BOF         (1<<10)
+#define _F_DFS         (1<<11)
+#define _F_PFEN                (1<<12)
+#define _F_LDSTR       (1<<13)
+#define _F_RAM         (1<<14)
+#define _F_CLK80       (1<<15)
+#define _F_CACHE_SET   (_F_ERL|_F_CLSE|_F_WRIE|_F_ERMP)
+#define _F_SCSI_SET    (_F_WIDE|_F_ULTRA|_F_ULTRA2|_F_DBLR|_F_QUAD|F_CLK80)
+#define _F_SPECIAL_SET (_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM)
+} ncr_chip;
+
+#define SCSI_NCR_CHIP_TABLE                                            \
+{                                                                      \
+ {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810",  4,  8, 4,                    \
+ _F_ERL}                                                               \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4,  8, 4,                    \
+ _F_CACHE_SET|_F_LDSTR|_F_PFEN|_F_BOF}                                 \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C815, 0xff, "815",  4,  8, 4,                    \
+ _F_ERL|_F_BOF}                                                                \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C820, 0xff, "820",  4,  8, 4,                    \
+ _F_WIDE|_F_ERL}                                                       \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825",  4,  8, 4,                    \
+ _F_WIDE|_F_ERL|_F_BOF}                                                        \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 7,  8, 4,                    \
+ _F_WIDE|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}           \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C860, 0xff, "860",  4,  8, 5,                    \
+ _F_WIDE|_F_ULTRA|_F_CLK80|_F_CACHE_SET|_F_BOF|_F_LDSTR|_F_PFEN|_F_RAM}        \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  7, 16, 5,                    \
+ _F_WIDE|_F_ULTRA|_F_CLK80|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM} \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875",  7, 16, 5,                    \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}  \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J",  7, 16, 5,                  \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}  \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885",  7, 16, 5,                    \
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}  \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C895, 0xff, "895",  7, 31, 7,                    \
+ _F_WIDE|_F_ULTRA|_F_ULTRA2|_F_QUAD|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}        \
+ ,                                                                     \
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  7, 31, 7,                    \
+ _F_WIDE|_F_ULTRA|_F_ULTRA2|_F_QUAD|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}        \
+}
+
+/*
+ * List of supported NCR chip ids
+ */
+#define SCSI_NCR_CHIP_IDS              \
+{                                      \
+       PCI_DEVICE_ID_NCR_53C810,       \
+       PCI_DEVICE_ID_NCR_53C815,       \
+       PCI_DEVICE_ID_NCR_53C820,       \
+       PCI_DEVICE_ID_NCR_53C825,       \
+       PCI_DEVICE_ID_NCR_53C860,       \
+       PCI_DEVICE_ID_NCR_53C875,       \
+       PCI_DEVICE_ID_NCR_53C875J,      \
+       PCI_DEVICE_ID_NCR_53C885,       \
+       PCI_DEVICE_ID_NCR_53C895,       \
+       PCI_DEVICE_ID_NCR_53C896        \
+}
+
+/*
+**     Initial setup.
+**     Can be overriden at startup by a command line.
+*/
+#define SCSI_NCR_DRIVER_SETUP                  \
+{                                              \
+       SCSI_NCR_SETUP_MASTER_PARITY,           \
+       SCSI_NCR_SETUP_SCSI_PARITY,             \
+       SCSI_NCR_SETUP_DISCONNECTION,           \
+       SCSI_NCR_SETUP_SPECIAL_FEATURES,        \
+       SCSI_NCR_SETUP_ULTRA_SCSI,              \
+       SCSI_NCR_SETUP_FORCE_SYNC_NEGO,         \
+       0,                                      \
+       0,                                      \
+       1,                                      \
+       SCSI_NCR_SETUP_DEFAULT_TAGS,            \
+       SCSI_NCR_SETUP_DEFAULT_SYNC,            \
+       0x00,                                   \
+       7,                                      \
+       SCSI_NCR_SETUP_LED_PIN,                 \
+       1,                                      \
+       SCSI_NCR_SETUP_SETTLE_TIME,             \
+       SCSI_NCR_SETUP_DIFF_SUPPORT,            \
+       0                                       \
+}
+
+/*
+**     Boot fail safe setup.
+**     Override initial setup from boot command line:
+**     ncr53c8xx=safe:y
+*/
+#define SCSI_NCR_DRIVER_SAFE_SETUP             \
+{                                              \
+       0,                                      \
+       1,                                      \
+       0,                                      \
+       0,                                      \
+       0,                                      \
+       0,                                      \
+       0,                                      \
+       0,                                      \
+       2,                                      \
+       0,                                      \
+       255,                                    \
+       0x00,                                   \
+       255,                                    \
+       0,                                      \
+       0,                                      \
+       10,                                     \
+       1,                                      \
+       1                                       \
+}
+
 /*
 **     Define the table of target capabilities by host and target
 **
@@ -486,50 +582,6 @@ int ncr53c8xx_release(struct Scsi_Host *);
 #endif
 #endif
 
-/*
-**     NCR53C8XX Device Ids
-*/
-
-#ifndef PCI_DEVICE_ID_NCR_53C810
-#define PCI_DEVICE_ID_NCR_53C810 1
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C810AP
-#define PCI_DEVICE_ID_NCR_53C810AP 5
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C815
-#define PCI_DEVICE_ID_NCR_53C815 4
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C820
-#define PCI_DEVICE_ID_NCR_53C820 2
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C825
-#define PCI_DEVICE_ID_NCR_53C825 3
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C860
-#define PCI_DEVICE_ID_NCR_53C860 6
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C875
-#define PCI_DEVICE_ID_NCR_53C875 0xf
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C885
-#define PCI_DEVICE_ID_NCR_53C885 0xd
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C895
-#define PCI_DEVICE_ID_NCR_53C895 0xc
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C896
-#define PCI_DEVICE_ID_NCR_53C896 0xb
-#endif
-
 /**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
 
 /*-----------------------------------------------------------------
@@ -608,6 +660,7 @@ struct ncr_reg {
         #define   ILF1    0x80  /* sta: data in SIDL register msb[W]*/
         #define   ORF1    0x40  /* sta: data in SODR register msb[W]*/
         #define   OLF1    0x20  /* sta: data in SODL register msb[W]*/
+        #define   DM      0x04  /* sta: DIFFSENS mismatch (895/6 only) */
         #define   LDSC    0x02  /* sta: disconnect & reconnect      */
 
 /*10*/  u_int32    nc_dsa;     /* --> Base page                    */
@@ -680,6 +733,7 @@ struct ncr_reg {
 
 /*40*/  u_short   nc_sien;     /* -->: interrupt enable            */
 /*42*/  u_short   nc_sist;     /* <--: interrupt status            */
+        #define   SBMC    0x1000/* sta: SCSI Bus Mode Change (895/6 only) */
         #define   STO     0x0400/* sta: timeout (select)            */
         #define   GEN     0x0200/* sta: timeout (general)           */
         #define   HTH     0x0100/* sta: timeout (handshake)         */
@@ -713,10 +767,17 @@ struct ncr_reg {
 
 /*4f*/  u_char    nc_stest3;
        #define   TE     0x80   /* c: tolerAnt enable */
+       #define   HSC    0x20   /* c: Halt SCSI Clock */
        #define   CSF    0x02   /* c: clear scsi fifo */
 
 /*50*/  u_short   nc_sidl;     /* Lowlevel: latched from scsi data */
 /*52*/  u_char    nc_stest4;
+       #define   SMODE  0xc0   /* SCSI bus mode      (895/6 only) */
+       #define    SMODE_HVD 0x40       /* High Voltage Differential       */
+       #define    SMODE_SE  0x80       /* Single Ended                    */
+       #define    SMODE_LVD 0xc0       /* Low Voltage Differential        */
+       #define   LCKFRQ 0x20   /* Frequency Lock (895/6 only)     */
+
 /*53*/ u_char    nc_53_;
 /*54*/  u_short   nc_sodl;     /* Lowlevel: data out to scsi data  */
 /*56*/  u_short   nc_56_;
@@ -870,10 +931,18 @@ struct scr_tblsel {
 **     << source_address >>
 **     << destination_address >>
 **
+**     SCR_COPY   sets the NO FLUSH option by default.
+**     SCR_COPY_F does not set this option.
+**
+**     For chips which do not support this option,
+**     ncr_copy_and_bind() will remove this bit.
 **-----------------------------------------------------------
 */
 
-#define SCR_COPY(n) (0xc0000000 | (n))
+#define SCR_NO_FLUSH 0x01000000
+
+#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
+#define SCR_COPY_F(n) (0xc0000000 | (n))
 
 /*-----------------------------------------------------------
 **
@@ -979,6 +1048,7 @@ struct scr_tblsel {
 **-----------------------------------------------------------
 */
 
+#define SCR_NO_OP        0x80000000
 #define SCR_JUMP        0x80080000
 #define SCR_JUMPR       0x80880000
 #define SCR_CALL        0x88080000
index aca31e7c732af661b9b5546f0ad19b75e2e6d2d0..83c21c20bb3ceeba62bd270f5c392560f17a8515 100644 (file)
@@ -11,6 +11,9 @@
  * 
  * generic command parser provided by: 
  * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
+ *
+ * generic_proc_info() support of xxxx_info() by:
+ * Michael A. Griffith <grif@acm.org>
  */
 
 /*
@@ -48,7 +51,9 @@ struct scsi_dir {
  * Used if the driver currently has no own support for /proc/scsi
  */
 int generic_proc_info(char *buffer, char **start, off_t offset, 
-                    int length, int inode, int inout)
+                    int length, int inode, int inout, 
+                     const char *(*info)(struct Scsi_Host *),
+                     struct Scsi_Host *sh)
 {
     int len, pos, begin;
 
@@ -56,8 +61,13 @@ int generic_proc_info(char *buffer, char **start, off_t offset,
        return(-ENOSYS);  /* This is a no-op */
     
     begin = 0;
-    pos = len = sprintf(buffer, 
-                       "The driver does not yet support the proc-fs\n");
+    if (info && sh) {
+          pos = len = sprintf(buffer, "%s\n", info(sh));
+    }
+    else {
+      pos = len = sprintf(buffer, 
+                          "The driver does not yet support the proc-fs\n");
+    }
     if(pos < offset) {
        len = 0;
        begin = pos;
@@ -91,7 +101,9 @@ extern int dispatch_scsi_info(int ino, char *buffer, char **start,
         if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
             if(hpnt->hostt->proc_info == NULL)
                 return generic_proc_info(buffer, start, offset, length, 
-                                         hpnt->host_no, func);
+                                         hpnt->host_no, func,
+                                         hpnt->hostt->info,
+                                         hpnt);
             else
                 return(hpnt->hostt->proc_info(buffer, start, offset, 
                                               length, hpnt->host_no, func));
index 73bff45af2cc75c1652e7b4fc1886ecb47f05194..e9c411e48b6a5f975b4fd842923c61d34bd510f5 100644 (file)
@@ -564,36 +564,6 @@ const char *seagate_st0x_info (struct Scsi_Host *shpnt)
   return buffer;
 }
 
-int seagate_st0x_proc_info (char *buffer, char **start, off_t offset,
-                            int length, int hostno, int inout)
-{
-  const char *info = seagate_st0x_info (NULL);
-  int len;
-  int pos;
-  int begin;
-
-  if (inout)
-    return (-ENOSYS);
-
-  begin = 0;
-  strcpy (buffer, info);
-  strcat (buffer, "\n");
-
-  pos = len = strlen (buffer);
-
-  if (pos < offset)
-  {
-    len = 0;
-    begin = pos;
-  }
-
-  *start = buffer + (offset - begin);
-  len -= (offset - begin);
-  if (len > length)
-    len = length;
-  return (len);
-}
-
 /*
  * These are our saved pointers for the outstanding command that is
  * waiting for a reconnect
index 7d677e5ea97ac2716d7cbbf1a1e0f18007a7d63c..f339ea6128a57c91a453d37ac48a35339d443cf7 100644 (file)
@@ -19,7 +19,6 @@ int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int seagate_st0x_abort(Scsi_Cmnd *);
 const char *seagate_st0x_info(struct Scsi_Host *);
 int seagate_st0x_reset(Scsi_Cmnd *, unsigned int); 
-int seagate_st0x_proc_info(char *,char **,off_t,int,int,int);
 
 #ifndef NULL
        #define NULL 0
@@ -28,7 +27,7 @@ int seagate_st0x_proc_info(char *,char **,off_t,int,int,int);
 #include <linux/kdev_t.h>
 int seagate_st0x_biosparam(Disk *, kdev_t, int*);
 
-#define SEAGATE_ST0X  {  NULL, NULL, NULL, seagate_st0x_proc_info, \
+#define SEAGATE_ST0X  {  NULL, NULL, NULL, NULL, \
                         NULL, seagate_st0x_detect,     \
                         NULL,                                          \
                         seagate_st0x_info, seagate_st0x_command,       \
index 658bbdaf1f76c737bb56a7d1796ca2cf00f9f390..a7382db4c5e5c90c08925927ba892e1c1ef52802 100644 (file)
@@ -86,7 +86,7 @@ affs_free_block(struct super_block *sb, s32 block)
                        return;
                }
        }
-       if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
+       if (test_and_set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
                affs_warning(sb,"affs_free_block","Trying to free block %d which is already free",
                                block);
        else {
@@ -138,7 +138,7 @@ found:
        zone->z_start = i;
        w   = ~htonl(bm[i]);
        fb  = find_first_zero_bit(&w,32);
-       if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+       if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
                unlock_super(sb);
                affs_warning(sb,"balloc","Empty block disappeared somehow");
                goto repeat;
@@ -153,7 +153,7 @@ found:
                        fb = find_next_zero_bit(&w,32,fb);
                        if (fb > 31)
                                break;
-                       if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+                       if (!test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
                                affs_warning(sb,"balloc","Empty block disappeared somehow");
                                break;
                        }
index 6b59088446bbb6e0ab5840f5b8c8712aa01c2c81..a4be4e885d3095a3fdcd45b57e7260f43f0453aa 100644 (file)
@@ -1159,7 +1159,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
                set_fs(fs);
 
                len = current->mm->arg_end - current->mm->arg_start;
-               len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
+               if (len >= ELF_PRARGSZ)
+                       len = ELF_PRARGSZ-1;
                copy_from_user(&psinfo.pr_psargs,
                              (const char *)current->mm->arg_start, len);
                for(i = 0; i < len; i++)
index 8d9ce9d969b00f8e2752cc0d6cacefcbcf8f52c6..708198a00af521dd9e2175eae1847c90b9788881 100644 (file)
@@ -138,13 +138,7 @@ static int parse_options(char *options, struct iso9660_options * popt)
                          !strcmp(this_char,"uid") ||
                          !strcmp(this_char,"gid"))) {
                  char * vpnt = value;
-                 unsigned int ivalue;
-                 ivalue = 0;
-                 while(*vpnt){
-                   if(*vpnt <  '0' || *vpnt > '9') break;
-                   ivalue = ivalue * 10 + (*vpnt - '0');
-                   vpnt++;
-                 }
+                 unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
                  if (*vpnt) return 0;
                  switch(*this_char) {
                  case 'b':
index 3aa53089747f431eeba6f8481f318407264fc380..a3590ea6493ba40eaae042b415bd20136273a138 100644 (file)
  *
  *  Some adaptations for NFS support.
  *  Olaf Kirch (okir@monad.swb.de), Dec 1996,
+ *
+ *  Fixed /proc/locks interface so that we can't overrun the buffer we are handed.
+ *  Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997.
  */
 
 #include <linux/malloc.h>
@@ -132,7 +135,7 @@ static int posix_locks_deadlock(struct file_lock *caller,
 static struct file_lock *locks_alloc_lock(struct file_lock *fl);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
 static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait);
-static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx);
+static char *lock_get_status(struct file_lock *fl, int id, char *pfx);
 
 static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter);
 static void locks_delete_block(struct file_lock *blocker, struct file_lock *waiter);
@@ -227,6 +230,7 @@ void
 posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
 {
        locks_insert_block(blocker, waiter);
+       return;
 }
 
 void
@@ -234,6 +238,7 @@ posix_unblock_lock(struct file_lock *waiter)
 {
        if (waiter->fl_prevblock)
                locks_delete_block(waiter->fl_prevblock, waiter);
+       return;
 }
 
 /* Wake up processes blocked waiting for blocker.
@@ -269,20 +274,20 @@ asmlinkage int sys_flock(unsigned int fd, unsigned int cmd)
 {
        struct file_lock file_lock;
        struct file *filp;
-       int err;
+       int error;
 
        lock_kernel();
        if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
-               err = -EBADF;
+               error = -EBADF;
        else if (!flock_make_lock(filp, &file_lock, cmd))
-               err = -EINVAL;
+               error = -EINVAL;
        else if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
-               err = -EBADF;
+               error = -EBADF;
        else
-               err = flock_lock_file(filp, &file_lock,
-                                     (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+               error = flock_lock_file(filp, &file_lock,
+                                       (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
        unlock_kernel();
-       return err;
+       return (error);
 }
 
 /* Report the first existing lock that would conflict with l.
@@ -298,7 +303,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
        if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
                return (-EBADF);
        if (copy_from_user(&flock, l, sizeof(flock)))
-               return -EFAULT;         
+               return (-EFAULT);
 
        if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
                return (-EINVAL);
@@ -308,9 +313,9 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
 
        if (filp->f_op->lock) {
                error = filp->f_op->lock(filp->f_inode, filp,
-                                       F_GETLK, &file_lock);
+                                        F_GETLK, &file_lock);
                if (error < 0)
-                       return error;
+                       return (error);
                fl = &file_lock;
        } else {
                fl = posix_test_lock(filp, &file_lock);
@@ -323,12 +328,12 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
                        fl->fl_end - fl->fl_start + 1;
                flock.l_whence = 0;
                flock.l_type = fl->fl_type;
-               return copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0; 
+               return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
        } else {
                flock.l_type = F_UNLCK;
        }
   
-       return copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0; 
+       return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
 }
 
 /* Apply the lock described by l to an open file descriptor.
@@ -366,7 +371,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
        }
 
        if (copy_from_user(&flock, l, sizeof(flock)))
-               return -EFAULT;         
+               return (-EFAULT);
        if (!posix_make_lock(filp, &file_lock, &flock))
                return (-EINVAL);
        
@@ -399,13 +404,13 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
                break;
 #endif
        default:
-               return -EINVAL;
+               return (-EINVAL);
        }
 
        if (filp->f_op->lock != NULL) {
                error = filp->f_op->lock(filp->f_inode, filp, cmd, &file_lock);
                if (error < 0)
-                       return error;
+                       return (error);
        }
 
        return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
@@ -457,7 +462,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
                        break;
        }
 
-       return cfl;
+       return (cfl);
 }
 
 int locks_verify_locked(struct inode *inode)
@@ -1044,16 +1049,18 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
 }
 
 
-static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx)
+static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
 {
+       static char temp[129];
+       char *p = temp;
        struct inode *inode;
 
        inode = fl->fl_file->f_inode;
 
        p += sprintf(p, "%d:%s ", id, pfx);
        if (fl->fl_flags & FL_POSIX) {
-               p += sprintf(p, "%s %s ",
-                            (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX",
+               p += sprintf(p, "%6s %s ",
+                            (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
                             (IS_MANDLOCK(inode) &&
                              (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
                             "MANDATORY" : "ADVISORY ");
@@ -1066,28 +1073,68 @@ static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx)
                     fl->fl_pid,
                     kdevname(inode->i_dev), inode->i_ino, fl->fl_start,
                     fl->fl_end);
-       p += sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
-                    (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
-                    (long)fl->fl_next, (long)fl->fl_nextblock);
-       return (p);
+       sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
+               (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
+               (long)fl->fl_next, (long)fl->fl_nextblock);
+       return (temp);
 }
 
-int get_locks_status(char *buf)
+static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
+                                  off_t offset, int length)
+{
+       int i;
+
+       i = pos - offset;
+       if (i > 0) {
+               if (i >= length) {
+                       i = len + length - i;
+                       memcpy(*q, p, i);
+                       *q += i;
+                       return (0);
+               }
+               if (i < len) {
+                       p += len - i;
+               }
+               else
+                       i = len;
+               memcpy(*q, p, i);
+               *q += i;
+       }
+       
+       return (1);
+}
+
+int get_locks_status(char *buffer, char **start, off_t offset, int length)
 {
        struct file_lock *fl;
        struct file_lock *bfl;
        char *p;
+       char *q = buffer;
        int i;
+       int len;
+       off_t pos = 0;
 
-       p = buf;
        for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
-               p = lock_get_status(fl, p, i, "");
+               p = lock_get_status(fl, i, "");
+               len = strlen(p);
+               pos += len;
+               if (!copy_lock_status(p, &q, pos, len, offset, length))
+                       goto done;
                if ((bfl = fl->fl_nextblock) == NULL)
                        continue;
                do {
-                       p = lock_get_status(bfl, p, i, " ->");
+                       p = lock_get_status(bfl, i, " ->");
+                       len = strlen(p);
+                       pos += len;
+                       if (!copy_lock_status(p, &q, pos, len, offset, length))
+                               goto done;
                } while ((bfl = bfl->fl_nextblock) != fl);
        }
-       return (p - buf);
+done:
+       if (q != buffer)
+               *start = buffer;
+       return (q - buffer);
 }
 
+
+
index 18b71ee2fcb2120e51166a51b3def6e595436d15..3c17b6eec20697cee7086549de383e3d57679f67 100644 (file)
@@ -130,9 +130,9 @@ nfs_unlock_page(struct page *page)
 
 #ifdef CONFIG_NFS_SWAP
        /* async swap-out support */
-       if (clear_bit(PG_decr_after, &page->flags))
+       if (test_and_clear_bit(PG_decr_after, &page->flags))
                atomic_dec(&page->count);
-       if (clear_bit(PG_swap_unlock_after, &page->flags))
+       if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
                swap_after_unlock_page(page->swap_unlock_entry);
 #endif
 }
index 153c09f770d9d6a13e299cf9ea94eed9d65625a6..37ccfdbe7f753c8ab39f5be3ccfa9b5f77cc4708 100644 (file)
@@ -1019,7 +1019,7 @@ extern int get_cpuinfo(char *);
 extern int get_pci_list(char*);
 extern int get_md_status (char *);
 extern int get_rtc_status (char *);
-extern int get_locks_status (char *);
+extern int get_locks_status (char *, char **, off_t, int);
 extern int get_swaparea_info (char *);
 #ifdef __SMP_PROF__
 extern int get_smp_prof_list(char *);
@@ -1106,7 +1106,7 @@ static long get_root_array(char * page, int type, char **start,
                        return get_rtc_status(page);
 #endif
                case PROC_LOCKS:
-                       return get_locks_status(page);
+                       return get_locks_status(page, start, offset, length);
 #ifdef CONFIG_ZORRO
                case PROC_ZORRO:
                        return zorro_get_list(page);
index 55d52cad5d9d178b5ec6a95dbe46bb898bd745a5..f25b16b3834ede4be5e13affd3242ed87682c87d 100644 (file)
@@ -285,10 +285,10 @@ int mem_mmap(struct inode * inode, struct file * file,
                        return -ENOMEM;
 
                if (!pte_present(*src_table))
-                       do_no_page(tsk, src_vma, stmp, 1);
+                       handle_mm_fault(src_vma, stmp, 1);
 
                if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
-                       do_wp_page(tsk, src_vma, stmp, 1);
+                       handle_mm_fault(src_vma, stmp, 1);
 
                set_pte(src_table, pte_mkdirty(*src_table));
                set_pte(dest_table, *src_table);
index 4b7e0242da75fdb5b510948287fdd8ed382cc9b4..a38477426df8cacad292adde1c6342423791299a 100644 (file)
@@ -108,7 +108,7 @@ l1:
                lock->previous = (unsigned long) &&l1;
 }
 
-#define spin_trylock(lock) (!set_bit(0,(lock)))
+#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
 
 #define spin_lock_irq(lock) \
        do { __cli(); spin_lock(lock); } while (0)
index bdaad9b354439dcc9bbf43eb07e7d19f3cff3ffd..0ceef9108feac1a13c981813373aa1d6fad166e2 100644 (file)
@@ -58,7 +58,6 @@ static inline int hardirq_trylock(int cpu)
                return 0;
        }
        ++local_irq_count[cpu];
-       __sti();
        return 1;
 }
 
index 4395dfce026163986adbc306e90aaca2bbbd5906..255880b6157e65bfeb611ea7378246fb76635172 100644 (file)
@@ -81,48 +81,28 @@ static inline int waking_non_zero(struct semaphore *sem)
  * "down_failed" is a special asm handler that calls the C
  * routine that actually waits. See arch/i386/lib/semaphore.S
  */
-extern inline void down(struct semaphore * sem)
+extern inline void do_down(struct semaphore * sem, void (*failed)(void))
 {
        __asm__ __volatile__(
                "# atomic down operation\n\t"
-               "movl $1f,%%eax\n\t"
 #ifdef __SMP__
                "lock ; "
 #endif
                "decl 0(%0)\n\t"
-               "js " SYMBOL_NAME_STR(__down_failed)
-               "\n1:"
+               "js 2f\n"
+               "1:\n"
+               ".section .text.lock,\"ax\"\n"
+               "2:\tpushl $1b\n\t"
+               "jmp %1\n"
+               ".previous"
                :/* no outputs */
-               :"c" (sem)
-               :"ax","memory");
-}
-
-/*
- * This version waits in interruptible state so that the waiting
- * process can be killed.  The down_failed_interruptible routine
- * returns negative for signalled and zero for semaphore acquired.
- */
-extern inline int down_interruptible(struct semaphore * sem)
-{
-       int     ret;
-
-       __asm__ __volatile__(
-               "# atomic interruptible down operation\n\t"
-               "movl $1f,%0\n\t"
-#ifdef __SMP__
-               "lock ; "
-#endif
-               "decl 0(%1)\n\t"
-               "js " SYMBOL_NAME_STR(__down_failed_interruptible) "\n\t"
-               "xorl %0,%0"
-               "\n1:"
-               :"=a" (ret)
-               :"c" (sem)
+               :"c" (sem), "m" (*(unsigned long *)failed)
                :"memory");
-
-       return ret;
 }
 
+#define down(sem) do_down((sem),__down_failed)
+#define down_interruptible(sem) do_down((sem),__down_failed_interruptible)
+
 /*
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
@@ -133,16 +113,19 @@ extern inline void up(struct semaphore * sem)
 {
        __asm__ __volatile__(
                "# atomic up operation\n\t"
-               "movl $1f,%%eax\n\t"
 #ifdef __SMP__
                "lock ; "
 #endif
                "incl 0(%0)\n\t"
-               "jle " SYMBOL_NAME_STR(__up_wakeup)
-               "\n1:"
+               "jle 2f\n"
+               "1:\n"
+               ".section .text.lock,\"ax\"\n"
+               "2:\tpushl $1b\n\t"
+               "jmp %1\n"
+               ".previous"
                :/* no outputs */
-               :"c" (sem)
-               :"ax", "memory");
+               :"c" (sem), "m" (*(unsigned long *)__up_wakeup)
+               :"memory");
 }
 
 #endif
index 0ddc6012b3d5a56ea15211138d39947c42ece025..af6cf8c9c37a158e618dddf73e7212040f15c6ef 100644 (file)
@@ -93,7 +93,7 @@ __asm__ __volatile__( \
        "lock ; btrl $0,%0" \
        :"=m" (__dummy_lock(lock)))
 
-#define spin_trylock(lock) (!set_bit(0,(lock)))
+#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
 
 #define spin_lock_irq(lock) \
        do { __cli(); spin_lock(lock); } while (0)
index 10bd23bfdc5d634524a21209c54c4b21da258e19..87120a7f76b5a67bc2a16ef8214d888437ad215d 100644 (file)
@@ -261,8 +261,6 @@ extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t p
 
 extern void vmtruncate(struct inode * inode, unsigned long offset);
 extern void handle_mm_fault(struct vm_area_struct *vma, unsigned long address, int write_access);
-extern void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access);
-extern void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access);
 
 extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
 extern void mem_init(unsigned long start_mem, unsigned long end_mem);
index 6b9b41aa588c26d026ce94f7c08d32ed707d35fe..de398bcff1dba6abee110d37e7639a6448792f70 100644 (file)
@@ -62,13 +62,14 @@ static inline void run_bottom_halves(void)
 
 asmlinkage void do_bottom_half(void)
 {
-       int cpu = smp_processor_id();
+       if (softirq_trylock()) {
+               int cpu = smp_processor_id();
 
-       if (hardirq_trylock(cpu)) {
-               if (softirq_trylock()) {
+               if (hardirq_trylock(cpu)) {
+                       __sti();
                        run_bottom_halves();
-                       softirq_endlock();
+                       hardirq_endlock(cpu);
                }
-               hardirq_endlock(cpu);
+               softirq_endlock();
        }
 }
index a4e357ee7b8456dcb719a4d7e88846f8c46ebfa1..6be7846c8cae2a292695c5a423a9b072a5e5f5ab 100644 (file)
@@ -224,6 +224,7 @@ __initfunc(long kmalloc_init(long start_mem, long end_mem))
        return start_mem;
 }
 
+static spinlock_t kmalloc_lock;
 
 /*
  * Ugh, this is ugly, but we want the default case to run
@@ -277,8 +278,7 @@ void *kmalloc(size_t size, int priority)
                }
        }
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&kmalloc_lock, flags);
        page = *pg;
        if (!page)
                goto no_bucket_page;
@@ -292,7 +292,7 @@ found_it:
        page->nfree--;
        if (!page->nfree)
                *pg = page->next;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&kmalloc_lock, flags);
        bucket->nmallocs++;
        bucket->nbytesmalloced += size;
        p->bh_flags = type;     /* As of now this block is officially in use */
@@ -308,9 +308,9 @@ no_bucket_page:
         * If we didn't find a page already allocated for this
         * bucket size, we need to get one..
         *
-        * This can be done with ints on: it is private to this invocation
+        * This can be done without locks: it is private to this invocation
         */
-       restore_flags(flags);
+       spin_unlock_irqrestore(&kmalloc_lock, flags);
 
        {
                int i, sz;
@@ -346,7 +346,7 @@ found_cached_page:
         * Now we're going to muck with the "global" freelist
         * for this size: this should be uninterruptible
         */
-       cli();
+       spin_lock_irq(&kmalloc_lock);
        page->next = *pg;
        *pg = page;
        goto found_it;
@@ -372,7 +372,7 @@ no_free_page:
        }
 
 not_free_on_freelist:
-       restore_flags(flags);
+       spin_unlock_irqrestore(&kmalloc_lock, flags);
        printk("Problem: block on freelist at %08lx isn't free.\n", (long) p);
        return NULL;
 }
@@ -409,8 +409,7 @@ void kfree(void *__ptr)
 #ifdef SADISTIC_KMALLOC
        memset(ptr+1, 0x0e, ptr->bh_length);
 #endif
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&kmalloc_lock, flags);
 
        bucket->nfrees++;
        bucket->nbytesmalloced -= ptr->bh_length;
@@ -439,7 +438,7 @@ free_page:
                bucket->npages--;
                free_kmalloc_pages(page, bucket->gfporder, dma);
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&kmalloc_lock, flags);
 null_kfree:
        return;
 
@@ -450,5 +449,5 @@ bad_order:
 
 not_on_freelist:
        printk("Ooops. page %p doesn't show on freelist.\n", page);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&kmalloc_lock, flags);
 }
index 4af17725b729cbfcb876e9c7dd47a3d1ecd99c72..5866c03f3cf1124d06e4322b2cf849b4879ef120 100644 (file)
@@ -589,7 +589,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
  * change only once the write actually happens. This avoids a few races,
  * and potentially makes it more efficient.
  */
-void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
        unsigned long address, int write_access)
 {
        pgd_t *page_dir;
@@ -785,7 +785,7 @@ static inline void do_swap_page(struct task_struct * tsk,
  * As this is called only for pages that do not currently exist, we
  * do not need to flush old virtual caches or the TLB.
  */
-void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
        unsigned long address, int write_access)
 {
        pgd_t * pgd;
index 32d504eef6003a540f62cc0af8a22c0947e41969..1fbb9512a008617f91246c5a6bff20e0a09f8ba8 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/uaccess.h> /* for copy_to/from_user */
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
+#include <asm/spinlock.h>
 
 int nr_swap_pages = 0;
 int nr_free_pages = 0;
@@ -89,10 +90,6 @@ static inline void remove_mem_queue(struct page * entry)
  *
  * With the above two rules, you get a straight-line execution path
  * for the normal case, giving better asm-code.
- *
- * free_page() may sleep since the page being freed may be a buffer
- * page or present in the swap cache. It will not sleep, however,
- * for a freshly allocated page (get_free_page()).
  */
 
 /*
@@ -100,6 +97,8 @@ static inline void remove_mem_queue(struct page * entry)
  *
  * Hint: -mask = 1+~mask
  */
+static spinlock_t page_alloc_lock;
+
 static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
 {
        struct free_area_struct *area = free_area + order;
@@ -107,8 +106,7 @@ static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
        unsigned long mask = (~0UL) << order;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&page_alloc_lock, flags);
 
 #define list(x) (mem_map+(x))
 
@@ -127,7 +125,7 @@ static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
 
 #undef list
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&page_alloc_lock, flags);
 }
 
 void __free_page(struct page *page)
@@ -173,7 +171,7 @@ do { struct free_area_struct * area = free_area+order; \
                                MARK_USED(map_nr, new_order, area); \
                                nr_free_pages -= 1 << order; \
                                EXPAND(ret, map_nr, order, new_order, area); \
-                               restore_flags(flags); \
+                               spin_unlock_irqrestore(&page_alloc_lock, flags); \
                                return ADDRESS(map_nr); \
                        } \
                        prev = ret; \
@@ -215,15 +213,14 @@ unsigned long __get_free_pages(int priority, unsigned long order, int dma)
        reserved_pages = 5;
        if (priority != GFP_NFS)
                reserved_pages = min_free_pages;
-       save_flags(flags);
 repeat:
-       cli();
+       spin_lock_irqsave(&page_alloc_lock, flags);
        if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
                RMQUEUE(order, dma);
-               restore_flags(flags);
+               spin_unlock_irqrestore(&page_alloc_lock, flags);
                return 0;
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&page_alloc_lock, flags);
        if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1))
                goto repeat;
        return 0;
@@ -240,8 +237,7 @@ void show_free_areas(void)
        unsigned long total = 0;
 
        printk("Free pages:      %6dkB\n ( ",nr_free_pages<<(PAGE_SHIFT-10));
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&page_alloc_lock, flags);
        for (order=0 ; order < NR_MEM_LISTS; order++) {
                struct page * tmp;
                unsigned long nr = 0;
@@ -251,7 +247,7 @@ void show_free_areas(void)
                total += nr * ((PAGE_SIZE>>10) << order);
                printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order));
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&page_alloc_lock, flags);
        printk("= %lukB)\n", total);
 #ifdef SWAP_CACHE_INFO
        show_swap_cache_info();