]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.96pre1 2.1.96pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:12 +0000 (15:15 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:12 +0000 (15:15 -0500)
278 files changed:
Documentation/Configure.help
Documentation/parport.txt
Documentation/sound/ultrasound [new file with mode: 0644]
Makefile
arch/alpha/kernel/bios32.c
arch/arm/Makefile
arch/arm/boot/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/tools/build.c [deleted file]
arch/arm/config.in
arch/arm/defconfig
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c
arch/arm/kernel/bios32.c [new file with mode: 0644]
arch/arm/kernel/dma-a5k.c [new file with mode: 0644]
arch/arm/kernel/dma-arc.c [new file with mode: 0644]
arch/arm/kernel/dma-dummy.c [new file with mode: 0644]
arch/arm/kernel/dma-rpc.c [new file with mode: 0644]
arch/arm/kernel/dma.c
arch/arm/kernel/dma.h [new file with mode: 0644]
arch/arm/kernel/ecard.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/head-armo.S
arch/arm/kernel/head-armv.S
arch/arm/kernel/irq.c
arch/arm/kernel/leds-ebsa285.c [new file with mode: 0644]
arch/arm/kernel/process.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup-ebsa110.c
arch/arm/kernel/setup.c
arch/arm/kernel/time.c
arch/arm/kernel/traps.c
arch/arm/lib/Makefile
arch/arm/lib/extractconstants.pl [new file with mode: 0644]
arch/arm/lib/extractinfo.perl [deleted file]
arch/arm/lib/getconsdata.c
arch/arm/lib/getconstants.c [deleted file]
arch/arm/lib/getconstants.h [deleted file]
arch/arm/lib/io-acorn.S
arch/arm/lib/io-ebsa285.S [new file with mode: 0644]
arch/arm/lib/ll_char_wr.S
arch/arm/lib/memcpy.S
arch/arm/lib/uaccess.S
arch/arm/mm/Makefile
arch/arm/mm/fault-armv.c
arch/arm/mm/init.c
arch/arm/mm/mm-a5k.c [deleted file]
arch/arm/mm/mm-arc.c
arch/arm/mm/mm-ebsa110.c
arch/arm/mm/mm-ebsa285.c [new file with mode: 0644]
arch/arm/mm/mm-nexuspci.c
arch/arm/mm/mm-rpc.c
arch/arm/mm/proc-arm6,7.S
arch/arm/mm/proc-sa110.S
arch/arm/vmlinux.lds
drivers/block/ide-disk.c
drivers/block/ide.c
drivers/block/rz1000.c
drivers/char/cyclades.c
drivers/char/lp.c
drivers/char/pc_keyb.c
drivers/misc/parport_init.c
drivers/misc/parport_pc.c
drivers/misc/parport_share.c
drivers/scsi/53c7,8xx.c
drivers/scsi/53c7xx.c
drivers/scsi/AM53C974.c
drivers/scsi/Config.in
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/NCR53c406a.c
drivers/scsi/README.aic7xxx
drivers/scsi/a2091.c
drivers/scsi/a3000.c
drivers/scsi/advansys.c
drivers/scsi/aha1542.c
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx.h
drivers/scsi/aic7xxx/aic7xxx.reg
drivers/scsi/aic7xxx/aic7xxx.seq
drivers/scsi/aic7xxx/scsi_message.h
drivers/scsi/aic7xxx/sequencer.h
drivers/scsi/aic7xxx_proc.c
drivers/scsi/aic7xxx_reg.h
drivers/scsi/aic7xxx_seq.h
drivers/scsi/dtc.c
drivers/scsi/dtc.h
drivers/scsi/eata.c
drivers/scsi/eata_dma.c
drivers/scsi/eata_pio.c
drivers/scsi/esp.c
drivers/scsi/fdomain.c
drivers/scsi/g_NCR5380.c
drivers/scsi/g_NCR5380.h
drivers/scsi/gdth.c
drivers/scsi/gvp11.c
drivers/scsi/hosts.h
drivers/scsi/ibmmca.c
drivers/scsi/ide-scsi.c
drivers/scsi/ide-scsi.h
drivers/scsi/in2000.c
drivers/scsi/mac53c94.c
drivers/scsi/mesh.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/pas16.c
drivers/scsi/pas16.h
drivers/scsi/pci2000.c
drivers/scsi/pci2220i.c
drivers/scsi/psi240i.c
drivers/scsi/qlogicfas.c
drivers/scsi/qlogicisp.c
drivers/scsi/qlogicpti.c
drivers/scsi/scsi.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_obsolete.c
drivers/scsi/scsiiom.c
drivers/scsi/seagate.c
drivers/scsi/sg.c
drivers/scsi/t128.c
drivers/scsi/t128.h
drivers/scsi/tmscsim.c
drivers/scsi/ultrastor.c
drivers/scsi/wd7000.c
drivers/sound/Config.in
drivers/sound/gus_card.c
drivers/sound/gus_wave.c
drivers/sound/pas2_card.c
fs/binfmt_misc.c
include/asm-arm/a.out.h
include/asm-arm/arch-a5k/a.out.h [deleted file]
include/asm-arm/arch-a5k/dma.h [deleted file]
include/asm-arm/arch-a5k/hardware.h [deleted file]
include/asm-arm/arch-a5k/ide.h [deleted file]
include/asm-arm/arch-a5k/io.h [deleted file]
include/asm-arm/arch-a5k/irq.h [deleted file]
include/asm-arm/arch-a5k/irqs.h [deleted file]
include/asm-arm/arch-a5k/mmu.h [deleted file]
include/asm-arm/arch-a5k/oldlatches.h [deleted file]
include/asm-arm/arch-a5k/processor.h [deleted file]
include/asm-arm/arch-a5k/serial.h [deleted file]
include/asm-arm/arch-a5k/shmparam.h [deleted file]
include/asm-arm/arch-a5k/system.h [deleted file]
include/asm-arm/arch-a5k/time.h [deleted file]
include/asm-arm/arch-a5k/timex.h [deleted file]
include/asm-arm/arch-a5k/uncompress.h [deleted file]
include/asm-arm/arch-arc/a.out.h
include/asm-arm/arch-arc/dma.h
include/asm-arm/arch-arc/hardware.h
include/asm-arm/arch-arc/ide.h
include/asm-arm/arch-arc/io.h
include/asm-arm/arch-arc/irq.h
include/asm-arm/arch-arc/irqs.h
include/asm-arm/arch-arc/keyboard.h [new file with mode: 0644]
include/asm-arm/arch-arc/mmu.h
include/asm-arm/arch-arc/oldlatches.h
include/asm-arm/arch-arc/processor.h
include/asm-arm/arch-arc/serial.h
include/asm-arm/arch-arc/system.h
include/asm-arm/arch-arc/timex.h
include/asm-arm/arch-arc/uncompress.h
include/asm-arm/arch-ebsa110/a.out.h
include/asm-arm/arch-ebsa110/dma.h
include/asm-arm/arch-ebsa110/hardware.h
include/asm-arm/arch-ebsa110/io.h
include/asm-arm/arch-ebsa110/irqs.h
include/asm-arm/arch-ebsa110/mm-init.h
include/asm-arm/arch-ebsa110/mmap.h [deleted file]
include/asm-arm/arch-ebsa110/mmu.h
include/asm-arm/arch-ebsa110/processor.h
include/asm-arm/arch-ebsa285/a.out.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/dma.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/hardware.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/ide.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/io.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/irq.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/irqs.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/keyboard.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/mm-init.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/mmu.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/oldlatches.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/processor.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/shmparam.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/system.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/time.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/timex.h [new file with mode: 0644]
include/asm-arm/arch-ebsa285/uncompress.h [new file with mode: 0644]
include/asm-arm/arch-nexuspci/a.out.h
include/asm-arm/arch-nexuspci/dma.h
include/asm-arm/arch-nexuspci/hardware.h
include/asm-arm/arch-nexuspci/irqs.h
include/asm-arm/arch-nexuspci/mm-init.h [new file with mode: 0644]
include/asm-arm/arch-nexuspci/mmap.h [deleted file]
include/asm-arm/arch-nexuspci/processor.h
include/asm-arm/arch-nexuspci/serial.h [deleted file]
include/asm-arm/arch-nexuspci/uncompress.h
include/asm-arm/arch-rpc/a.out.h
include/asm-arm/arch-rpc/dma.h
include/asm-arm/arch-rpc/hardware.h
include/asm-arm/arch-rpc/io.h
include/asm-arm/arch-rpc/irq.h
include/asm-arm/arch-rpc/irqs.h
include/asm-arm/arch-rpc/keyboard.h [new file with mode: 0644]
include/asm-arm/arch-rpc/mm-init.h [new file with mode: 0644]
include/asm-arm/arch-rpc/mmap.h [deleted file]
include/asm-arm/arch-rpc/mmu.h
include/asm-arm/arch-rpc/processor.h
include/asm-arm/arch-rpc/uncompress.h
include/asm-arm/dma.h
include/asm-arm/ecard.h
include/asm-arm/elf.h
include/asm-arm/hardirq.h
include/asm-arm/hardware.h
include/asm-arm/io.h
include/asm-arm/irq-no.h [deleted file]
include/asm-arm/irq.h
include/asm-arm/keyboard.h [new file with mode: 0644]
include/asm-arm/leds.h [new file with mode: 0644]
include/asm-arm/proc-armo/processor.h
include/asm-arm/proc-armv/mm-init.h
include/asm-arm/proc-armv/pgtable.h
include/asm-arm/proc-armv/processor.h
include/asm-arm/proc-armv/system.h
include/asm-arm/smp.h
include/asm-arm/socket.h
include/asm-arm/softirq.h
include/asm-arm/types.h
include/asm-i386/system.h
include/linux/cyclades.h
include/linux/if_arp.h
include/linux/parport.h
include/linux/pci.h
include/linux/socket.h
include/linux/sysctl.h
include/linux/tcp.h
include/net/ipx.h
include/net/netrom.h
include/net/rose.h
include/net/sock.h
include/net/spx.h
include/net/spxcall.h [new file with mode: 0644]
include/net/tcp.h
include/scsi/sg.h
net/ax25/af_ax25.c
net/ax25/ax25_out.c
net/core/iovec.c
net/core/sock.c
net/ipv4/icmp.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv6/tcp_ipv6.c
net/ipx/Config.in
net/ipx/Makefile
net/ipx/af_ipx.c
net/ipx/af_spx.c [new file with mode: 0644]
net/netrom/Makefile
net/netrom/af_netrom.c
net/netrom/nr_in.c
net/netrom/nr_loopback.c [new file with mode: 0644]
net/netrom/nr_route.c
net/netrom/nr_subr.c
net/netsyms.c
net/rose/Makefile
net/rose/af_rose.c
net/rose/rose_dev.c
net/rose/rose_in.c
net/rose/rose_link.c
net/rose/rose_loopback.c [new file with mode: 0644]
net/rose/rose_route.c
net/socket.c
net/x25/af_x25.c
net/x25/x25_in.c
scripts/Configure
scripts/Menuconfig

index fe121bc669360f9e39009394b70de5368f7e084e..56f879f9fb430ba9957de27e439aca189c1730dd 100644 (file)
@@ -2398,74 +2398,64 @@ CONFIG_SCSI_AHA1740
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
-Adaptec AIC7xxx support (includes 274x/284x/294x)
+Adaptec AIC7xxx chipset SCSI controller support
 CONFIG_SCSI_AIC7XXX
-  Information about this SCSI host adapter is contained in
-  drivers/scsi/README.aic7xxx and in the SCSI-HOWTO, available via ftp
-  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note
-  that the AHA2920 SCSI host adapter is *not* supported by this
-  driver; choose "Future Domain 16xx SCSI support" instead. If you
-  want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/ modules.txt. The module will be
-  called aic7xxx.o.
-
-Enable tagged command queueing
-CONFIG_AIC7XXX_TAGGED_QUEUEING
-  This option allows you to enable tagged command queueing for this
-  driver. Some SCSI devices do not properly support this feature. 
-  Tagged command queueing will improve performance.
+  This is support for the various aic7xxx based Adaptec SCSI controllers.
+  These include the 274x EISA cards, 284x VLB cards, 294x PCI cards,
+  394x PCI cards, 3985 PCI card, and several versions of the Adaptec
+  built-in SCSI controllers on various PC motherboards.  Information on
+  the configuration options for this controller can be found by checking
+  the README.aic7xxx file, usually in /usr/src/linux/drivers/scsi.
 
 Override driver defaults for commands per LUN
 CONFIG_OVERRIDE_CMDS
-  This option allows you to set the maximum number of SCSI commands
-  queued per LUN (Logical Unit Number - some physical SCSI devices,
-  e.g. CD jukeboxes, act logically as several logical units).  If you
-  say N here, the driver will attempt to set the commands per LUN
-  using its own reasonable heuristic. If you say Y, you can specify
-  your preference in the next question.  If unsure, say N.
+  Use this option to allow you to override the default maximum number of
+  commands that a single device on the aic7xxx controller is allowed to have
+  active at one time.  This option only effects tagged queueing capable
+  devices.  The driver uses a "failsafe" value of 8 by default.  This is
+  much lower than many devices can handle, but left in place for safety sake.
+  NOTE: This does not actually enabled tagged queueing on any particular
+  device.  The driver has changed in this respect.  Please see the file
+  README.aic7xxx in /usr/src/linux/drivers/scsi for more information on how
+  to get particular devices to use tagged command queueing.
+  Default: N
 
 Maximum number of commands per LUN
 CONFIG_AIC7XXX_CMDS_PER_LUN
-  By default, we limit the commands per LUN to 2 with or without
-  tagged queueing enabled.  If tagged queueing is enabled, the
-  sequencer in the host adapter will attempt to send the 2nd command
-  block to the device while the first command block is still executing
-  and the device is disconnected. If the devices don't complain, you
-  can thus try to increase the number of SCSI commands per LUN to more
-  than 2 in this case. If tagged queueing is disabled, the sequencer
-  in the host adapter will keep the 2nd command in its input queue
-  until the first one completes - so it is OK to have more than 1
-  command queued. However, for host adapters limited to 4 command
-  blocks (SCB's), you may want to actually decrease the commands per
-  LUN to 1, if you often have more than 2 devices active at the same
-  time.  This will ensure that there will always be a free SCB for up
-  to 4 devices active at the same time. When SCB paging is enabled,
-  set the commands per LUN to 8 or higher (see "SCB paging support"
-  below).  If unsure, go with the default for now.
-
-Enable SCB paging
-CONFIG_AIC7XXX_PAGE_ENABLE
-  This option enables SCB paging.  This will increase performance when
-  tagged queueing is enabled.  Note that, if you say Y here, you
-  should increase the "Maximum number of commands per LUN"
-  (AIC7XXX_CMDS_PER_LUN) above to 8 as most tagged queueing devices
-  allow at least this many.  Note that EISA and VLB controllers do not
-  support SCB paging due to chip limitations; enabling it on these
-  controllers has no effect.
+  Specify the maximum number of commands per lun you would like to allocate
+  per device.  Reasonable figures are in the range of 14 to 32 commands per
+  device, but depending on hardware could be increased or decreased from
+  that figure.  If the number is too high for any particular device, the
+  driver will automatically compensate usually after only 10 minutes of
+  uptime and will issue a message to alert you to the fact that the number
+  of commands for that device has been reduced.  It will not hinder
+  performance if a portion of your devices eventually have their commands
+  per lun reduced, but is a waste of memory if all of your devices end
+  up reducing this number down to a more reasonable figure.  Default: 24
 
 Collect statistics to report in /proc
 CONFIG_AIC7XXX_PROC_STATS
-  This option enables collection of SCSI transfer statistics for the
-  /proc filesystem.  This does affect performance since it has to
-  maintain statistics. The statistics will appear under
-  /proc/scsi/aic7xxx. This will only work if you also enable the "proc
-  filesystem", below.
+  This option tells the driver to keep track of how many commands have been
+  sent to each particular device and report that information to the user
+  via the /proc/scsi/aic7xxx/x file, where x is the number of the aic7xxx
+  controller you want the information on.  This adds a small amount of
+  overhead to each and every SCSI command the aic7xxx driver handles, so if
+  you aren't really interested in this information, it is best to leave it
+  disabled.  Default: N
 
 Delay in seconds after SCSI bus reset
 CONFIG_AIC7XXX_RESET_DELAY
-  This option sets the delay in seconds after a SCSI bus reset. If you
-  don't know what you are doing, go with the default.
+  This sets how long the driver will wait after resetting the SCSI bus before
+  attempting to communicate with the devices on the SCSI bus again.  This
+  delay will be used during the reset phase at bootup time as well as after
+  any reset that might occur during normal operation.  Reasonable numbers
+  range anywhere from 5 to 15 seconds depending on your devices.  DAT tape
+  drives are notorious for needing more time after a bus reset to be
+  ready for the next command, but most hard drives and CD-ROM devices are
+  ready in only a few seconds.  This option has a maximum upper limit of
+  20 seconds to avoid bad interactions between the aic7xxx driver and the
+  rest of the linux kernel.  The default value has been reduced.  If this
+  doesn't work with your hardware, try increasing this value.  Default: 5
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
index 278ab3a7a3e9ef6dd3d1e3703d6288b0c6427b8b..f9ee710921450aa24b1fade4b692dbe0a691b016 100644 (file)
@@ -5,11 +5,15 @@ drivers.
 You can pass parameters to the parport code to override its automatic
 detection of your hardware.  This is particularly useful if you want
 to use IRQs, since in general these can't be autoprobed successfully.
+By default IRQs are not used even if they _can_ be probed.  This is
+because there are a lot of people using the same IRQ for their
+parallel port and a sound card or network card.
 
 The parport code is split into two parts: generic (which deals with
 port-sharing) and architecture-dependent (which deals with actually
 using the port).
 
+
 Parport as modules
 ==================
 
@@ -20,31 +24,33 @@ If you load the parport code as a module, say
 to load the generic parport code.  You then must load the
 architecture-dependent code with (for example):
 
-       # insmod parport_pc.o io=0x378,0x278 irq=7,5
+       # insmod parport_pc.o io=0x3bc,0x378,0x278 irq=none,7,auto
+
+to tell the parport code that you want three PC-style ports, one at
+0x3bc with no IRQ, one at 0x378 using IRQ 7, and one at 0x278 with an
+auto-detected IRQ.  Currently, PC-style (parport_pc) and Sun Ultra/AX
+(parport_ax) hardware is supported; more is in the works.
 
-to tell the parport code that you want two PC-style ports, one at
-0x378 using IRQ 7, and one at 0x278 using IRQ 5.  Currently, PC-style
-(parport_pc) and ARC onboard (parport_arc) parallel ports are
-supported.
 
-Kerneld
--------
+KMod
+----
 
-If you use kerneld, you will find it useful to edit /etc/conf.modules.
+If you use kmod, you will find it useful to edit /etc/conf.modules.
 Here is an example of the lines that need to be added:
 
        alias parport_lowlevel parport_pc
-       options parport_pc io=0x378,0x278 irq=7,5
+       options parport_pc io=0x378,0x278 irq=7,auto
+
+KMod will then automatically load parport_pc (with the options
+"io=0x378,0x278 irq=7,auto") whenever a parallel port device driver
+(such as lp) is loaded.
 
-Kerneld, in conjunction with parport, will automatically load
-parport_pc whenever a parallel port device driver (such as lp) is
-loaded.
 
 Parport probe [optional]
 -------------
 
 Once the architecture-dependent part of the parport code is loaded
-into the kernel, you insert the parport_probe module with:
+into the kernel, you can insert the parport_probe module with:
 
        # insmod parport_probe.o
 
@@ -53,22 +59,25 @@ message similar to:
 
        parport0: Printer, BJC-210 (Canon)
 
-(If you are using kerneld and have configured parport_probe as a 
-module, this will just happen.)
+(If you are using kmod and have configured parport_probe as a module,
+this will just happen.)
 
 
-Parport, but not as modules
-===========================
+Parport linked into the kernel statically
+=========================================
 
 If you compile the parport code into the kernel, then you can use
 kernel boot parameters to get the same effect.  Add something like the
 following to your LILO command line:
 
-       parport=0x378,7 parport=0x278,5
+       parport=0x3bc parport=0x378,7 parport=0x278,auto
 
 You can have many `parport=...' statements, one for each port you want
 to add.  Adding `parport=0' to the kernel command-line will disable
-parport support entirely.
+parport support entirely.  Adding `parport=auto' to the kernel
+command-line will make parport use any IRQ lines or DMA channels that
+it auto-detects.
+
 
 Files in /proc
 ==============
@@ -90,10 +99,10 @@ File:                               Contents:
                                and DMA channel.
 
 /proc/parport/0/irq            The IRQ that parport is using for that
-                               port (as above).  This is in a
-                               separate file to allow you to alter it
-                               by writing a new value in (IRQ number
-                               or "none").
+                               port.  This is in a separate file to
+                                allow you to alter it by writing a new
+                               value in (IRQ number or "none").
+
 
 Device drivers
 ==============
@@ -121,7 +130,7 @@ regardless of base address.
 
 Also:
 
- * If you selected the device autoprobe at compile time, you can say
+ * If you selected the IEEE-1284 autoprobe at compile time, you can say
    `lp=auto' on the kernel command line, and lp will create devices
    only for those ports that seem to have printers attached.
 
@@ -129,10 +138,7 @@ Also:
    the command line, or with `insmod plip timid=1' when using modules,
    it will avoid any ports that seem to be in use by other devices.
 
- * If your BIOS allows you to engage "ECP mode", you may find that
-   your port's IRQ can be autoprobed, without having to specify any 
-   parameters.
-
+ * IRQ autoprobing works only for a few port types at the moment.
 
 --
 Philip.Blundell@pobox.com
diff --git a/Documentation/sound/ultrasound b/Documentation/sound/ultrasound
new file mode 100644 (file)
index 0000000..552dff4
--- /dev/null
@@ -0,0 +1,31 @@
+
+insmod sound
+insmod ad1848
+insmod gus io=* irq=* dma=* ...
+
+This loads the driver for the Gravis Ultrasound familily of soundcards.
+
+The gus modules takes the following arguments
+
+io             I/O address of the ultrasound card (eg. io=0x220)
+irq            IRQ of the soundblaster card 
+dma            DMA channel for the soundblaster
+dma16          2nd DMA channel, only needed for full duplex operation
+type           1 for PnP card
+gus16          1 for using 16 bit sampling daughter board
+no_wave_dma    Set to disable dma usage for wavetable (see note)
+db16           ???
+
+
+no_wave_dma option
+
+This option defaults to a value of 0, which allows the Ultrasound wavetable
+DSP to use DMA for for playback and downloading samples. This is the same
+as the old behaviour. If set to 1, no DMA is needed for downloading samples,
+and allows owners of a GUS MAX to make use of simultanious digital audio
+(/dev/dsp), MIDI, and wavetable playback.
+
+
+If you have problems in recording with GUS MAX, you could try to use
+just one 8 bit DMA channel. Recording will not work with one DMA
+channel if it's a 16 bit one.
index 9bfef8b6f2c7a10ffe0a4cf18f45c696b743adfd..7a6f0d296717868b13badb439d789e5b12d5579e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 95
+SUBLEVEL = 96
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
index 81c8f70e05ec384eb3cebf0718710c26799fce9f..46880f11e6365c2ed12ee51038700ee0d1c7d27d 100644 (file)
@@ -410,7 +410,7 @@ static void layout_dev(struct pci_dev *dev)
                        pcibios_write_config_dword(bus->number, dev->devfn,
                                                   off, base);
                        handle = HANDLE(bus->number) | base;
-                       dev->base_address[PCI_BASE_INDEX(off)] = handle;
+                       dev->base_address[idx] = handle;
                        DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n",
                                  dev->device, handle, size));
                }
index 5c1efb76a28af7fd15fcd8388b4354d62d0e9e31..0c39121be4dc61e185d01fa104a5a1fdfa0c3732 100644 (file)
@@ -12,6 +12,9 @@
 #
 # Copyright (C) 1995, 1996 by Russell King
 
+CFLAGS_PROC    :=
+ASFLAGS_PROC   :=
+
 ifeq ($(CONFIG_CPU_ARM2),y)
 PROCESSOR       = armo
 ASFLAGS_PROC   += -m2
@@ -65,7 +68,6 @@ endif
 # ZRELADDR - Compressed kernel relocating address (point at which uncompressed kernel is loaded).
 #
 
-HEAD           := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o
 COMPRESSED_HEAD         = head.o
 
 ifeq ($(PROCESSOR),armo)
@@ -79,11 +81,13 @@ endif
 
 ifeq ($(CONFIG_ARCH_A5K),y)
 MACHINE                 = a5k
+ARCHDIR                 = arc
 COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 endif
 
 ifeq ($(CONFIG_ARCH_ARC),y)
 MACHINE                 = arc
+ARCHDIR                 = arc
 COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 endif
 
@@ -96,6 +100,7 @@ endif
 
 ifeq ($(CONFIG_ARCH_RPC),y)
 MACHINE                 = rpc
+ARCHDIR                 = rpc
 COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 ZTEXTADDR       = 0x10008000
 ZRELADDR        = 0x10008000
@@ -103,6 +108,14 @@ endif
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 MACHINE                 = ebsa110
+ARCHDIR                 = ebsa110
+ZTEXTADDR       = 0x00008000
+ZRELADDR        = 0x00008000
+endif
+
+ifeq ($(CONFIG_ARCH_EBSA285),y)
+MACHINE                 = ebsa285
+ARCHDIR                 = ebsa285
 ZTEXTADDR       = 0x00008000
 ZRELADDR        = 0x00008000
 endif
@@ -129,35 +142,55 @@ ifeq ($(CONFIG_FRAME_POINTER),y)
 CFLAGS         := $(CFLAGS:-fomit-frame-pointer=)
 endif
 CFLAGS         := $(CFLAGS_PROC) $(CFLAGS) -pipe
-ASFLAGS                := $(ASFLAGS_PROC) $(ASFLAGS) -D__ASSEMBLY__
+ASFLAGS                := $(ASFLAGS_PROC) $(ASFLAGS)
 LINKFLAGS       = -T $(TOPDIR)/arch/arm/vmlinux.lds -e stext -Ttext $(TEXTADDR)
 ZLINKFLAGS      = -Ttext $(ZTEXTADDR)
 
 SUBDIRS                := $(SUBDIRS:drivers=) arch/arm/lib arch/arm/kernel arch/arm/mm arch/arm/drivers
+HEAD           := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o
 CORE_FILES     := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
 LIBS           := arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
 
-DRIVERS                := arch/arm/drivers/block/block.a \
-                  arch/arm/drivers/char/char.a \
-                  drivers/misc/misc.a \
-                  arch/arm/drivers/net/net.a
+BLOCK_DRIVERS  := arch/arm/drivers/block/block.a
+CDROM_DRIVERS  := drivers/cdrom/cdrom.a
+CHAR_DRIVERS   := arch/arm/drivers/char/char.a
+MISC_DRIVERS   := drivers/misc/misc.a
+NET_DRIVERS    := drivers/net/net.a
+PARIDE_DRIVERS := drivers/block/paride/paride.a
+PCI_DRIVERS    := drivers/pci/pci.a
+SCSI_DRIVERS   := drivers/scsi/scsi.a
+SOUND_DRIVERS  := drivers/sound/sound.a
 
-ifeq ($(CONFIG_SCSI),y)
-DRIVERS                := $(DRIVERS) arch/arm/drivers/scsi/scsi.a
+ifeq ($(CONFIG_ARCH_ACORN),y)
+BLOCK_DRIVERS  += drivers/acorn/block/acorn-block.a
+CHAR_DRIVERS   += drivers/acorn/char/acorn-char.a
+NET_DRIVERS    += drivers/acorn/net/acorn-net.a drivers/net/net.a
+SCSI_DRIVERS   += drivers/acorn/scsi/acorn-scsi.a
 endif
 
+DRIVERS                := $(BLOCK_DRIVERS) $(CHAR_DRIVERS) $(MISC_DRIVERS) $(NET_DRIVERS)
+
+ifeq ($(CONFIG_SCSI),y)
+DRIVERS                := $(DRIVERS) $(SCSI_DRIVERS)
+endif
 ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR),)
-DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a
+DRIVERS                := $(DRIVERS) $(CDROM_DRIVERS)
+endif
+ifdef CONFIG_PCI
+DRIVERS                := $(DRIVERS) $(PCI_DRIVERS)
 endif
-
 ifeq ($(CONFIG_SOUND),y)
-DRIVERS                := $(DRIVERS) arch/arm/drivers/sound/sound.a
+DRIVERS                := $(DRIVERS) $(SOUND_DRIVERS)
+endif
+ifeq ($(CONFIG_PARIDE),y)
+DRIVERS                := $(DRIVERS) $(PARIDE_DRIVERS)
 endif
 
 symlinks::
        $(RM) include/asm-arm/arch include/asm-arm/proc
-       (cd include/asm-arm; ln -sf arch-$(MACHINE) arch; ln -sf proc-$(PROCESSOR) proc)
+       (cd include/asm-arm; ln -sf arch-$(ARCHDIR) arch; ln -sf proc-$(PROCESSOR) proc)
 
+# Once we've finished integrating the sources, the @$(MAKE) will disappear
 mrproper::
        rm -f include/asm-arm/arch include/asm-arm/proc
        @$(MAKE) -C arch/$(ARCH)/drivers mrproper
@@ -183,7 +216,6 @@ install: vmlinux
        @$(MAKEBOOT) install
 
 # My testing targets (that short circuit a few dependencies)
-#
 zImg:; @$(MAKEBOOT) zImage
 Img:;  @$(MAKEBOOT) Image
 i:;    @$(MAKEBOOT) install
@@ -191,8 +223,7 @@ zi:;        @$(MAKEBOOT) zinstall
 
 archclean:
        @$(MAKEBOOT) clean
-       @$(MAKE) -C arch/arm/lib clean
+       $(RM) arch/arm/lib/constants.h
 
 archdep:
        @$(MAKEBOOT) dep
-sed -e /^MACHINE..*=/s,= .*,= rpc,;/^PROCESSOR..*=/s,= .*,= armv, linux/arch/arm/Makefile.normal
index e6050bf1384593acacd1a58b5bcea5a4bfae3072..d210b92c2b747f72ccae4a79b53cab7644ef324e 100644 (file)
@@ -25,11 +25,8 @@ install: $(CONFIGURE) Image
 zinstall: $(CONFIGURE) zImage
        sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
-tools/build: tools/build.c
-       $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
-
 clean:
-       rm -f Image zImage tools/build
+       rm -f Image zImage
        @$(MAKE) -C compressed clean
 
 dep:
index 8e49f5dd0789e33a74debf34e7b04a470ca56d17..0c6a04c5b609d51f47afd83c239439440c5801e3 100644 (file)
@@ -26,7 +26,7 @@ piggy.o:      $(SYSTEM)
                $(OBJCOPY) $(SYSTEM) $$tmppiggy; \
                gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
                echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
-               $(LD) -m elf_arm -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \
+               $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \
                rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk;
 
 clean:;                rm -f vmlinux core
diff --git a/arch/arm/boot/tools/build.c b/arch/arm/boot/tools/build.c
deleted file mode 100644 (file)
index ac12975..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <a.out.h>
-
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long u32;
-
-void die(const char * str, ...)
-{
-       va_list args;
-       va_start(args, str);
-       vfprintf(stderr, str, args);
-       fputc('\n', stderr);
-       exit (1);
-}
-
-int main(int argc, char **argv)
-{
-       void *data;
-       struct exec ex;
-       FILE *f;
-       int totlen;
-
-       if (argc < 2) {
-               fprintf(stderr, "Usage: build kernel-name\n");
-               exit(1);
-       }
-
-       f = fopen(argv[1], "rb");
-       if (!f)
-               die("Unable to open `%s': %m", argv[1]);
-
-       fread(&ex, 1, sizeof(ex), f);
-
-       if(N_MAGIC(ex) == ZMAGIC) {
-               fseek(f, 4096, SEEK_SET);
-               totlen = ex.a_text + ex.a_data;
-       } else
-       if(N_MAGIC(ex) == QMAGIC) {
-               unsigned long my_header;
-               
-               fseek(f, 4, SEEK_SET);
-
-               my_header = 0xea000006;
-
-               fwrite(&my_header, 4, 1, stdout);
-
-               totlen = ex.a_text + ex.a_data - 4;
-       } else {
-               fprintf(stderr, "Unacceptable a.out header on kernel\n");
-               fclose(f);
-               exit(1);
-       }
-
-       fprintf(stderr, "Kernel is %dk (%dk text, %dk data, %dk bss)\n",
-               (ex.a_text + ex.a_data + ex.a_bss)/1024,
-                ex.a_text/1024, ex.a_data/1024, ex.a_bss/1024);
-
-       data = malloc(totlen);
-       fread(data, 1, totlen, f);
-       fwrite(data, 1, totlen, stdout);
-
-       free(data);
-       fclose(f);
-       fflush(stdout);
-       return 0;
-}
index b95c2f16ee12b114637a72af432d3166d75b2606..3396b15103ada8ae347297abb76a247f24d2d11a 100644 (file)
@@ -7,38 +7,25 @@ mainmenu_name "Linux Kernel Configuration"
 define_bool CONFIG_ARM y
 
 mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
-  bool 'Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'General setup'
+comment 'System type and processor type'
 choice 'ARM system type'       \
        "Archimedes             CONFIG_ARCH_ARC \
         A5000                  CONFIG_ARCH_A5K \
         RiscPC                 CONFIG_ARCH_RPC \
         EBSA-110               CONFIG_ARCH_EBSA110 \
+        EBSA-285               CONFIG_ARCH_EBSA285 \
         NexusPCI               CONFIG_ARCH_NEXUSPCI" RiscPC
 if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" -o "$CONFIG_ARCH_RPC" = "y" ]; then
   define_bool CONFIG_ARCH_ACORN y
 else
   define_bool CONFIG_ARCH_ACORN n
 fi
-if [ "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then
+if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_EBSA285" = "y" ]; then
   define_bool CONFIG_PCI y
 else
   define_bool CONFIG_PCI n
 fi
-if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_EBSA110" = "y" ]; then
+if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_ARCH_EBSA285" = "y" ]; then
   define_bool CONFIG_CPU_SA110 y
 else
   if [ "$CONFIG_ARCH_A5K" = "y" ]; then
@@ -51,11 +38,31 @@ else
         StrongARM              CONFIG_CPU_SA110" StrongARM
   fi
 fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+  bool 'Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
 bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER
 bool 'Use new compilation options (for GCC 2.8)' CONFIG_BINUTILS_NEW
 bool 'Debug kernel errors' CONFIG_DEBUG_ERRORS
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
+# This needs kernel/acct.c to be updated
+#bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
@@ -70,6 +77,7 @@ fi
 endmenu
 
 source arch/arm/drivers/block/Config.in
+source drivers/acorn/block/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
@@ -81,7 +89,7 @@ comment 'SCSI support'
 tristate 'SCSI support?' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-  source arch/arm/drivers/scsi/Config.in
+  source drivers/scsi/Config.in
 fi
 endmenu
 
@@ -91,7 +99,7 @@ if [ "$CONFIG_NET" = "y" ]; then
 
   bool 'Network device support?' CONFIG_NETDEVICES
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    source arch/arm/drivers/net/Config.in
+    source drivers/net/Config.in
   fi
   endmenu
 fi
@@ -128,7 +136,7 @@ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
 
   tristate 'Sound support' CONFIG_SOUND
   if [ "$CONFIG_SOUND" != "n" ]; then
-    source arch/arm/drivers/sound/Config.in
+    source drivers/sound/Config.in
   fi
   endmenu
 fi
index 48358557b3a5f5b1bacfe4943a5ee0e4b23c1364..5e587ffbf5ed5d828bf61926784eac6ce888e09d 100644 (file)
@@ -31,6 +31,7 @@ CONFIG_ARCH_ACORN=y
 CONFIG_CPU_SA110=y
 CONFIG_FRAME_POINTER=y
 # CONFIG_BINUTILS_NEW is not set
+CONFIG_DEBUG_ERRORS=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
@@ -76,7 +77,7 @@ CONFIG_BLK_DEV_PART=y
 #
 # Networking options
 #
-CONFIG_PACKET=m
+# CONFIG_PACKET is not set
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
 # CONFIG_NET_ALIAS is not set
@@ -112,8 +113,11 @@ CONFIG_IP_NOSR=y
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
 
 #
 # SCSI support
@@ -149,7 +153,6 @@ CONFIG_SCSI_POWERTECSCSI=m
 # The following drives are not fully supported
 #
 CONFIG_SCSI_CUMANA_1=m
-CONFIG_SCSI_ECOSCSI=m
 CONFIG_SCSI_OAK1=m
 CONFIG_SCSI_PPA=m
 CONFIG_SCSI_PPA_HAVE_PEDANTIC=2
@@ -199,6 +202,7 @@ CONFIG_LOCKD=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_ADFS_FS=y
+CONFIG_ADFS_FS=y
 # CONFIG_MAC_PARTITION is not set
 CONFIG_NLS=y
 
@@ -252,10 +256,10 @@ CONFIG_RPCMOUSE=y
 #
 # Sound
 #
-# CONFIG_SOUND is not set
-# CONFIG_VIDC is not set
-# CONFIG_AUDIO is not set
-# DSP_BUFFSIZE is not set
+CONFIG_SOUND=m
+CONFIG_VIDC=y
+CONFIG_AUDIO=y
+DSP_BUFFSIZE=65536
 
 #
 # Kernel hacking
index 90e71345af47aa3378d9f3796cd43b8d598298f9..f263b2a7f3e58be63b907240a53ca8775d8a5f1a 100644 (file)
@@ -19,15 +19,24 @@ else
 O_OBJS += armksyms.o
 endif
 
+ifdef CONFIG_PCI
+  O_OBJS += bios32.o
+endif
+
 ifdef CONFIG_ARCH_ACORN
   O_OBJS += setup.o ecard.o iic.o dma.o
   ifdef CONFIG_ARCH_ARC
     O_OBJS += oldlatches.o
   endif
+  O_OBJS += dma-$(MACHINE).o
 endif
 
 ifeq ($(MACHINE),ebsa110)
-  O_OBJS += setup-ebsa110.o dma.o
+  O_OBJS += setup-ebsa110.o dma.o dma-dummy.o
+endif
+
+ifeq ($(MACHINE),ebsa285)
+  O_OBJS += dma.o dma-dummy.o leds-ebsa285.o setup-ebsa110.o
 endif
 
 ifeq ($(MACHINE),nexuspci)
@@ -37,9 +46,12 @@ endif
 $(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
        $(CC) -D__ASSEMBLY__ -traditional -c $(HEAD_OBJ:.o=.S) -o $@
 
+$(ENTRY_OBJ): $(ENTRY_OBJ:.o=.S)
+       $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $(ENTRY_OBJ:.o=.S) -o $@
+
 include $(TOPDIR)/Rules.make
 
-$(ENTRY_OBJ:.o=.S): ../lib/constants.h
+$(ENTRY_OBJ): ../lib/constants.h
 
 .PHONY: ../lib/constants.h
 
index 0079d809520906bc2052d079550e308bf2ec605b..a5b49bf2a5d278ce19cb24e17f86b25e4d693caf 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/dma.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
-#include <asm/irq.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, struct user_fp_struct *);
@@ -64,7 +63,6 @@ extern void fp_send_sig(int);
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(udelay);
-EXPORT_SYMBOL(dma_str);
 EXPORT_SYMBOL(xchg_str);
 
 /* expansion card support */
@@ -78,26 +76,39 @@ EXPORT_SYMBOL(ecard_address);
 /* processor dependencies */
 EXPORT_SYMBOL(processor);
 
-/* irq */
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-
 /* io */
 EXPORT_SYMBOL(outswb);
 EXPORT_SYMBOL(outsw);
 EXPORT_SYMBOL(inswb);
 EXPORT_SYMBOL(insw);
 
-#ifdef CONFIG_ARCH_RPC
-EXPORT_SYMBOL(drambank);
+/* address translation */
+#ifndef __virt_to_phys__is_a_macro
+EXPORT_SYMBOL(__virt_to_phys);
+#endif
+#ifndef __phys_to_virt__is_a_macro
+EXPORT_SYMBOL(__phys_to_virt);
 #endif
+#ifndef __virt_to_bus__is_a_macro
+EXPORT_SYMBOL(__virt_to_bus);
+#endif
+#ifndef __bus_to_virt__is_a_macro
+EXPORT_SYMBOL(__bus_to_virt);
+#endif
+
+EXPORT_SYMBOL(quicklists);
+EXPORT_SYMBOL(__bad_pmd);
+EXPORT_SYMBOL(__bad_pmd_kernel);
 
 /* dma */
+EXPORT_SYMBOL(dma_str);
 EXPORT_SYMBOL(enable_dma);
-EXPORT_SYMBOL(set_dma_mode);
+EXPORT_SYMBOL(disable_dma);
 EXPORT_SYMBOL(set_dma_addr);
 EXPORT_SYMBOL(set_dma_count);
+EXPORT_SYMBOL(set_dma_mode);
 EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(set_dma_sg);
 
 /*
  * floating point math emulator support.
@@ -182,7 +193,3 @@ EXPORT_SYMBOL(change_bit);
 EXPORT_SYMBOL(test_and_change_bit);
 EXPORT_SYMBOL(find_first_zero_bit);
 EXPORT_SYMBOL(find_next_zero_bit);
-
-#if CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
new file mode 100644 (file)
index 0000000..fb5b2e5
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * arch/arm/kernel/bios32.c: PCI functions for ARM
+ *
+ * Copyright (C) 1998 Russell King
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+int pcibios_present(void)
+{
+       return 1;
+}
+
+static unsigned long pcibios_base_address(unsigned char dev_fn)
+{
+       int slot = PCI_SLOT(dev_fn);
+
+       if (slot < 4)
+               return 0xf8000000 + (1 << (19 - slot));
+       else
+               return 0;
+}
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+                            unsigned char where, unsigned char *val)
+{
+       unsigned long addr = pcibios_base_address(dev_fn);
+       unsigned char v;
+
+       if (addr) {
+               __asm__("ldr%?b %0, [%1, %2]"
+                       : "=r" (v)
+                       : "r" (addr), "r" (where));
+               *val = v;
+       } else
+               *val = 0xff;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                            unsigned char where, unsigned short *val)
+{
+       unsigned long addr = pcibios_base_address(dev_fn);
+       unsigned short v;
+
+       if (addr) {
+               __asm__("ldrh%? %0, [%1, %2]"
+                       : "=r" (v)
+                       : "r" (addr), "r" (where));
+               *val = v;
+       } else
+               *val = 0xffff;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+                             unsigned char where, unsigned int *val)
+{
+       unsigned long addr = pcibios_base_address(dev_fn);
+       unsigned int v;
+
+       if (addr) {
+               __asm__("ldr%?  %0, [%1, %2]"
+                       : "=r" (v)
+                       : "r" (addr), "r" (where));
+               *val = v;
+       } else
+               *val = 0xffffffff;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+                            unsigned char where, unsigned char val)
+{
+       unsigned long addr = pcibios_base_address(dev_fn);
+
+       if (addr)
+               __asm__("str%?b %0, [%1, %2]"
+                       : : "r" (val), "r" (addr), "r" (where));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                             unsigned char where, unsigned short val)
+{
+       unsigned long addr = pcibios_base_address(dev_fn);
+
+       if (addr)
+               __asm__("strh%? %0, [%1, %2]"
+                       : : "r" (val), "r" (addr), "r" (where));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+                              unsigned char where, unsigned int val)
+{
+       unsigned long addr = pcibios_base_address(dev_fn);
+
+       if (addr)
+               __asm__("str%?  %0, [%1, %2]"
+                       : : "r" (val), "r" (addr), "r" (where));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int irq[] = { 18, 8, 9, 11 };
+
+__initfunc(void pcibios_fixup(void))
+{
+       struct pci_dev *dev;
+       unsigned char pin;
+
+       for (dev = pci_devices; dev; dev = dev->next) {
+               pcibios_read_config_byte(dev->bus->number,
+                                        dev->devfn,
+                                        PCI_INTERRUPT_PIN,
+                                        &pin);
+
+               dev->irq = irq[(PCI_SLOT(dev->devfn) + pin) & 3];
+
+               pcibios_write_config_byte(dev->bus->number,
+                                         dev->devfn,
+                                         PCI_INTERRUPT_LINE,
+                                         dev->irq);
+
+               printk("PCI: %02x:%02x [%04x/%04x] pin %d irq %d\n",
+                       dev->bus->number, dev->devfn,
+                       dev->vendor, dev->device,
+                       pin, dev->irq);
+       }
+}
+
+__initfunc(void pcibios_init(void))
+{
+       int rev;
+
+       rev = *(unsigned char *)0xfe000008;
+       printk("DEC21285 PCI revision %02X\n", rev);
+}
+
+__initfunc(char *pcibios_setup(char *str))
+{
+       return str;
+}
diff --git a/arch/arm/kernel/dma-a5k.c b/arch/arm/kernel/dma-a5k.c
new file mode 100644 (file)
index 0000000..f722809
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * arch/arm/kernel/dma-a5k.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * DMA functions specific to A5000 architecture
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+
+int arch_request_dma(dmach_t channel, dma_t *dma)
+{
+       if (channel == DMA_VIRTUAL_FLOPPY0)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+       if (channel != DMA_VIRTUAL_FLOPPY0)
+               printk ("arch_free_dma: invalid channel %d\n", channel);
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+       if (channel != DMA_VIRTUAL_FLOPPY0)
+               printk ("arch_dma_count: invalid channel %d\n", dmanr);
+       else {
+               extern int floppy_fiqresidual(void);
+               return floppy_fiqresidual();
+       }
+       return 0;
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+       if (channel != DMA_VIRTUAL_FLOPPY0)
+               printk ("arch_enable_dma: invalid channel %d\n", channel);
+       else {
+               void *fiqhandler_start;
+               unsigned int fiqhandler_length;
+               extern void floppy_fiqsetup (unsigned long len, unsigned long addr,
+                                            unsigned long port);
+
+               if (dma->dma_mode == DMA_MODE_READ) {
+                       extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
+                       fiqhandler_start = &floppy_fiqin_start;
+                       fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
+               } else {
+                       extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
+                       fiqhandler_start = &floppy_fiqout_start;
+                       fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
+               }
+               memcpy ((void *)0x1c, fiqhandler_start, fiqhandler_length);
+               flush_page_to_ram(0);
+               floppy_fiqsetup (dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE);
+               enable_irq (dma->dma_irq);
+       }
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+       if (channel != DMA_VIRTUAL_FLOPPY0)
+               printk ("arch_disable_dma: invalid channel %d\n", channel);
+       else
+               disable_irq (dma->dma_irq);
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+       dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64;
+}
diff --git a/arch/arm/kernel/dma-arc.c b/arch/arm/kernel/dma-arc.c
new file mode 100644 (file)
index 0000000..27a139a
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * arch/arm/kernel/dma-arc.c
+ *
+ * Copyright (C) 1998 Dave Gilbert / Russell King
+ *
+ * DMA functions specific to Archimedes architecture
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+
+int arch_request_dma(dmach_t channel, dma_t *dma)
+{
+       if (channel == DMA_VIRTUAL_FLOPPY0 ||
+           channel == DMA_VIRTUAL_FLOPPY1)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+       if (channel != DMA_VIRTUAL_FLOPPY0 &&
+           channel != DMA_VIRTUAL_FLOPPY1)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+       switch (channel) {
+       case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */
+               switch (dma->dma_mode) {
+               case DMA_MODE_READ: /* read */
+               {
+                       extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end;
+                       extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
+                       unsigned long flags;
+#ifdef DEBUG
+                       printk("enable_dma fdc1772 data read\n");
+#endif
+                       save_flags(flags);
+                       cliIF();
+                       
+                       memcpy ((void *)0x1c, (void *)&fdc1772_dma_read,
+                               &fdc1772_dma_read_end - &fdc1772_dma_read);
+                       fdc1772_setupdma(dma->buf.length, __bus_to_virt(dma->buf.address)); /* Sets data pointer up */
+                       enable_irq (64);
+                       restore_flags(flags);
+               }
+               break;
+
+               case DMA_MODE_WRITE: /* write */
+               {
+                       extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end;
+                       extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
+                       unsigned long flags;
+
+#ifdef DEBUG
+                       printk("enable_dma fdc1772 data write\n");
+#endif
+                       save_flags(flags);
+                       cliIF();
+                       memcpy ((void *)0x1c, (void *)&fdc1772_dma_write,
+                               &fdc1772_dma_write_end - &fdc1772_dma_write);
+                       fdc1772_setupdma(dma->buf.length, __bus_to_virt(dma->buf.address)); /* Sets data pointer up */
+                       enable_irq (64);
+
+                       restore_flags(flags);
+               }
+               break;
+               default:
+                       printk ("enable_dma: dma%d not initialised\n", channel);
+                       return;
+               }
+       }
+       break;
+
+       case DMA_VIRTUAL_FLOPPY1: { /* Command end FIQ - actually just sets a flag */
+               /* Need to build a branch at the FIQ address */
+               extern void fdc1772_comendhandler(void);
+               unsigned long flags;
+
+               /*printk("enable_dma fdc1772 command end FIQ\n");*/
+               save_flags(flags);
+               cliIF();
+       
+               *((unsigned int *)0x1c)=0xea000000 | (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); /* B fdc1772_comendhandler */
+
+               restore_flags(flags);
+       }
+       break;
+       }
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+       if (channel != DMA_VIRTUAL_FLOPPY0 &&
+           channel != DMA_VIRTUAL_FLOPPY1)
+               printk("arch_disable_dma: invalid channel %d\n", channel);
+       else
+               disable_irq(dma->dma_irq);
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+       dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64;
+       dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 65;
+}
diff --git a/arch/arm/kernel/dma-dummy.c b/arch/arm/kernel/dma-dummy.c
new file mode 100644 (file)
index 0000000..af47512
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * arch/arm/kernel/dma-dummy.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * Dummy DMA functions
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *devname)
+{
+       return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+       printk ("arch_free_dma: invalid channel %d\n", channel);
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+       printk ("arch_enable_dma: invalid channel %d\n", channel);
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+       printk ("arch_disable_dma: invalid channel %d\n", channel);
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+       printk ("arch_get_dma_residue: invalid channel %d\n", channel);
+       return 0;
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+}
diff --git a/arch/arm/kernel/dma-rpc.c b/arch/arm/kernel/dma-rpc.c
new file mode 100644 (file)
index 0000000..eb5bc87
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * arch/arm/kernel/dma-rpc.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * DMA functions specific to RiscPC architecture
+ */
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+
+#include "dma.h"
+
+#if 0
+typedef enum {
+       dma_size_8      = 1,
+       dma_size_16     = 2,
+       dma_size_32     = 4,
+       dma_size_128    = 16
+} dma_size_t;
+
+typedef struct {
+       dma_size_t      transfersize;
+} dma_t;
+#endif
+
+#define TRANSFER_SIZE  2
+
+#define CURA   (0)
+#define ENDA   ((IOMD_IO0ENDA - IOMD_IO0CURA) << 2)
+#define CURB   ((IOMD_IO0CURB - IOMD_IO0CURA) << 2)
+#define ENDB   ((IOMD_IO0ENDB - IOMD_IO0CURA) << 2)
+#define CR     ((IOMD_IO0CR - IOMD_IO0CURA) << 2)
+#define ST     ((IOMD_IO0ST - IOMD_IO0CURA) << 2)
+
+#define state_prog_a   0
+#define state_wait_a   1
+#define state_wait_b   2
+
+static void arch_get_next_sg(dmasg_t *sg, dma_t *dma)
+{
+       unsigned long end, offset, flags = 0;
+
+       if (dma->sg) {
+               sg->address = dma->sg->address;
+               offset = sg->address & ~PAGE_MASK;
+
+               end = offset + dma->sg->length;
+
+               if (end > PAGE_SIZE)
+                       end = PAGE_SIZE;
+
+               if (offset + (int) TRANSFER_SIZE > end)
+                       flags |= DMA_END_L;
+
+               sg->length = end - TRANSFER_SIZE;
+
+               dma->sg->length -= end - offset;
+               dma->sg->address += end - offset;
+
+               if (dma->sg->length == 0) {
+                       if (dma->sgcount > 1) {
+                               dma->sg++;
+                               dma->sgcount--;
+                       } else {
+                               dma->sg = NULL;
+                               flags |= DMA_END_S;
+                       }
+               }
+       } else {
+               flags = DMA_END_S | DMA_END_L;
+               sg->address = 0;
+               sg->length = 0;
+       }
+
+       sg->length |= flags;
+}
+
+static inline void arch_setup_dma_a(dmasg_t *sg, dma_t *dma)
+{
+       outl_t(sg->address, dma->dma_base + CURA);
+       outl_t(sg->length, dma->dma_base + ENDA);
+}
+
+static inline void arch_setup_dma_b(dmasg_t *sg, dma_t *dma)
+{
+       outl_t(sg->address, dma->dma_base + CURB);
+       outl_t(sg->length, dma->dma_base + ENDB);
+}
+
+static void arch_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+       dma_t *dma = (dma_t *)dev_id;
+       unsigned int status = 0, no_buffer = dma->sg == NULL;
+
+       do {
+               switch (dma->state) {
+               case state_prog_a:
+                       arch_get_next_sg(&dma->cur_sg, dma);
+                       arch_setup_dma_a(&dma->cur_sg, dma);
+                       dma->state = state_wait_a;
+
+               case state_wait_a:
+                       status = inb_t(dma->dma_base + ST);
+                       switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
+                       case DMA_ST_OFL|DMA_ST_INT:
+                               arch_get_next_sg(&dma->cur_sg, dma);
+                               arch_setup_dma_a(&dma->cur_sg, dma);
+                               break;
+
+                       case DMA_ST_INT:
+                               arch_get_next_sg(&dma->cur_sg, dma);
+                               arch_setup_dma_b(&dma->cur_sg, dma);
+                               dma->state = state_wait_b;
+                               break;
+
+                       case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
+                               arch_setup_dma_b(&dma->cur_sg, dma);
+                               dma->state = state_wait_b;
+                               break;
+                       }
+                       break;
+
+               case state_wait_b:
+                       status = inb_t(dma->dma_base + ST);
+                       switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
+                       case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
+                               arch_get_next_sg(&dma->cur_sg, dma);
+                               arch_setup_dma_b(&dma->cur_sg, dma);
+                               break;
+
+                       case DMA_ST_INT|DMA_ST_AB:
+                               arch_get_next_sg(&dma->cur_sg, dma);
+                               arch_setup_dma_a(&dma->cur_sg, dma);
+                               dma->state = state_wait_a;
+                               break;
+
+                       case DMA_ST_OFL|DMA_ST_INT:
+                               arch_setup_dma_a(&dma->cur_sg, dma);
+                               dma->state = state_wait_a;
+                               break;
+                       }
+                       break;
+               }
+       } while (dma->sg && (status & DMA_ST_INT));
+
+       if (!no_buffer)
+               enable_irq(irq);
+}
+
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
+{
+       unsigned long flags;
+       int ret;
+
+       switch (channel) {
+       case DMA_0:
+       case DMA_1:
+       case DMA_2:
+       case DMA_3:
+       case DMA_S0:
+       case DMA_S1:
+               save_flags_cli(flags);
+               ret = request_irq(dma->dma_irq, arch_dma_handle, SA_INTERRUPT, dev_name, dma);
+               if (!ret)
+                       disable_irq(dma->dma_irq);
+               restore_flags(flags);
+               break;
+
+       case DMA_VIRTUAL_FLOPPY:
+       case DMA_VIRTUAL_SOUND:
+               ret = 0;
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+       switch (channel) {
+       case DMA_0:
+       case DMA_1:
+       case DMA_2:
+       case DMA_3:
+       case DMA_S0:
+       case DMA_S1:
+               free_irq(dma->dma_irq, dma);
+               break;
+
+       default:
+               break;
+       }
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+       int residue = 0;
+
+       switch (channel) {
+       case DMA_0:     /* Physical DMA channels */
+       case DMA_1:
+       case DMA_2:
+       case DMA_3:
+       case DMA_S0:
+       case DMA_S1:
+               break;
+
+       case DMA_VIRTUAL_FLOPPY: {
+               extern int floppy_fiqresidual(void);
+               residue = floppy_fiqresidual();
+               }
+               break;
+       }
+       return residue;
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+       unsigned long dma_base = dma->dma_base;
+       unsigned int ctrl;
+
+       switch (channel) {
+       case DMA_0:     /* Physical DMA channels */
+       case DMA_1:
+       case DMA_2:
+       case DMA_3:
+       case DMA_S0:
+       case DMA_S1:
+               ctrl = TRANSFER_SIZE | DMA_CR_E;
+
+               if (dma->invalid) {
+                       dma->invalid = 0;
+
+                       outb_t(DMA_CR_C, dma_base + CR);
+                       dma->state = state_prog_a;
+               }
+               
+               if (dma->dma_mode == DMA_MODE_READ)
+                       ctrl |= DMA_CR_D;
+
+               outb_t(ctrl, dma_base + CR);
+               enable_irq(dma->dma_irq);
+               break;
+
+       case DMA_VIRTUAL_FLOPPY: {
+               void *fiqhandler_start;
+               unsigned int fiqhandler_length;
+               extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
+                                            unsigned long port);
+
+               if (dma->dma_mode == DMA_MODE_READ) {
+                       extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
+                       fiqhandler_start = &floppy_fiqin_start;
+                       fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
+               } else {
+                       extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
+                       fiqhandler_start = &floppy_fiqout_start;
+                       fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
+               }
+               /* Allow access to page 0 via domains */
+               __asm__ __volatile__("mcr       p15, 0, %0, c3, c0" :
+                                       : "r" (DOMAIN_USER_MANAGER |
+                                              DOMAIN_KERNEL_CLIENT |
+                                              DOMAIN_IO_CLIENT));
+               memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length);
+               /* set domain register to normal */
+               set_fs(get_fs());
+               flush_page_to_ram(0);
+               floppy_fiqsetup(dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE);
+               enable_irq(dma->dma_irq);
+               }
+               break;
+
+       default:
+               break;
+       }
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+       unsigned long dma_base = dma->dma_base;
+       unsigned int ctrl;
+
+       switch (channel) {
+       case DMA_0:     /* Physical DMA channels */
+       case DMA_1:
+       case DMA_2:
+       case DMA_3:
+       case DMA_S0:
+       case DMA_S1:
+               disable_irq(dma->dma_irq);
+               ctrl = inb_t(dma_base + CR);
+               outb_t(ctrl & ~DMA_CR_E, dma_base + CR);
+               break;
+
+       case DMA_VIRTUAL_FLOPPY:
+               disable_irq(dma->dma_irq);
+               break;
+       }
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+       outb(0, IOMD_IO0CR);
+       outb(0, IOMD_IO1CR);
+       outb(0, IOMD_IO2CR);
+       outb(0, IOMD_IO3CR);
+
+//     outb(0xf0, IOMD_DMATCR);
+
+       dma[0].dma_base = ioaddr(IOMD_IO0CURA);
+       dma[0].dma_irq  = IRQ_DMA0;
+       dma[1].dma_base = ioaddr(IOMD_IO1CURA);
+       dma[1].dma_irq  = IRQ_DMA1;
+       dma[2].dma_base = ioaddr(IOMD_IO2CURA);
+       dma[2].dma_irq  = IRQ_DMA2;
+       dma[3].dma_base = ioaddr(IOMD_IO3CURA);
+       dma[3].dma_irq  = IRQ_DMA3;
+       dma[4].dma_base = ioaddr(IOMD_SD0CURA);
+       dma[4].dma_irq  = IRQ_DMAS0;
+       dma[5].dma_base = ioaddr(IOMD_SD1CURA);
+       dma[5].dma_irq  = IRQ_DMAS1;
+       dma[6].dma_irq  = 64;
+
+       /* Setup DMA channels 2,3 to be for podules
+        * and channels 0,1 for internal devices
+        */
+       outb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
+}
index 3c165c41df4d56be9edfd16bc44f59aa15bd2892..6058a286308d124b475877f0b16e461727f7ebf7 100644 (file)
 /*
  * linux/arch/arm/kernel/dma.c
  *
- * Copyright (C) 1995, 1996 Russell King
+ * Copyright (C) 1995-1998 Russell King
+ *
+ * Front-end to the DMA handling.  You must provide the following
+ * architecture-specific routines:
+ *
+ *  int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_id);
+ *  void arch_free_dma(dmach_t channel, dma_t *dma);
+ *  void arch_enable_dma(dmach_t channel, dma_t *dma);
+ *  void arch_disable_dma(dmach_t channel, dma_t *dma);
+ *  int arch_get_dma_residue(dmach_t channel, dma_t *dma);
+ *
+ * Moved DMA resource allocation here...
  */
-
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/malloc.h>
 #include <linux/mman.h>
+#include <linux/init.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
-#define KERNEL_ARCH_DMA
 #include <asm/dma.h>
 
-static unsigned long dma_address[8];
-static unsigned long dma_count[8];
-static char dma_direction[8] = { -1, -1, -1, -1, -1, -1, -1};
+#include "dma.h"
 
-#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC)
-#define DMA_PCIO
-#endif
-#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD)
-#define DMA_OLD
-#endif
+static dma_t dma_chan[MAX_DMA_CHANNELS];
 
-void enable_dma (unsigned int dmanr)
+/* Get dma list
+ * for /proc/dma
+ */
+int get_dma_list(char *buf)
 {
-       switch (dmanr) {
-#ifdef DMA_PCIO
-               case 2: {
-                       void *fiqhandler_start;
-                       unsigned int fiqhandler_length;
-                       extern void floppy_fiqsetup (unsigned long len, unsigned long addr,
-                                       unsigned long port);
-                       switch (dma_direction[dmanr]) {
-                       case 1: {
-                               extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
-                               fiqhandler_start = &floppy_fiqin_start;
-                               fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
-                               break;
-                       }
-                       case 0: {
-                               extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
-                               fiqhandler_start = &floppy_fiqout_start;
-                               fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
-                               break;
-                       }
-                       default:
-                               printk ("enable_dma: dma%d not initialised\n", dmanr);
-                               return;
-                       }
-                       memcpy ((void *)0x1c, fiqhandler_start, fiqhandler_length);
-                       flush_page_to_ram(0);
-                       floppy_fiqsetup (dma_count[dmanr], dma_address[dmanr], (int)PCIO_FLOPPYDMABASE);
-                       enable_irq (64);
-                       return;
-               }
-#endif
-#ifdef DMA_OLD
-               case 0: { /* Data DMA */
-                       switch (dma_direction[dmanr]) {
-                       case 1: /* read */
-                       {
-                               extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end;
-                               extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
-                               unsigned long flags;
-#ifdef DEBUG
-                               printk("enable_dma fdc1772 data read\n");
-#endif
-                               save_flags(flags);
-                               cliIF();
-                       
-                               memcpy ((void *)0x1c, (void *)&fdc1772_dma_read,
-                                       &fdc1772_dma_read_end - &fdc1772_dma_read);
-                               fdc1772_setupdma(dma_count[dmanr],dma_address[dmanr]); /* Sets data pointer up */
-                               enable_irq (64);
-                               restore_flags(flags);
-                       }
-                       break;
-
-                       case 0: /* write */
-                       {
-                               extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end;
-                               extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
-                               unsigned long flags;
-
-#ifdef DEBUG
-                               printk("enable_dma fdc1772 data write\n");
-#endif
-                               save_flags(flags);
-                               cliIF();
-                               memcpy ((void *)0x1c, (void *)&fdc1772_dma_write,
-                                       &fdc1772_dma_write_end - &fdc1772_dma_write);
-                               fdc1772_setupdma(dma_count[dmanr],dma_address[dmanr]); /* Sets data pointer up */
-                               enable_irq (64);
-
-                               restore_flags(flags);
-                       }
-                       break;
-                       default:
-                               printk ("enable_dma: dma%d not initialised\n", dmanr);
-                               return;
-                       }
-               }
-               break;
+       int i, len = 0;
 
-               case 1: { /* Command end FIQ - actually just sets a flag */
-                       /* Need to build a branch at the FIQ address */
-                       extern void fdc1772_comendhandler(void);
-                       unsigned long flags;
+       for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+               if (dma_chan[i].lock)
+                       len += sprintf(buf + len, "%2d: %s\n",
+                                      i, dma_chan[i].device_id);
+       }
+       return len;
+}
 
-                       /*printk("enable_dma fdc1772 command end FIQ\n");*/
-                       save_flags(flags);
-                       cliIF();
-       
-                       *((unsigned int *)0x1c)=0xea000000 | (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); /* B fdc1772_comendhandler */
+/* Request DMA channel
+ *
+ * On certain platforms, we have to allocate an interrupt as well...
+ */
+int request_dma(dmach_t channel, const char *device_id)
+{
+       if (channel < MAX_DMA_CHANNELS) {
+               int ret;
+
+               if (xchg(&dma_chan[channel].lock, 1) != 0)
+                       return -EBUSY;
+
+               ret = arch_request_dma(channel, &dma_chan[channel], device_id);
+               if (!ret) {
+                       dma_chan[channel].device_id = device_id;
+                       dma_chan[channel].active    = 0;
+                       dma_chan[channel].invalid   = 1;
+               } else
+                       xchg(&dma_chan[channel].lock, 0);
+
+               return ret;
+       } else {
+               printk (KERN_ERR "Trying to allocate DMA%d\n", channel);
+               return -EINVAL;
+       }
+}
+
+/* Free DMA channel
+ *
+ * On certain platforms, we have to free interrupt as well...
+ */
+void free_dma(dmach_t channel)
+{
+       if (channel >= MAX_DMA_CHANNELS) {
+               printk (KERN_ERR "Trying to free DMA%d\n", channel);
+               return;
+       }
 
-                       restore_flags(flags);
+       if (xchg(&dma_chan[channel].lock, 0) == 0) {
+               if (dma_chan[channel].active) {
+                       printk (KERN_ERR "Freeing active DMA%d\n", channel);
+                       arch_disable_dma(channel, &dma_chan[channel]);
+                       dma_chan[channel].active = 0;
                }
-               break;
-#endif
-               case DMA_0:
-               case DMA_1:
-               case DMA_2:
-               case DMA_3:
-               case DMA_S0:
-               case DMA_S1:
-                       arch_enable_dma (dmanr - DMA_0);
-                       break;
-
-               default:
-                       printk ("enable_dma: dma %d not supported\n", dmanr);
+
+               printk (KERN_ERR "Trying to free free DMA%d\n", channel);
+               return;
        }
+       arch_free_dma(channel, &dma_chan[channel]);
+}
+
+/* Set DMA Scatter-Gather list
+ */
+void set_dma_sg (dmach_t channel, dmasg_t *sg, int nr_sg)
+{
+       dma_chan[channel].sg = sg;
+       dma_chan[channel].sgcount = nr_sg;
+       dma_chan[channel].invalid = 1;
 }
 
-void set_dma_mode (unsigned int dmanr, char mode)
+/* Set DMA address
+ *
+ * Copy address to the structure, and set the invalid bit
+ */
+void set_dma_addr (dmach_t channel, unsigned long physaddr)
 {
-       if (dmanr < 8) {
-               if (mode == DMA_MODE_READ)
-                       dma_direction[dmanr] = 1;
-               else if (mode == DMA_MODE_WRITE)
-                       dma_direction[dmanr] = 0;
-               else
-                       printk ("set_dma_mode: dma%d: invalid mode %02X not supported\n",
-                               dmanr, mode);
-       } else if (dmanr < MAX_DMA_CHANNELS)
-               arch_set_dma_mode (dmanr - DMA_0, mode);
-       else
-               printk ("set_dma_mode: dma %d not supported\n", dmanr);
+       if (dma_chan[channel].active)
+               printk(KERN_ERR "set_dma_addr: altering DMA%d"
+                      " address while DMA active\n",
+                      channel);
+
+       dma_chan[channel].sg = &dma_chan[channel].buf;
+       dma_chan[channel].sgcount = 1;
+       dma_chan[channel].buf.address = physaddr;
+       dma_chan[channel].invalid = 1;
 }
 
-void set_dma_addr (unsigned int dmanr, unsigned int addr)
+/* Set DMA byte count
+ *
+ * Copy address to the structure, and set the invalid bit
+ */
+void set_dma_count (dmach_t channel, unsigned long count)
 {
-       if (dmanr < 8)
-               dma_address[dmanr] = (unsigned long)addr;
-       else if (dmanr < MAX_DMA_CHANNELS)
-               arch_set_dma_addr (dmanr - DMA_0, addr);
-       else
-               printk ("set_dma_addr: dma %d not supported\n", dmanr);
+       if (dma_chan[channel].active)
+               printk(KERN_ERR "set_dma_count: altering DMA%d"
+                      " count while DMA active\n",
+                      channel);
+
+       dma_chan[channel].sg = &dma_chan[channel].buf;
+       dma_chan[channel].sgcount = 1;
+       dma_chan[channel].buf.length = count;
+       dma_chan[channel].invalid = 1;
 }
 
-void set_dma_count (unsigned int dmanr, unsigned int count)
+/* Set DMA direction mode
+ */
+void set_dma_mode (dmach_t channel, dmamode_t mode)
 {
-       if (dmanr < 8)
-               dma_count[dmanr] = (unsigned long)count;
-       else if (dmanr < MAX_DMA_CHANNELS)
-               arch_set_dma_count (dmanr - DMA_0, count);
-       else
-               printk ("set_dma_count: dma %d not supported\n", dmanr);
+       if (dma_chan[channel].active)
+               printk(KERN_ERR "set_dma_mode: altering DMA%d"
+                      " mode while DMA active\n",
+                      channel);
+
+       dma_chan[channel].dma_mode = mode;
+       dma_chan[channel].invalid = 1;
 }
 
-int get_dma_residue (unsigned int dmanr)
+/* Enable DMA channel
+ */
+void enable_dma (dmach_t channel)
 {
-       if (dmanr < 8) {
-               switch (dmanr) {
-#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC)
-               case 2: {
-                       extern int floppy_fiqresidual (void);
-                       return floppy_fiqresidual ();
-               }
-#endif
-#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD)
-               case 0: {
-                       extern unsigned int fdc1772_bytestogo;
-                       return fdc1772_bytestogo;
+       if (dma_chan[channel].lock) {
+               if (dma_chan[channel].active == 0) {
+                       dma_chan[channel].active = 1;
+                       arch_enable_dma(channel, &dma_chan[channel]);
                }
-#endif
-               default:
-                       return -1;
+       } else
+               printk (KERN_ERR "Trying to enable free DMA%d\n", channel);
+}
+
+/* Disable DMA channel
+ */
+void disable_dma (dmach_t channel)
+{
+       if (dma_chan[channel].lock) {
+               if (dma_chan[channel].active == 1) {
+                       dma_chan[channel].active = 0;
+                       arch_disable_dma(channel, &dma_chan[channel]);
                }
-       } else if (dmanr < MAX_DMA_CHANNELS)
-               return arch_dma_count (dmanr - DMA_0);
-       return -1;
+       } else
+               printk (KERN_ERR "Trying to disable free DMA%d\n", channel);
+}
+
+int get_dma_residue(dmach_t channel)
+{
+       return arch_get_dma_residue(channel, &dma_chan[channel]);
+}
+
+__initfunc(void init_dma(void))
+{
+       arch_dma_init(dma_chan);
 }
diff --git a/arch/arm/kernel/dma.h b/arch/arm/kernel/dma.h
new file mode 100644 (file)
index 0000000..e4c72c6
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/kernel/dma.h
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * This header file describes the interface between the generic DMA handler
+ * (dma.c) and the architecture-specific DMA backends (dma-*.c)
+ */
+
+typedef struct {
+       dmasg_t         buf;            /* single DMA                   */
+       int             sgcount;        /* number of DMA SG             */
+       dmasg_t         *sg;            /* DMA Scatter-Gather List      */
+
+       unsigned int    active:1;       /* Transfer active              */
+       unsigned int    invalid:1;      /* Address/Count changed        */
+       dmamode_t       dma_mode;       /* DMA mode                     */
+
+       unsigned int    lock;           /* Device is allocated          */
+       const char      *device_id;     /* Device name                  */
+
+       unsigned int    dma_base;       /* Controller base address      */
+       int             dma_irq;        /* Controller IRQ               */
+       int             state;          /* Controller state             */
+       dmasg_t         cur_sg;         /* Current controller buffer    */
+} dma_t;
+
+/* Prototype: int arch_request_dma(channel, dma, dev_id)
+ * Purpose  : Perform architecture specific claiming of a DMA channel
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure (above) for channel
+ *          : dev_id  - device ID string passed with request
+ * Returns  : 0 on success, E????? number on error
+ */ 
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_id);
+
+/* Prototype: int arch_free_dma(channel, dma)
+ * Purpose  : Perform architecture specific freeing of a DMA channel
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ */
+void arch_free_dma(dmach_t channel, dma_t *dma);
+
+/* Prototype: void arch_enable_dma(channel, dma)
+ * Purpose  : Enable a claimed DMA channel
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ */
+void arch_enable_dma(dmach_t channel, dma_t *dma);
+
+/* Prototype: void arch_disable_dma(channel, dma)
+ * Purpose  : Disable a claimed DMA channel
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ */
+void arch_disable_dma(dmach_t channel, dma_t *dma);
+
+/* Prototype: int arch_get_dma_residue(channel, dma)
+ * Purpose  : Return number of bytes left to DMA
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ * Returns  : Number of bytes left to DMA
+ */
+int arch_get_dma_residue(dmach_t channel, dma_t *dma);
+
+/* Prototype: void arch_dma_init(dma)
+ * Purpose  : Initialise architecture specific DMA
+ * Params   : dma - pointer to array of DMA structures
+ */
+void arch_dma_init(dma_t *dma);
index cc18252b3e6511cd6c72e2481f365650ea6c90a4..f03147e661e55287acffe116a4f860f29e4e29a5 100644 (file)
@@ -13,6 +13,7 @@
  *                     now register their own routine to control interrupts (recommended).
  * 29-Sep-1997 RMK     Expansion card interrupt hardware not being re-enabled on reset from
  *                     Linux. (Caused cards not to respond under RiscOS without hard reset).
+ * 15-Feb-1998 RMK     Added DMA support
  */
 
 #define ECARD_C
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
-#include <asm/irq-no.h>
-#include <asm/ecard.h>
-#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/arch/irq.h>
+#include <asm/ecard.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
 
 #ifdef CONFIG_ARCH_ARC
 #include <asm/arch/oldlatches.h>
@@ -59,9 +61,11 @@ static const struct expcard_blacklist {
   BLACKLIST_LOADER(MANU_ATOMWIDE,      PROD_ATOMWIDE_3PSERIAL, atomwide_serial_loader),
   BLACKLIST_LOADER(MANU_OAK,           PROD_OAK_SCSI,          oak_scsi_loader),
 
+/* Supported cards with broken loader */
+  { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI, noloader, "AlSystems PowerTec SCSI (loader blacklisted)" },
+
 /* Unsupported cards with no loader */
-BLACKLIST_NOLOADER(MANU_ALSYSTEMS,     PROD_ALSYS_SCSIATAPI),
-BLACKLIST_NOLOADER(MANU_MCS,           PROD_MCS_CONNECT32)
+  BLACKLIST_NOLOADER(MANU_MCS,         PROD_MCS_CONNECT32)
 };
 
 extern int setup_arm_irq(int, struct irqaction *);
@@ -75,7 +79,6 @@ static ecard_t expcard[MAX_ECARDS];
 static signed char irqno_to_expcard[16];
 static unsigned int ecard_numcards, ecard_numirqcards;
 static unsigned int have_expmask;
-static unsigned long kmem;
 
 static void ecard_def_irq_enable (ecard_t *ec, int irqnr)
 {
@@ -178,20 +181,6 @@ void ecard_disablefiq (unsigned int fiqnr)
        }
 }
 
-static void *ecard_malloc(int len)
-{
-       int r;
-
-       len = (len + 3) & ~3;
-
-       if (kmem) {
-               r = kmem;
-               kmem += len;
-               return (void *)r;
-       } else
-               return kmalloc(len, GFP_KERNEL);
-}
-
 static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
 {
        const int num_cards = ecard_numirqcards;
@@ -301,13 +290,13 @@ static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int usel
                        lowaddress = 0;
                }
                while (lowaddress <= laddr) {
-                       byte = inb (ec->podaddr + haddr);
+                       byte = inb(ec->podaddr + haddr);
                        lowaddress += 1;
                }
                while (len--) {
                        *a++ = byte;
                        if (len) {
-                               byte = inb (ec->podaddr + haddr);
+                               byte = inb(ec->podaddr + haddr);
                                lowaddress += 1;
                        }
                }
@@ -417,7 +406,7 @@ int ecard_readchunk (struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
                }
                if (c_id(&excd) == 0x80) { /* loader */
                        if (!ec->loader) {
-                               ec->loader = (loader_t)ecard_malloc(c_len(&excd));
+                               ec->loader = (loader_t)kmalloc(c_len(&excd), GFP_KERNEL);
                                ecard_readbytes(ec->loader, ec, (int)c_start(&excd), c_len(&excd), useld);
                        }
                        continue;
@@ -441,20 +430,39 @@ int ecard_readchunk (struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
        return 1;
 }
 
-unsigned int ecard_address (ecard_t *ec, card_type_t memc, card_speed_t speed)
+unsigned int ecard_address (ecard_t *ec, card_type_t type, card_speed_t speed)
 {
        switch (ec->slot_no) {
        case 0:
        case 1:
        case 2:
        case 3:
-               return (memc ? MEMCECIO_BASE : IOCECIO_BASE + (speed << 17)) + (ec->slot_no << 12);
+               switch (type) {
+               case ECARD_MEMC:
+                       return MEMCECIO_BASE + (ec->slot_no << 12);
+
+               case ECARD_IOC:
+                       return IOCECIO_BASE + (speed << 17) + (ec->slot_no << 12);
+
+               default:
+                       return 0;
+               }
+
 #ifdef IOCEC4IO_BASE
        case 4:
        case 5:
        case 6:
        case 7:
-               return (memc ? 0 : IOCEC4IO_BASE + (speed << 17)) + ((ec->slot_no - 4) << 12);
+               switch (type) {
+               case ECARD_MEMC:
+                       return 0;
+
+               case ECARD_IOC:
+                       return IOCEC4IO_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
+
+               default:
+                       return 0;
+               }
 #endif
 #ifdef MEMCEC8IO_BASE
        case 8:
@@ -470,7 +478,7 @@ unsigned int ecard_address (ecard_t *ec, card_type_t memc, card_speed_t speed)
  * If bit 1 of the first byte of the card is set,
  * then the card does not exist.
  */
-static int ecard_probe (int card, int freeslot)
+__initfunc(static int ecard_probe (int card, int freeslot))
 {
        ecard_t *ec = expcard + freeslot;
        struct ex_ecld excld;
@@ -480,7 +488,7 @@ static int ecard_probe (int card, int freeslot)
        irqno_to_expcard[card] = -1;
 
        ec->slot_no = card;
-       if ((ec->podaddr = ecard_address (ec, 0, ECARD_SYNC)) == 0)
+       if ((ec->podaddr = ecard_address (ec, ECARD_IOC, ECARD_SYNC)) == 0)
                return 0;
 
        excld.r_ecld = 2;
@@ -490,8 +498,9 @@ static int ecard_probe (int card, int freeslot)
 
        irqno_to_expcard[card] = freeslot;
 
-       ec->irq = -1;
-       ec->fiq = -1;
+       ec->irq = NO_IRQ;
+       ec->fiq = NO_IRQ;
+       ec->dma = NO_DMA;
        ec->cld.ecld = e_ecld(&excld);
        ec->cld.manufacturer = e_manu(&excld);
        ec->cld.product = e_prod(&excld);
@@ -514,15 +523,20 @@ static int ecard_probe (int card, int freeslot)
                        break;
                }
 
-       if (card != 8) {
-               ec->irq = 32 + card;
+       ec->irq = 32 + card;
 #if 0
-               ec->fiq = 96 + card;
+       /* We don't support FIQs on expansion cards at the moment */
+       ec->fiq = 96 + card;
 #endif
-       } else {
+#ifdef CONFIG_ARCH_RPC
+       if (card != 8) {
+               /* On RiscPC, only first two slots have DMA capability
+                */
+               if (card < 2)
+                       ec->dma = 2 + card;
+       } else
                ec->irq = 11;
-               ec->fiq = -1;
-       }
+#endif
 
        if ((ec->cld.ecld & 0x78) == 0) {
                struct in_chunk_dir incd;
@@ -551,11 +565,10 @@ static struct irqaction irqexpansioncard = { ecard_irq_noexpmask, SA_INTERRUPT,
  * Locate all hardware - interrupt management and
  * actual cards.
  */
-unsigned long ecard_init(unsigned long start_mem)
+__initfunc(void ecard_init(void))
 {
        int i, nc = 0;
 
-       kmem = (start_mem | 3) & ~3;
        memset (expcard, 0, sizeof (expcard));
 
 #ifdef HAS_EXPMASK
@@ -565,6 +578,7 @@ unsigned long ecard_init(unsigned long start_mem)
                have_expmask = -1;
        }
 #endif
+
        printk("Installed expansion cards:");
 
        /*
@@ -578,27 +592,25 @@ unsigned long ecard_init(unsigned long start_mem)
 
        ecard_numirqcards = nc;
 
-       /*
-        * Now probe other cards with different interrupt lines
+       /* Now probe other cards with different interrupt lines
         */
 #ifdef MEMCEC8IO_BASE
        if (ecard_probe (8, nc))
                nc += 1;
 #endif
+
        printk("\n");
        ecard_numcards = nc;
 
        if (nc && setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) {
                printk ("Could not allocate interrupt for expansion cards\n");
-               return kmem;
+               return;
        }
        
 #ifdef HAS_EXPMASK
        if (nc && have_expmask)
                EXPMASK_ENABLE = have_expmask;
 #endif
+
        oldlatch_init ();
-       start_mem = kmem;
-       kmem = 0;
-       return start_mem;       
 }
index a2de41f33b6d95526cb70fcea6b782d0ba2f9509..f2d752cd46229c502bd5e96e4722839bff576e6c 100644 (file)
@@ -9,7 +9,7 @@
  * Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes
  * it to save wrong values...  Be aware!
  */
-#include <linux/config.h> /* for CONFIG_ARCH_EBSA110 /*
+#include <linux/config.h> /* for CONFIG_ARCH_EBSA110 */
 #include <linux/autoconf.h>
 #include <linux/linkage.h>
 
 
                .text
 
-@ Offsets into task structure
-@ ---------------------------
-@
-#define STATE          0
-#define COUNTER                4
-#define PRIORITY       8
-#define FLAGS          12
-#define SIGPENDING     16
-
 #define PF_TRACESYS    0x20
 
 @ Bad Abort numbers
                strb    r12, [r12, #0x38]       @ Disable FIQ register
                .endm
 
-               .macro  get_irqnr_and_base, irqnr, base
+               .macro  get_irqnr_and_base, irqnr, irqstat, base
                mov     r4, #ioc_base_high              @ point at IOC
                .if     ioc_base_low
                orr     r4, r4, #ioc_base_low
                .endif
-               ldrb    \irqnr, [r4, #0x24]             @ get high priority first
+               ldrb    \irqstat, [r4, #0x24]           @ get high priority first
                adr     \base, irq_prio_h
-               teq     \irqnr, #0
+               teq     \irqstat, #0
 #ifdef IOMD_BASE
-               ldreqb  \irqnr, [r4, #0x1f4]            @ get dma
+               ldreqb  \irqstat, [r4, #0x1f4]          @ get dma
                adreq   \base, irq_prio_d
-               teqeq   \irqnr, #0
+               teqeq   \irqstat, #0
 #endif
-               ldreqb  \irqnr, [r4, #0x14]             @ get low priority
+               ldreqb  \irqstat, [r4, #0x14]           @ get low priority
                adreq   \base, irq_prio_l
+
+               teq     \irqstat, #0
+               ldrneb  \irqnr, [r5, \irqstat]          @ get IRQ number
                .endm
 
 /*
@@ -160,10 +154,13 @@ irq_prio_h:       .byte    0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
                .macro  disable_fiq
                .endm
 
-               .macro  get_irqnr_and_base, irqnr, base
+               .macro  get_irqnr_and_base, irqnr, irqstat, base
                mov     r4, #0xf3000000
-               ldrb    \irqnr, [r4]                    @ get interrupts
+               ldrb    \irqstat, [r4]                  @ get interrupts
                adr     \base, irq_prio_ebsa110
+
+               teq     \irqstat, #0
+               ldrneb  \irqnr, [r5, \irqstat]          @ get IRQ number
                .endm
 
                .macro  irq_prio_table
@@ -189,6 +186,26 @@ irq_prio_ebsa110:
                .byte    6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2
                .endm
 
+#elif defined(CONFIG_ARCH_EBSA285)
+
+               .macro  disable_fiq
+               .endm
+
+               .macro  get_irqnr_and_base, irqnr, irqstat, base
+               mov     r4, #0xfe000000
+               ldr     \irqstat, [r4, #0x180]          @ get interrupts
+               mov     \irqnr, #0
+1001:          tst     \irqstat, #1
+               addeq   \irqnr, \irqnr, #1
+               moveq   \irqstat, \irqstat, lsr #1
+               tsteq   \irqnr, #32
+               beq     1001b
+               teq     \irqnr, #32
+               .endm
+
+               .macro  irq_prio_table
+               .endm
+
 #else
 #error Unknown architecture
 #endif
@@ -266,6 +283,16 @@ irq_prio_ebsa110:
                adr\cond        \reg, \label
                .endm
 
+/*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen, and won't happen in 32-bit mode).
+ */
+
+vector_addrexcptn:
+               b       vector_addrexcptn
+
 /*=============================================================================
  * Undefined FIQs
  *-----------------------------------------------------------------------------
@@ -399,86 +426,6 @@ vector_data:       @
                b       __dabt_invalid                  @  2  (IRQ_26 / IRQ_32)
                b       __dabt_svc                      @  3  (SVC_26 / SVC_32)
 
-/*=============================================================================
- * Undefined instruction handler
- *-----------------------------------------------------------------------------
- * Handles floating point instructions
- */
-__und_usr:     sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
-               stmia   sp, {r0 - r12}                  @ Save r0 - r12
-               add     r8, sp, #S_PC
-               stmdb   r8, {sp, lr}^                   @ Save user r0 - r12
-               ldr     r4, .LCund
-               ldmia   r4, {r5 - r7}
-               stmia   r8, {r5 - r7}                   @ Save USR pc, cpsr, old_r0
-               mov     fp, #0
-
-               adr     r1, .LC2
-               ldmia   r1, {r1, r4}
-               ldr     r1, [r1]
-               get_current_task r2
-               teq     r1, r2
-               blne    SYMBOL_NAME(math_state_restore)
-               adrsvc, al, r9, SYMBOL_NAME(fpreturn)
-               adrsvc  al, lr, SYMBOL_NAME(fpundefinstr)
-               ldr     pc, [r4]                        @ Call FP module USR entry point
-
-               .globl  SYMBOL_NAME(fpundefinstr)
-SYMBOL_NAME(fpundefinstr):                             @ Called by FP module on undefined instr
-               mov     r0, lr
-               mov     r1, sp
-               mrs     r4, cpsr                        @ Enable interrupts
-               bic     r4, r4, #I_BIT
-               msr     cpsr, r4
-               bl      SYMBOL_NAME(do_undefinstr)
-               b       ret_from_exception              @ Normal FP exit
-
-__und_svc:     sub     sp, sp, #S_FRAME_SIZE
-               stmia   sp, {r0 - r12}                  @ save r0 - r12
-               mov     r6, lr
-               ldr     r7, .LCund
-               ldmia   r7, {r7 - r9}
-               add     r5, sp, #S_FRAME_SIZE
-               add     r4, sp, #S_SP
-               stmia   r4, {r5 - r9}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-
-               adr     r1, .LC2
-               ldmia   r1, {r1, r4}
-               ldr     r1, [r1]
-               mov     r2, sp, lsr #13
-               mov     r2, r2, lsl #13
-               teq     r1, r2
-               blne    SYMBOL_NAME(math_state_restore)
-               adrsvc  al, r9, SYMBOL_NAME(fpreturnsvc)
-               adrsvc  al, lr, SYMBOL_NAME(fpundefinstrsvc)
-               ldr     pc, [r4]                        @ Call FP module SVC entry point
-
-               .globl  SYMBOL_NAME(fpundefinstrsvc)
-SYMBOL_NAME(fpundefinstrsvc):
-               mov     r0, r5                          @ unsigned long pc
-               mov     r1, sp                          @ struct pt_regs *regs
-               bl      SYMBOL_NAME(do_undefinstr)
-
-               .globl  SYMBOL_NAME(fpreturnsvc)
-SYMBOL_NAME(fpreturnsvc):
-               ldr     lr, [sp, #S_PSR]                @ Get SVC cpsr
-               msr     spsr, lr
-               ldmia   sp, {r0 - pc}^                  @ Restore SVC registers
-
-.LC2:          .word   SYMBOL_NAME(last_task_used_math)
-               .word   SYMBOL_NAME(fp_enter)
-
-__und_invalid: sub     sp, sp, #S_FRAME_SIZE
-               stmia   sp, {r0 - lr}
-               mov     r7, r0
-               ldr     r4, .LCund
-               ldmia   r4, {r5, r6}                    @ Get UND/IRQ/FIQ/ABT pc, cpsr
-               add     r4, sp, #S_PC
-               stmia   r4, {r5, r6, r7}                @ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0
-               mov     r0, sp                          @ struct pt_regs *regs
-               mov     r1, #BAD_UNDEFINSTR             @ int reason
-               and     r2, r6, #31                     @ int mode
-               b       SYMBOL_NAME(bad_mode)           @ Does not ever return...
 /*=============================================================================
  * Prefetch abort handler
  *-----------------------------------------------------------------------------
@@ -531,14 +478,62 @@ t:                .ascii "*** undef ***\r\n\0"
 #endif
 
 /*=============================================================================
- * Address exception handler
+ * Data abort handler code
  *-----------------------------------------------------------------------------
- * These aren't too critical.
- * (they're not supposed to happen, and won't happen in 32-bit mode).
  */
+.LCprocfns:    .word   SYMBOL_NAME(processor)
 
-vector_addrexcptn:
-               b       vector_addrexcptn
+__dabt_usr:    sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
+               stmia   sp, {r0 - r12}                  @ save r0 - r12
+               add     r3, sp, #S_PC
+               stmdb   r3, {sp, lr}^
+               ldr     r0, .LCabt
+               ldmia   r0, {r0 - r2}                   @ Get USR pc, cpsr
+               stmia   r3, {r0 - r2}                   @ Save USR pc, cpsr, old_r0
+               mov     fp, #0
+               mrs     r2, cpsr                        @ Enable interrupts if they were
+               bic     r2, r2, #I_BIT                  @ previously
+               msr     cpsr, r2
+               ldr     r2, .LCprocfns
+               mov     lr, pc
+               ldr     pc, [r2, #8]                    @ call processor specific code
+               mov     r3, sp
+               bl      SYMBOL_NAME(do_DataAbort)
+               b       ret_from_sys_call
+
+__dabt_svc:    sub     sp, sp, #S_FRAME_SIZE
+               stmia   sp, {r0 - r12}                  @ save r0 - r12
+               ldr     r2, .LCabt
+               add     r0, sp, #S_FRAME_SIZE
+               add     r5, sp, #S_SP
+               mov     r1, lr
+               ldmia   r2, {r2 - r4}                   @ get pc, cpsr
+               stmia   r5, {r0 - r4}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
+               tst     r3, #I_BIT
+               mrseq   r0, cpsr                        @ Enable interrupts if they were
+               biceq   r0, r0, #I_BIT                  @ previously
+               msreq   cpsr, r0
+               mov     r0, r2
+               ldr     r2, .LCprocfns
+               mov     lr, pc
+               ldr     pc, [r2, #8]                    @ call processor specific code
+               mov     r3, sp
+               bl      SYMBOL_NAME(do_DataAbort)
+               ldr     r0, [sp, #S_PSR]
+               msr     spsr, r0
+               ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
+
+__dabt_invalid:        sub     sp, sp, #S_FRAME_SIZE
+               stmia   sp, {r0 - lr}                   @ Save SVC r0 - lr [lr *should* be intact]
+               mov     r7, r0
+               ldr     r4, .LCabt
+               ldmia   r4, {r5, r6}                    @ Get SVC pc, cpsr
+               add     r4, sp, #S_PC
+               stmia   r4, {r5, r6, r7}                @ Save SVC pc, cpsr, old_r0
+               mov     r0, sp
+               mov     r1, #BAD_DATA
+               and     r2, r6, #31
+               b       SYMBOL_NAME(bad_mode)
 
 /*=============================================================================
  * Interrupt (IRQ) handler
@@ -551,9 +546,7 @@ __irq_usr:  sub     sp, sp, #S_FRAME_SIZE
                ldr     r4, .LCirq
                ldmia   r4, {r5 - r7}                   @ get saved PC, SPSR
                stmia   r8, {r5 - r7}                   @ save pc, psr, old_r0
-1:             get_irqnr_and_base r6, r5
-               teq     r6, #0
-               ldrneb  r0, [r5, r6]                    @ get IRQ number
+1:             get_irqnr_and_base r0, r6, r5
                movne   r1, sp
                @
                @ routine called with r0 = irq number, r1 = struct pt_regs *
@@ -572,9 +565,7 @@ __irq_svc:  sub     sp, sp, #S_FRAME_SIZE
                add     r5, sp, #S_FRAME_SIZE
                add     r4, sp, #S_SP
                stmia   r4, {r5, r6, r7, r8, r9}        @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-1:             get_irqnr_and_base r6, r5
-               teq     r6, #0
-               ldrneb  r0, [r5, r6]                    @ get IRQ number
+1:             get_irqnr_and_base r0, r6, r5
                movne   r1, sp
                @
                @ routine called with r0 = irq number, r1 = struct pt_regs *
@@ -598,63 +589,85 @@ __irq_invalid:    sub     sp, sp, #S_FRAME_SIZE   @ Allocate space on stack for frame
                b       SYMBOL_NAME(bad_mode)
 
 /*=============================================================================
- * Data abort handler code
+ * Undefined instruction handler
  *-----------------------------------------------------------------------------
+ * Handles floating point instructions
  */
-.LCprocfns:    .word   SYMBOL_NAME(processor)
-
-__dabt_usr:    sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
-               stmia   sp, {r0 - r12}                  @ save r0 - r12
-               add     r3, sp, #S_PC
-               stmdb   r3, {sp, lr}^
-               ldr     r0, .LCabt
-               ldmia   r0, {r0 - r2}                   @ Get USR pc, cpsr
-               stmia   r3, {r0 - r2}                   @ Save USR pc, cpsr, old_r0
+__und_usr:     sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
+               stmia   sp, {r0 - r12}                  @ Save r0 - r12
+               add     r8, sp, #S_PC
+               stmdb   r8, {sp, lr}^                   @ Save user r0 - r12
+               ldr     r4, .LCund
+               ldmia   r4, {r5 - r7}
+               stmia   r8, {r5 - r7}                   @ Save USR pc, cpsr, old_r0
                mov     fp, #0
-               mrs     r2, cpsr                        @ Enable interrupts if they were
-               bic     r2, r2, #I_BIT                  @ previously
-               msr     cpsr, r2
-               ldr     r2, .LCprocfns
-               mov     lr, pc
-               ldr     pc, [r2, #8]                    @ call processor specific code
-               mov     r3, sp
-               bl      SYMBOL_NAME(do_DataAbort)
-               b       ret_from_sys_call
 
-__dabt_svc:    sub     sp, sp, #S_FRAME_SIZE
+               adr     r1, .LC2
+               ldmia   r1, {r1, r4}
+               ldr     r1, [r1]
+               get_current_task r2
+               teq     r1, r2
+               blne    SYMBOL_NAME(math_state_restore)
+               adrsvc  al, r9, SYMBOL_NAME(fpreturn)
+               adrsvc  al, lr, SYMBOL_NAME(fpundefinstr)
+               ldr     pc, [r4]                        @ Call FP module USR entry point
+
+               .globl  SYMBOL_NAME(fpundefinstr)
+SYMBOL_NAME(fpundefinstr):                             @ Called by FP module on undefined instr
+               mov     r0, lr
+               mov     r1, sp
+               mrs     r4, cpsr                        @ Enable interrupts
+               bic     r4, r4, #I_BIT
+               msr     cpsr, r4
+               bl      SYMBOL_NAME(do_undefinstr)
+               b       ret_from_exception              @ Normal FP exit
+
+__und_svc:     sub     sp, sp, #S_FRAME_SIZE
                stmia   sp, {r0 - r12}                  @ save r0 - r12
-               ldr     r2, .LCabt
-               add     r0, sp, #S_FRAME_SIZE
-               add     r5, sp, #S_SP
-               mov     r1, lr
-               ldmia   r2, {r2 - r4}                   @ get pc, cpsr
-               stmia   r5, {r0 - r4}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-               tst     r3, #I_BIT
-               mrseq   r0, cpsr                        @ Enable interrupts if they were
-               biceq   r0, r0, #I_BIT                  @ previously
-               msreq   cpsr, r0
-               mov     r0, r2
-               ldr     r2, .LCprocfns
-               mov     lr, pc
-               ldr     pc, [r2, #8]                    @ call processor specific code
-               mov     r3, sp
-               bl      SYMBOL_NAME(do_DataAbort)
-               ldr     r0, [sp, #S_PSR]
-               msr     spsr, r0
-               ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
+               mov     r6, lr
+               ldr     r7, .LCund
+               ldmia   r7, {r7 - r9}
+               add     r5, sp, #S_FRAME_SIZE
+               add     r4, sp, #S_SP
+               stmia   r4, {r5 - r9}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
 
-__dabt_invalid:        sub     sp, sp, #S_FRAME_SIZE
-               stmia   sp, {r0 - lr}                   @ Save SVC r0 - lr [lr *should* be intact]
+               adr     r1, .LC2
+               ldmia   r1, {r1, r4}
+               ldr     r1, [r1]
+               mov     r2, sp, lsr #13
+               mov     r2, r2, lsl #13
+               teq     r1, r2
+               blne    SYMBOL_NAME(math_state_restore)
+               adrsvc  al, r9, SYMBOL_NAME(fpreturnsvc)
+               adrsvc  al, lr, SYMBOL_NAME(fpundefinstrsvc)
+               ldr     pc, [r4]                        @ Call FP module SVC entry point
+
+               .globl  SYMBOL_NAME(fpundefinstrsvc)
+SYMBOL_NAME(fpundefinstrsvc):
+               mov     r0, r5                          @ unsigned long pc
+               mov     r1, sp                          @ struct pt_regs *regs
+               bl      SYMBOL_NAME(do_undefinstr)
+
+               .globl  SYMBOL_NAME(fpreturnsvc)
+SYMBOL_NAME(fpreturnsvc):
+               ldr     lr, [sp, #S_PSR]                @ Get SVC cpsr
+               msr     spsr, lr
+               ldmia   sp, {r0 - pc}^                  @ Restore SVC registers
+
+.LC2:          .word   SYMBOL_NAME(last_task_used_math)
+               .word   SYMBOL_NAME(fp_enter)
+
+__und_invalid: sub     sp, sp, #S_FRAME_SIZE
+               stmia   sp, {r0 - lr}
                mov     r7, r0
-               ldr     r4, .LCabt
-               ldmia   r4, {r5, r6}                    @ Get SVC pc, cpsr
+               ldr     r4, .LCund
+               ldmia   r4, {r5, r6}                    @ Get UND/IRQ/FIQ/ABT pc, cpsr
                add     r4, sp, #S_PC
-               stmia   r4, {r5, r6, r7}                @ Save SVC pc, cpsr, old_r0
-               mov     r0, sp
-               mov     r1, #BAD_DATA
-               and     r2, r6, #31
-               b       SYMBOL_NAME(bad_mode)
-
+               stmia   r4, {r5, r6, r7}                @ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0
+               mov     r0, sp                          @ struct pt_regs *regs
+               mov     r1, #BAD_UNDEFINSTR             @ int reason
+               and     r2, r6, #31                     @ int mode
+               b       SYMBOL_NAME(bad_mode)           @ Does not ever return...
 
 #include "entry-common.S"
 
index 5725e17812a02169cc6cb59d9593980a866e78ee..98c41266f3a1fe6774b5d90519fd24c44fd39471 100644 (file)
@@ -1,56 +1,54 @@
-/*
- *=============================================================================
- *             Low-level interface code
- *-----------------------------------------------------------------------------
- *             Trap initialisation
- *-----------------------------------------------------------------------------
- *
- * Note - FIQ code has changed.  The default is a couple of words in 0x1c, 0x20
- * that call _unexp_fiq.  Nowever, we now copy the FIQ routine to 0x1c (removes
- * some excess cycles).
- *
- * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000
- * (the kernel).
- * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for
- * the actuall address to jump to.
- */
-/*
- * these go into 0x00
- */
-.Lbranches:    swi     SYS_ERROR0
-               ldr     pc, .Lbranches + 0xe4
-               ldr     pc, .Lbranches + 0xe8
-               ldr     pc, .Lbranches + 0xec
-               ldr     pc, .Lbranches + 0xf0
-               ldr     pc, .Lbranches + 0xf4
-               ldr     pc, .Lbranches + 0xf8
-               ldr     pc, .Lbranches + 0xfc
-/*
- * this is put into 0xe4 and above
- */
-.Ljump_addresses:
-               .word   vector_undefinstr       @ 0xe4
-               .word   vector_swi              @ 0xe8
-               .word   vector_prefetch         @ 0xec
-               .word   vector_data             @ 0xf0
-               .word   vector_addrexcptn       @ 0xf4
-               .word   vector_IRQ              @ 0xf8
-               .word   _unexp_fiq              @ 0xfc
-/*
- * initialise the trap system
+/*============================================================================
+ * All exits to user mode from the kernel go through this code.
  */
-ENTRY(trap_init)
-               stmfd   sp!, {r4 - r7, lr}
-               initialise_traps_extra
-               mov     r0, #0xe4
-               adr     r1, .Ljump_addresses
-               ldmia   r1, {r1 - r6}
-               stmia   r0, {r1 - r6}
-               mov     r0, #0
-               adr     r1, .Lbranches
-               ldmia   r1, {r1 - r7}
-               stmia   r0, {r1 - r7}
-               LOADREGS(fd, sp!, {r4 - r7, pc})
+
+               .globl  ret_from_sys_call
+
+               .globl  SYMBOL_NAME(fpreturn)
+SYMBOL_NAME(fpreturn):
+ret_from_exception:
+               adr     r0, 1f
+               ldmia   r0, {r0, r1}
+               ldr     r0, [r0]
+               ldr     r1, [r1]
+               tst     r0, r1
+               blne    SYMBOL_NAME(do_bottom_half)
+ret_from_intr: ldr     r0, [sp, #S_PSR]
+               tst     r0, #3
+               beq     ret_with_reschedule
+               b       ret_from_all
+
+ret_signal:    mov     r1, sp
+               adrsvc  al, lr, ret_from_all
+               b       SYMBOL_NAME(do_signal)
+
+2:             bl      SYMBOL_NAME(schedule)
+
+ret_from_sys_call:
+               adr     r0, 1f
+               ldmia   r0, {r0, r1}
+               ldr     r0, [r0]
+               ldr     r1, [r1]
+               tst     r0, r1
+               adrsvc  ne, lr, ret_from_intr
+               bne     SYMBOL_NAME(do_bottom_half)
+
+ret_with_reschedule:
+               ldr     r0, 1f + 8
+               ldr     r0, [r0]
+               teq     r0, #0
+               bne     2b
+
+               get_current_task r1
+               ldr     r1, [r1, #TSK_SIGPENDING]
+               teq     r1, #0
+               bne     ret_signal
+
+ret_from_all:  restore_user_regs
+
+1:             .word   SYMBOL_NAME(bh_mask)
+               .word   SYMBOL_NAME(bh_active)
+               .word   SYMBOL_NAME(need_resched)
 
 /*=============================================================================
  * SWI handler
@@ -77,7 +75,7 @@ vector_swi:   save_user_regs
                bcs     2f
 
                get_current_task r5
-               ldr     ip, [r5, #FLAGS]        @ check for syscall tracing
+               ldr     ip, [r5, #TSK_FLAGS]    @ check for syscall tracing
                tst     ip, #PF_TRACESYS
                bne     1f
 
@@ -91,7 +89,7 @@ vector_swi:   save_user_regs
 
 1:             ldr     r7, [sp, #S_IP]         @ save old IP
                mov     r0, #0
-               str     r7, [sp, #S_IP]         @ trace entry [IP = 0]
+               str     r0, [sp, #S_IP]         @ trace entry [IP = 0]
                bl      SYMBOL_NAME(syscall_trace)
                str     r7, [sp, #S_IP]
                ldmia   sp, {r0 - r3}           @ have to reload r0 - r3
@@ -193,57 +191,59 @@ sys_rt_sigreturn_wrapper:
                add     r0, sp, #4
                b       SYMBOL_NAME(sys_rt_sigreturn)
 
-/*============================================================================
- * All exits to user mode from the kernel go through this code.
+/*
+ *=============================================================================
+ *             Low-level interface code
+ *-----------------------------------------------------------------------------
+ *             Trap initialisation
+ *-----------------------------------------------------------------------------
+ *
+ * Note - FIQ code has changed.  The default is a couple of words in 0x1c, 0x20
+ * that call _unexp_fiq.  Nowever, we now copy the FIQ routine to 0x1c (removes
+ * some excess cycles).
+ *
+ * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000
+ * (the kernel).
+ * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for
+ * the actuall address to jump to.
  */
-
-               .globl  ret_from_sys_call
-
-               .globl  SYMBOL_NAME(fpreturn)
-SYMBOL_NAME(fpreturn):
-ret_from_exception:
-               adr     r0, 1f
-               ldmia   r0, {r0, r1}
-               ldr     r0, [r0]
-               ldr     r1, [r1]
-               tst     r0, r1
-               blne    SYMBOL_NAME(do_bottom_half)
-ret_from_intr: ldr     r0, [sp, #S_PSR]
-               tst     r0, #3
-               beq     ret_with_reschedule
-               b       ret_from_all
-
-ret_signal:    mov     r1, sp
-               adrsvc  al, lr, ret_from_all
-               b       SYMBOL_NAME(do_signal)
-
-2:             bl      SYMBOL_NAME(schedule)
-
-ret_from_sys_call:
-               adr     r0, 1f
-               ldmia   r0, {r0, r1}
-               ldr     r0, [r0]
-               ldr     r1, [r1]
-               tst     r0, r1
-               adrsvc  ne, lr, ret_from_intr
-               bne     SYMBOL_NAME(do_bottom_half)
-
-ret_with_reschedule:
-               ldr     r0, 1f + 8
-               ldr     r0, [r0]
-               teq     r0, #0
-               bne     2b
-
-               get_current_task r1
-               ldr     r1, [r1, #SIGPENDING]
-               teq     r1, #0
-               bne     ret_signal
-
-ret_from_all:  restore_user_regs
-
-1:             .word   SYMBOL_NAME(bh_mask)
-               .word   SYMBOL_NAME(bh_active)
-               .word   SYMBOL_NAME(need_resched)
+/*
+ * these go into 0x00
+ */
+.Lbranches:    swi     SYS_ERROR0
+               ldr     pc, .Lbranches + 0xe4
+               ldr     pc, .Lbranches + 0xe8
+               ldr     pc, .Lbranches + 0xec
+               ldr     pc, .Lbranches + 0xf0
+               ldr     pc, .Lbranches + 0xf4
+               ldr     pc, .Lbranches + 0xf8
+               ldr     pc, .Lbranches + 0xfc
+/*
+ * this is put into 0xe4 and above
+ */
+.Ljump_addresses:
+               .word   vector_undefinstr       @ 0xe4
+               .word   vector_swi              @ 0xe8
+               .word   vector_prefetch         @ 0xec
+               .word   vector_data             @ 0xf0
+               .word   vector_addrexcptn       @ 0xf4
+               .word   vector_IRQ              @ 0xf8
+               .word   _unexp_fiq              @ 0xfc
+/*
+ * initialise the trap system
+ */
+ENTRY(trap_init)
+               stmfd   sp!, {r4 - r7, lr}
+               initialise_traps_extra
+               mov     r0, #0xe4
+               adr     r1, .Ljump_addresses
+               ldmia   r1, {r1 - r6}
+               stmia   r0, {r1 - r6}
+               mov     r0, #0
+               adr     r1, .Lbranches
+               ldmia   r1, {r1 - r7}
+               stmia   r0, {r1 - r7}
+               LOADREGS(fd, sp!, {r4 - r7, pc})
 
 /*============================================================================
  * FP support
index 7bd69ed5f56929dd11d533fadb4daa01ad0d7b6a..80d88e890295fadba433b50c75223e3ec708430b 100644 (file)
@@ -42,7 +42,7 @@ Lcontinue:    str     r5, [r6]
                b       SYMBOL_NAME(start_kernel)
 
 LC1:           .word   SYMBOL_NAME(_stext)
-LC0:           .word   SYMBOL_NAME(_edata)
+LC0:           .word   SYMBOL_NAME(__bss_start)
                .word   SYMBOL_NAME(arm_id)
                .word   SYMBOL_NAME(_end)
                .word   SYMBOL_NAME(init_task_union)+8192
index 0af401e43bd6d7160e7a495e4e683eadcd76c277..e53b7144f530d398bf66b496261e3fa460036801 100644 (file)
                .globl  __stext
 /*
  * Entry point and restart point.  Entry *must* be called with r0 == 0,
- * MMU off.
+ * MMU off.  Note! These should be unique!!! Please read Documentation/ARM-README
+ * for more information.
  *
- *  r1 = 0 -> ebsa  (Ram @ 0x00000000)
- *  r1 = 1 -> RPC   (Ram @ 0x10000000)
- *  r1 = 2 -> ebsit (???)
+ *  r1 = 0 -> ebsa110  (Ram @ 0x00000000)
+ *  r1 = 1 -> RPC      (Ram @ 0x10000000)
+ *  r1 = 2 -> ebsit    (???)
  *  r1 = 3 -> nexuspci
+ *  r1 = 4 -> ebsa285  (Ram @ 0x00000000)
  */
 ENTRY(stext)
 ENTRY(_stext)
 __entry:
                teq     r0, #0                                  @ check for illegal entry...
                bne     .Lerror                                 @ loop indefinitely
-               cmp     r1, #4                                  @ Unknown machine architecture
+               cmp     r1, #5                                  @ Unknown machine architecture
                bge     .Lerror
 @
 @ First thing to do is to get the page tables set up so that we can call the kernel
@@ -57,18 +59,23 @@ __entry:
 
                adr     r4, .LCMachTypes
                add     r4, r4, r1, lsl #4
-               ldmia   r4, {r4, r5, r6}                        @ r4 = page dir in physical ram
-
+               ldmia   r4, {r4, r5, r6}
+/*
+ * r4 = page dir in physical ram
+ * r5 = physical address of start of RAM
+ * r6 = I/O address
+ */
                mov     r0, r4
                mov     r1, #0
                add     r2, r0, #0x4000
 1:             str     r1, [r0], #4                            @ Clear page table
                teq     r0, r2
                bne     1b
-@
-@ Add enough entries to allow the kernel to be called.
-@ It will sort out the real mapping in paging_init
-@
+/*
+ * Add enough entries to allow the kernel to be called.
+ * It will sort out the real mapping in paging_init.
+ * We map in 2MB of memory into 0xC0000000 - 0xC0200000
+ */
                add     r0, r4, #0x3000
                mov     r1, #0x0000000c                         @ SECT_CACHEABLE | SECT_BUFFERABLE
                orr     r1, r1, r8
@@ -121,7 +128,7 @@ __entry:
 
 .Lbranch:      .long   .Lalready_done_mmap                     @ Real address of routine
 
-               @ EBSA (pg dir phys, phys ram start, phys i/o)
+               @ EBSA110 (pg dir phys, phys ram start, phys i/o)
 .LCMachTypes:  .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000        @ Address of page tables (physical)
                .long   0                                       @ Address of RAM
                .long   0xe0000000                              @ I/O address
@@ -145,6 +152,14 @@ __entry:
                .long   0x10000000
                .long   0
 
+               @ EBSA285
+               .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000        @ Address of page tables (physical)
+               .long   0                                       @ Address of RAM
+               .long   0x24000000                              @ I/O base address (0x42000000 -> 0xFE000000)
+               .long   0
+
+
+
 .LCProcTypes:  @ ARM6 / 610
                .long   0x41560600
                .long   0xffffff00
@@ -168,7 +183,7 @@ __entry:
 
                .long   0
 
-.LC0:          .long   SYMBOL_NAME(_edata)
+.LC0:          .long   SYMBOL_NAME(__bss_start)
                .long   SYMBOL_NAME(arm_id)
                .long   SYMBOL_NAME(_end)
                .long   SYMBOL_NAME(init_task_union)+8192
@@ -231,19 +246,84 @@ __entry:
                b       SYMBOL_NAME(start_kernel)
 
 #if 1
+
+#if defined(CONFIG_ARCH_RPC)
+               .macro  addruart,rx
+               mov     \rx, #0xe0000000
+               orr     \rx, \rx, #0x00010000
+               orr     \rx, \rx, #0x00000fe0
+               .endm
+
+               .macro  senduart,rd,rx
+               strb    \rd, [\rx]
+               .endm
+
+               .macro  busyuart,rd,rx
+1002:          ldrb    \rd, [\rx, #0x14]
+               and     \rd, \rd, #0x60
+               bne     1002b
+               .endm
+
+               .macro  waituart,rd,rx
+1001:          ldrb    \rd, [\rx, #0x18]
+               tst     \rd, #0x10
+               beq     1001b
+               .endm
+
+#elif defined(CONFIG_ARCH_EBSA110)
+               .macro  addruart,rx
+               mov     \rx, #0xf0000000
+               orr     \rx, \rx, #0x00000be0
+               .endm
+
+               .macro  senduart,rd,rx
+               strb    \rd, [\rx]
+               .endm
+
+               .macro  busyuart,rd,rx
+1002:          ldrb    \rd, [\rx, #0x14]
+               and     \rd, \rd, #0x60
+               bne     1002b
+               .endm
+
+               .macro  waituart,rd,rx
+1001:          ldrb    \rd, [\rx, #0x18]
+               tst     \rd, #0x10
+               beq     1001b
+               .endm
+
+#elif defined(CONFIG_ARCH_EBSA285)
+               .macro  addruart,rx
+               mov     \rx, #0xfe000000
+               .endm
+
+               .macro  senduart,rd,rx
+               str     \rd, [\rx, #0x160]      @ UARTDR
+               .endm
+
+               .macro  busyuart,rd,rx
+1001:          ldr     \rd, [\rx, #0x178]      @ UARTFLG
+               tst     \rd, #1 << 3
+               bne     1001b
+               .endm
+
+               .macro  waituart,rd,rx
+               .endm
+#endif
+
 /*
  * Useful debugging routines
  */
-               .globl  _printhex8
-_printhex8:    mov     r1, #8
+ENTRY(printhex8)
+               mov     r1, #8
                b       printhex
 
-               .globl  _printhex4
-_printhex4:    mov     r1, #4
+ENTRY(printhex4)
+               mov     r1, #4
                b       printhex
 
-               .globl  _printhex2
-_printhex2:    mov     r1, #2
+ENTRY(printhex2)
+               mov     r1, #2
 printhex:      ldr     r2, =hexbuf
                add     r3, r2, r1
                mov     r1, #0
@@ -258,46 +338,23 @@ printhex: ldr     r2, =hexbuf
                bne     1b
                mov     r0, r2
 
-               .globl  _printascii
-_printascii:
-#ifdef CONFIG_ARCH_RPC
-               mov     r3, #0xe0000000
-               orr     r3, r3, #0x00010000
-               orr     r3, r3, #0x00000fe0
-#else
-               mov     r3, #0xf0000000
-               orr     r3, r3, #0x0be0
-#endif
-               b       3f
-1:             ldrb    r2, [r3, #0x18]
-               tst     r2, #0x10
-               beq     1b
-               strb    r1, [r3]
-2:             ldrb    r2, [r3, #0x14]
-               and     r2, r2, #0x60
-               teq     r2, #0x60
-               bne     2b
+ENTRY(printascii)
+               addruart r3
+               b       2f
+1:             waituart r2, r3
+               senduart r1, r3
+               busyuart r2, r3
                teq     r1, #'\n'
                moveq   r1, #'\r'
                beq     1b
-3:             teq     r0, #0
+2:             teq     r0, #0
                ldrneb  r1, [r0], #1
                teqne   r1, #0
                bne     1b
                mov     pc, lr
 
-               .ltorg
-
-               .globl  _printch
-_printch:
-#ifdef CONFIG_ARCH_RPC
-               mov     r3, #0xe0000000
-               orr     r3, r3, #0x00010000
-               orr     r3, r3, #0x00000fe0
-#else
-               mov     r3, #0xf0000000
-               orr     r3, r3, #0x0be0
-#endif
+ENTRY(printch)
+               addruart r3
                mov     r1, r0
                mov     r0, #0
                b       1b
index 2e665312d0e3cea67492d31dc359664e8714518f..1dde0e0ba3481711692c9e89808afa6614e4aaff 100644 (file)
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/hardware.h>
-#include <asm/irq-no.h>
 #include <asm/arch/irq.h>
 
+unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
-#ifdef __SMP__
-atomic_t __arm_bh_counter;
-#else
-int __arm_bh_counter;
-#endif
-
 spinlock_t irq_controller_lock;
 
 #ifndef SMP
@@ -80,13 +74,21 @@ void enable_irq(unsigned int irq_nr)
 
 struct irqaction *irq_action[NR_IRQS];
 
-/*
- * Bitmask indicating valid interrupt numbers
+#ifdef CONFIG_ARCH_ACORN
+/* Bitmask indicating valid interrupt numbers
+ * (to be moved to include/asm-arm/arch-*)
  */
 unsigned long validirqs[NR_IRQS / 32] = {
-       0x003fffff,     0x000001ff,     0x000000ff,     0x00000000
+       0x003ffe7f,     0x000001ff,     0x000000ff,     0x00000000
 };
 
+#define valid_irq(x) ((x) < NR_IRQS && validirqs[(x) >> 5] & (1 << ((x) & 31)))
+#else
+
+#define valid_irq(x) ((x) < NR_IRQS)
+
+#endif
+
 int get_irq_list(char *buf)
 {
        int i;
@@ -98,7 +100,7 @@ int get_irq_list(char *buf)
                if (!action)
                        continue;
                p += sprintf(p, "%3d: %10u   %s",
-                            i, kstat.irqs[0][i], action->name);
+                            i, kstat_irqs(i), action->name);
                for (action = action->next; action; action = action->next) {
                        p += sprintf(p, ", %s", action->name);
                }
@@ -126,7 +128,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 
        cpu = smp_processor_id();
        irq_enter(cpu, irq);
-       kstat.irqs[0][irq]++;
+       kstat.irqs[cpu][irq]++;
 
        /* Return with this interrupt masked if no action */
        status = 0;
@@ -143,13 +145,26 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
                if (status & SA_SAMPLE_RANDOM)
                        add_interrupt_randomness(irq);
                __cli();
+
+               switch (irq) {
 #if defined(HAS_IOMD) || defined(HAS_IOC)
-               if (irq != IRQ_KEYBOARDTX && irq != IRQ_EXPANSIONCARD)
+               case IRQ_KEYBOARDTX:
+               case IRQ_EXPANSIONCARD:
+                       break;
+#endif
+#ifdef HAS_IOMD
+               case IRQ_DMA0:
+               case IRQ_DMA1:
+               case IRQ_DMA2:
+               case IRQ_DMA3:
+                       break;
 #endif
-               {
+
+               default:
                        spin_lock(&irq_controller_lock);
                        unmask_irq(irq);
                        spin_unlock(&irq_controller_lock);
+                       break;
                }
        }
 
@@ -235,7 +250,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
        unsigned long retval;
        struct irqaction *action;
         
-       if (irq >= NR_IRQS || !(validirqs[irq >> 5] & (1 << (irq & 31))))
+       if (!valid_irq(irq))
                return -EINVAL;
        if (!handler)
                return -EINVAL;
@@ -263,7 +278,7 @@ void free_irq(unsigned int irq, void *dev_id)
        struct irqaction * action, **p;
        unsigned long flags;
 
-       if (irq >= NR_IRQS || !(validirqs[irq >> 5] & (1 << (irq & 31)))) {
+       if (!valid_irq(irq)) {
                printk(KERN_ERR "Trying to free IRQ%d\n",irq);
 #ifdef CONFIG_DEBUG_ERRORS
                __backtrace();
@@ -294,7 +309,7 @@ unsigned long probe_irq_on (void)
 
        /* first snaffle up any unassigned irqs */
        for (i = 15; i > 0; i--) {
-               if (!irq_action[i]) {
+               if (!irq_action[i] && valid_irq(i)) {
                        enable_irq(i);
                        irqs |= 1 << i;
                }
@@ -323,5 +338,7 @@ int probe_irq_off (unsigned long irqs)
 
 __initfunc(void init_IRQ(void))
 {
+       extern void init_dma(void);
        irq_init_irq();
+       init_dma();
 }
diff --git a/arch/arm/kernel/leds-ebsa285.c b/arch/arm/kernel/leds-ebsa285.c
new file mode 100644 (file)
index 0000000..f8add1a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/kernel/leds-285.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * EBSA-285 LED control routines.  We use the leds as follows:
+ *
+ *  - Green - toggles state every 50 timer interrupts
+ *  - Amber - On if system is not idle
+ *  - Red   - currently unused
+ */
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+static char led_state = XBUS_LED_RED | XBUS_LED_GREEN;
+
+void leds_event(led_event_t ledevt)
+{
+       unsigned long flags;
+
+       save_flags_cli(flags);
+
+       switch(ledevt) {
+       case led_idle_start:
+               led_state |= XBUS_LED_AMBER;
+               break;
+
+       case led_idle_end:
+               led_state &= ~XBUS_LED_AMBER;
+               break;
+
+       case led_timer:
+               led_state ^= XBUS_LED_GREEN;
+               break;
+
+       default:
+               break;
+       }
+
+       restore_flags(flags);
+
+       *XBUS_LEDS = led_state;
+}
index 7f45e7c3c66ff7fa028745d165060ef35eb696e7..9372539ef69c183a2da99eebd03d886de72d768e 100644 (file)
@@ -69,8 +69,10 @@ asmlinkage int sys_idle(void)
        current->priority = -100;
        for (;;)
        {
+#if 0 //def ARCH_IDLE_OK
                if (!hlt_counter && !need_resched)
                        proc_idle ();
+#endif
                run_task_queue(&tq_scheduler);
                schedule();
        }
@@ -142,7 +144,7 @@ void show_regs(struct pt_regs * regs)
 "      mrc p15, 0, %1, c2, c0\n"
 "      mrc p15, 0, %2, c3, c0\n"
  : "=r" (ctrl), "=r" (transbase), "=r" (dac));
-  printk("Control: %04X  Table: %08X  DAC: %08X",
+  printk("Control: %04X  Table: %08X  DAC: %08X  ",
        ctrl, transbase, dac);
   }
 #endif
index 5fa67df6cecd6bb58bef541f75f5149bae807d19..f95e8de7e0e010b741d4a04db162050a7d2a4383 100644 (file)
  */
 #define BREAKINST      0xef9f0001
 
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
-       int i;
-
-       for (i = 1; i < NR_TASKS; i++) {
-               if (task[i] != NULL && (task[i]->pid == pid))
-                       return task[i];
-       }
-       return NULL;
-}
-
 /*
  * this routine will get a word off of the processes privileged stack.
  * the offset is how far from the base addr as stored in the TSS.
@@ -581,7 +569,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
        if (pid == 1)           /* you may not mess with init */
                goto out;
        ret = -ESRCH;
-       if (!(child = get_task(pid)))
+       if (!(child = find_task_by_pid(pid)))
                goto out;
        ret = -EPERM;
        if (request == PTRACE_ATTACH) {
index 285284b7db72856840e66aa1d5f4bee6bf3c1350..8cbfe7dc31580e19baf4e96970c9b81ee4beed06 100644 (file)
 #include <linux/delay.h>
 #include <linux/major.h>
 #include <linux/utsname.h>
+#include <linux/init.h>
 
-#include <asm/segment.h>
-#include <asm/system.h>
 #include <asm/hardware.h>
 #include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/setup.h>
+#include <asm/system.h>
 
 #ifndef CONFIG_CMDLINE
 #define CONFIG_CMDLINE "root=nfs rw console=ttyS1,38400n8"
 #endif
+#define COMMAND_LINE_SIZE 256
+
 #define MEM_SIZE       (16*1024*1024)
 
-#define COMMAND_LINE_SIZE 256
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+       char saved_command_line[COMMAND_LINE_SIZE];
 
+struct processor processor;
+struct screen_info screen_info;
 unsigned char aux_device_present;
 unsigned long arm_id;
+
 extern int root_mountflags;
 extern int _etext, _edata, _end;
+extern const struct processor sa110_processor_functions;
 
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;          /* 1 = load ramdisk, 0 = don't load */
 extern int rd_prompt;          /* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_image_start;     /* starting block # of image */
 
-static inline void setup_ramdisk (void)
+static inline void setup_ramdisk(int start, int prompt, int load)
 {
-    rd_image_start     = 0;
-    rd_prompt          = 1;
-    rd_doload          = 1;
+       rd_image_start  = start;
+       rd_prompt       = prompt;
+       rd_doload       = load;
 }
 #else
-#define setup_ramdisk()        
+#define setup_ramdisk(start,prompt,load)
 #endif
 
+#ifdef PARAMS_BASE
+static struct param_struct *params = (struct param_struct *)PARAMS_BASE;
+
+static inline char *setup_params(unsigned long *mem_end_p)
+{
+       ROOT_DEV          = to_kdev_t(params->u1.s.rootdev);
+       ORIG_X            = params->u1.s.video_x;
+       ORIG_Y            = params->u1.s.video_y;
+       ORIG_VIDEO_COLS   = params->u1.s.video_num_cols;
+       ORIG_VIDEO_LINES  = params->u1.s.video_num_rows;
+
+       setup_ramdisk(params->u1.s.rd_start,
+                     (params->u1.s.flags & FLAG_RDPROMPT) == 0,
+                     (params->u1.s.flags & FLAG_RDLOAD) == 0);
+
+       *mem_end_p = 0xc0000000 + MEM_SIZE;
+
+       return params->commandline;
+}
+#else
 static char default_command_line[] = CONFIG_CMDLINE;
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
 
-struct processor processor;
-extern const struct processor sa110_processor_functions;
+static inline char *setup_params(unsigned long *mem_end_p)
+{
+       ROOT_DEV          = 0x00ff;
+
+       setup_ramdisk(0, 1, 1);
+
+       *mem_end_p = 0xc0000000 + MEM_SIZE;
+
+       return default_command_line;
+}
+#endif
 
-void setup_arch(char **cmdline_p,
-       unsigned long * memory_start_p, unsigned long * memory_end_p)
+__initfunc(void setup_arch(char **cmdline_p,
+       unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
        unsigned long memory_start, memory_end;
        char c = ' ', *to = command_line, *from;
        int len = 0;
 
        memory_start = (unsigned long)&_end;
-       memory_end = 0xc0000000 + MEM_SIZE;
-       from = default_command_line;
 
        processor = sa110_processor_functions;
-       processor._proc_init ();
+       processor._proc_init();
 
-       ROOT_DEV                = 0x00ff;
-       setup_ramdisk();
+       from = setup_params(&memory_end);
 
        init_task.mm->start_code = TASK_SIZE;
        init_task.mm->end_code   = TASK_SIZE + (unsigned long) &_etext;
index ac304fb3e2da9eae85dbf8bc7aa3822bf1290024..a3b86fef766dbc657114c7e9a26d4e755692d2e4 100644 (file)
 #include <linux/major.h>
 #include <linux/utsname.h>
 #include <linux/blk.h>
+#include <linux/init.h>
 
-#include <asm/segment.h>
-#include <asm/system.h>
 #include <asm/hardware.h>
+#include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/arch/mmu.h>
 #include <asm/procinfo.h>
-#include <asm/io.h>
+#include <asm/segment.h>
 #include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/arch/mmu.h>
 
 struct drive_info_struct { char dummy[32]; } drive_info;
 struct screen_info screen_info;
@@ -153,13 +154,17 @@ static void setup_initrd (struct param_struct *params, unsigned long memory_end)
 #define setup_initrd(p,m)
 #endif
 
+#ifdef IOEB_BASE
 static inline void check_ioeb_present(void)
 {
        if (((*IOEB_BASE) & 15) == 5)
                armidlist[armidindex].features |= F_IOEB;
 }
+#else
+#define check_ioeb_present()
+#endif
 
-static void get_processor_type (void)
+static inline void get_processor_type (void)
 {
        for (armidindex = 0; ; armidindex ++)
                if (!((armidlist[armidindex].id ^ arm_id) &
@@ -179,11 +184,14 @@ static void get_processor_type (void)
 
 #define COMMAND_LINE_SIZE 256
 
+/* Can this be initdata?  --pb
+ *  command_line can be, saved_command_line can't though
+ */
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
 
-void setup_arch(char **cmdline_p,
-       unsigned long * memory_start_p, unsigned long * memory_end_p)
+__initfunc(void setup_arch(char **cmdline_p,
+       unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
        static unsigned char smptrap;
        unsigned long memory_start, memory_end;
index b1c679ec5e38ec59ea781e48baaa36cf0a49282d..1f598e14dd9ed063c6ebf66c2559109c956313ef 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -30,7 +31,6 @@
 #include <asm/delay.h>
 
 #include <linux/timex.h>
-#include <asm/irq-no.h>
 #include <asm/hardware.h>
 
 extern int setup_arm_irq(int, struct irqaction *);
@@ -143,12 +143,12 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        update_rtc ();
 }
 
-static struct irqaction irqtimer0 = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+static struct irqaction irqtimer = { timer_interrupt, 0, 0, "timer", NULL, NULL};
 
-void time_init(void)
+__initfunc(void time_init(void))
 {
        xtime.tv_sec = setup_timer();
        xtime.tv_usec = 0;
 
-       setup_arm_irq(IRQ_TIMER0, &irqtimer0);
+       setup_arm_irq(IRQ_TIMER, &irqtimer);
 }
index 7ff7436c55e007a93e7ccd5f22de2078bff45c80..222fd6b17d6fa0a39f9df7b3d12fe0bebf3e50e1 100644 (file)
@@ -59,17 +59,27 @@ static int verify_stack_pointer (unsigned long stackptr, int size)
                return 0;
 }
 
-static void dump_stack (unsigned long *start, unsigned long *end, int offset, int max)
+/*
+ * Dump out the contents of some memory nicely...
+ */
+void dump_mem(unsigned long bottom, unsigned long top)
 {
-       unsigned long *p;
+       unsigned long p = bottom & ~31;
        int i;
 
-       for (p = start + offset, i = 0; i < max && p < end; i++, p++) {
-               if (i && (i & 7) == 0)
-                       printk ("\n       ");
-               printk ("%08lx ", *p);
+       for (p = bottom & ~31; p < top;) {
+               printk("%08lx: ", p);
+
+               for (i = 0; i < 8; i++, p += 4) {
+                       if (p < bottom || p >= top)
+                               printk("         ");
+                       else
+                               printk("%08lx ", *(unsigned long *)p);
+                       if (i == 3)
+                               printk(" ");
+               }
+               printk ("\n");
        }
-       printk ("\n");
 }
 
 /*
@@ -139,28 +149,26 @@ void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret)
                break;
        }
 
-       console_verbose ();
-       printk ("Internal error: %s: %x\n", str, err);
-       printk ("CPU: %d", smp_processor_id());
-       show_regs (regs);
-       printk ("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
+       console_verbose();
+       printk("Internal error: %s: %x\n", str, err);
+       printk("CPU: %d", smp_processor_id());
+       show_regs(regs);
+       printk("Process %s (pid: %d, stackpage=%08lx)\n",
                current->comm, current->pid, 4096+(unsigned long)current);
 
        cstack = (unsigned long)(regs + 1);
        sstack = 4096+(unsigned long)current;
 
-       if (*(unsigned long *)sstack != STACK_MAGIC)
-               printk ("*** corrupted stack page\n       ");
-
-       if (verify_stack_pointer (cstack, 4))
-               printk ("%08lx invalid kernel stack pointer\n", cstack);
+       printk("Stack: ");
+       if (verify_stack_pointer(cstack, 4))
+               printk("invalid kernel stack pointer %08lx", cstack);
        else if(cstack > sstack + 4096)
-               printk("(sp overflow)\n");
+               printk("(sp overflow)");
        else if(cstack < sstack)
-               printk("(sp underflow)\n");
-       else
-               dump_stack ((unsigned long *)sstack, (unsigned long *)sstack + 1024,
-                       cstack - sstack, kstack_depth_to_print);
+               printk("(sp underflow)");
+       printk("\n");
+
+       dump_mem(cstack, sstack + 4096);
 
        frameptr = regs->ARM_fp;
        if (frameptr) {
@@ -172,7 +180,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret)
                }
        }
 
-       dump_instr (instruction_pointer(regs));
+       dump_instr(instruction_pointer(regs));
        died = 0;
        if (ret != -1)
                do_exit (ret);
index 10fad6b4353ecf377fb7b72da739660b227ee8c8..8ec13266d7ee7659307f73f17936df239afb5d3e 100644 (file)
@@ -5,17 +5,13 @@
 #
 
 L_TARGET := lib.a
-L_OBJS   := backtrace.o bitops.o delay.o fp_support.o \
+L_OBJS   := backtrace.o bitops.o checksum.o delay.o fp_support.o \
            loaders.o memcpy.o memfastset.o system.o string.o uaccess.o
 
 ifeq ($(PROCESSOR),armo)
   L_OBJS += uaccess-armo.o
 endif
 
-ifdef CONFIG_INET
-  L_OBJS += checksum.o
-endif
-
 ifdef CONFIG_ARCH_ACORN
   L_OBJS += ll_char_wr.o io-acorn.o
   ifdef CONFIG_ARCH_A5K
@@ -26,30 +22,27 @@ ifdef CONFIG_ARCH_ACORN
   endif
 endif
 
-ifdef CONFIG_ARCH_EBSA110
+ifeq ($(MACHINE),ebsa110)
   L_OBJS += io-ebsa110.o
 endif
 
-include $(TOPDIR)/Rules.make
+ifeq ($(MACHINE),ebsa285)
+  L_OBJS += io-ebsa285.o
+endif
 
-constants.h: getconstants
-       ./getconstants > constants.h
+include $(TOPDIR)/Rules.make
 
-getconstants: getconstants.c getconstants.h
-       $(HOSTCC) -D__KERNEL__ -o getconstants getconstants.c
+constants.h: getconsdata.o extractconstants.pl
+       $(PERL) extractconstants.pl $(OBJDUMP) > $@
 
-getconstants.h: getconsdata.c
+getconsdata.o: getconsdata.c
        $(CC) $(CFLAGS) -c getconsdata.c
-       $(PERL) extractinfo.perl $(OBJDUMP) > $@
 
 %.o: %.S
-ifndef $(CONFIG_BINUTILS_NEW)
+ifneq ($(CONFIG_BINUTILS_NEW),y)
        $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.$<.s
        $(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.$<.s
        $(RM) ..tmp.$<.s
 else
        $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
 endif
-
-clean:
-       $(RM) getconstants constants.h getconstants.h
diff --git a/arch/arm/lib/extractconstants.pl b/arch/arm/lib/extractconstants.pl
new file mode 100644 (file)
index 0000000..ff095a2
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+
+$OBJDUMP=$ARGV[0];
+
+sub swapdata {
+       local ($num) = @_;
+
+       return substr($num, 6, 2).substr($num, 4, 2).substr ($num, 2, 2).substr ($num, 0, 2);
+}
+
+open (DATA, $OBJDUMP.' --full-contents --section=.data getconsdata.o | grep \'^ 00\' |') ||
+       die ('Cant objdump!');
+while (<DATA>) {
+       ($addr, $data0, $data1, $data2, $data3) = split (' ');
+       $dat[hex($addr)] = hex(&swapdata($data0));
+       $dat[hex($addr)+4] = hex(&swapdata($data1));
+       $dat[hex($addr)+8] = hex(&swapdata($data2));
+       $dat[hex($addr)+12] = hex(&swapdata($data3));
+}
+close (DATA);
+
+open (DATA, $OBJDUMP.' --syms getconsdata.o |') || die ('Cant objdump!');
+while (<DATA>) {
+       /elf32/ && ( $elf = 1 );
+       /a.out/ && ( $aout = 1 );
+       next if ($aout && ! / 07 /);
+       next if ($elf && ! (/^00...... g/ && /.data/));
+       next if (!$aout && !$elf);
+
+       if ($aout) {
+               ($addr, $flags, $sect, $a1, $a2, $a3, $name) = split (' ');
+               $nam[hex($addr)] = substr($name, 1);
+       }
+       if ($elf) {
+               chomp;
+               $addr = substr ($_, 0, 8);
+               $name = substr ($_, 32);
+               $nam[hex($addr)] = $name;
+       }
+}
+close (DATA);
+
+print "/*\n * *** This file is automatically generated from getconsdata.c.  Do not edit! ***\n */\n";
+for ($i = 0; $i < hex($addr)+4; $i += 4) {
+       print "#define $nam[$i] $dat[$i]\n";
+}
diff --git a/arch/arm/lib/extractinfo.perl b/arch/arm/lib/extractinfo.perl
deleted file mode 100644 (file)
index d1f2efa..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/perl
-
-$OBJDUMP=$ARGV[0];
-
-sub swapdata {
-       local ($num) = @_;
-
-       return substr($num, 6, 2).substr($num, 4, 2).substr ($num, 2, 2).substr ($num, 0, 2);
-}
-
-open (DATA, $OBJDUMP.' --full-contents --section=.data getconsdata.o | grep \'^ 00\' |') ||
-       die ('Cant objdump!');
-while (<DATA>) {
-       ($addr, $data0, $data1, $data2, $data3) = split (' ');
-       $dat[hex($addr)] = hex(&swapdata($data0));
-       $dat[hex($addr)+4] = hex(&swapdata($data1));
-       $dat[hex($addr)+8] = hex(&swapdata($data2));
-       $dat[hex($addr)+12] = hex(&swapdata($data3));
-}
-close (DATA);
-
-open (DATA, $OBJDUMP.' --syms getconsdata.o |') || die ('Cant objdump!');
-while (<DATA>) {
-       /elf32/ && ( $elf = 1 );
-       /a.out/ && ( $aout = 1 );
-       next if ($aout && ! / 07 /);
-       next if ($elf && ! (/^00...... g/ && /.data/));
-       next if (!$aout && !$elf);
-
-       ($addr, $flags, $sect, $a1, $a2, $a3, $name) = split (' ') if $aout;
-       $nam[hex($addr)] = substr($name, 1) if $aout;
-       if ($elf) {
-               chomp;
-               $addr = substr ($_, 0, 8);
-               $name = substr ($_, 32);
-               $nam[hex($addr)] = $name;
-       }
-}
-close (DATA);
-
-print "/*\n * *** THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT! ***\n */\n";
-for ($i = 0; $i < hex($addr)+12; $i ++) {
-       print "unsigned long $nam[$i] = $dat[$i];\n" if $dat[$i];
-       print "#define __HAS_$nam[$i]\n" if $dat[$i];
-}
index 901c1ad16f667ee8353122e90fcf877e9e861c96..bdf09d5a3251452a942d875d23cb91c53a69d9ed 100644 (file)
@@ -1,9 +1,8 @@
 /*
  * linux/arch/arm/lib/getconsdata.c
  *
- * Copyright (C) 1995, 1996 Russell King
+ * Copyright (C) 1995-1998 Russell King
  */
-
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n)
 
 #ifdef KERNEL_DOMAIN
-unsigned long kernel_domain = KERNEL_DOMAIN;
+unsigned long DOM_KERNELDOMAIN = KERNEL_DOMAIN;
 #endif
 #ifdef USER_DOMAIN
-unsigned long user_domain = USER_DOMAIN;
-#endif
-unsigned long addr_limit = OFF_TSK(addr_limit);
-unsigned long tss_memmap = OFF_TSK(tss.memmap);
-unsigned long mm = OFF_TSK(mm);
-unsigned long pgd = OFF_MM(pgd);
-unsigned long tss_save = OFF_TSK(tss.save);
-unsigned long tss_fpesave = OFF_TSK(tss.fpstate.soft.save);
+unsigned long DOM_USERDOMAIN = USER_DOMAIN;
+#endif
+
+unsigned long TSK_STATE = OFF_TSK(state);
+unsigned long TSK_FLAGS = OFF_TSK(flags);
+unsigned long TSK_SIGPENDING = OFF_TSK(sigpending);
+unsigned long TSK_ADDR_LIMIT = OFF_TSK(addr_limit);
+
+unsigned long MM = OFF_TSK(mm);
+unsigned long PGD = OFF_MM(pgd);
+
+unsigned long TSS_MEMMAP = OFF_TSK(tss.memmap);
+unsigned long TSS_SAVE = OFF_TSK(tss.save);
+unsigned long TSS_FPESAVE = OFF_TSK(tss.fpstate.soft.save);
 #if defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3)
-unsigned long tss_memcmap = OFF_TSK(tss.memcmap);
+unsigned long TSS_MEMCMAP = OFF_TSK(tss.memcmap);
+#endif
+
+#ifdef _PAGE_PRESENT
+unsigned long PAGE_PRESENT = _PAGE_PRESENT;
+#endif
+#ifdef _PAGE_RW
+unsigned long PAGE_RW = _PAGE_RW;
 #endif
+#ifdef _PAGE_USER
+unsigned long PAGE_USER = _PAGE_USER;
+#endif
+#ifdef _PAGE_ACCESSED
+unsigned long PAGE_ACCESSED = _PAGE_ACCESSED;
+#endif
+#ifdef _PAGE_DIRTY
+unsigned long PAGE_DIRTY = _PAGE_DIRTY;
+#endif
+#ifdef _PAGE_READONLY
+unsigned long PAGE_READONLY = _PAGE_READONLY;
+#endif
+#ifdef _PAGE_NOT_USER
+unsigned long PAGE_NOT_USER = _PAGE_NOT_USER;
+#endif
+#ifdef _PAGE_OLD
+unsigned long PAGE_OLD = _PAGE_OLD;
+#endif
+#ifdef _PAGE_CLEAN
+unsigned long PAGE_CLEAN = _PAGE_CLEAN;
+#endif
+
+unsigned long KSWI_BASE = 0x900000;
+unsigned long KSWI_SYS_BASE = 0x9f0000;
+unsigned long SYS_ERROR0 = 0x9f0000;
diff --git a/arch/arm/lib/getconstants.c b/arch/arm/lib/getconstants.c
deleted file mode 100644 (file)
index edb67a5..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * linux/arch/arm/lib/getconstants.c
- *
- * Copyright (C) 1995, 1996 Russell King
- */
-
-#include <linux/mm.h>
-#include <asm/pgtable.h>
-#include <stdio.h>
-#include <linux/unistd.h>
-
-void printdef(char *def, int no)
-{
-       printf("#define %s\t%d\n", def, no);
-}
-
-#include "getconstants.h"
-
-int main()
-{
-       printf("/*\n *  contants.h generated by getconstants\n * DO NOT EDIT!\n */\n");
-
-       printf("#define _current\t_%s\n", "current_set");
-
-#ifdef _PAGE_PRESENT
-       printdef("PAGE_PRESENT",        _PAGE_PRESENT);
-#endif
-#ifdef _PAGE_RW
-       printdef("PAGE_RW",             _PAGE_RW);
-#endif
-#ifdef _PAGE_USER
-       printdef("PAGE_USER",           _PAGE_USER);
-#endif
-#ifdef _PAGE_ACCESSED
-       printdef("PAGE_ACCESSED",       _PAGE_ACCESSED);
-#endif
-#ifdef _PAGE_DIRTY
-       printdef("PAGE_DIRTY",          _PAGE_DIRTY);
-#endif
-#ifdef _PAGE_READONLY
-       printdef("PAGE_READONLY",       _PAGE_READONLY);
-#endif
-#ifdef _PAGE_NOT_USER
-       printdef("PAGE_NOT_USER",       _PAGE_NOT_USER);
-#endif
-#ifdef _PAGE_OLD
-       printdef("PAGE_OLD",            _PAGE_OLD);
-#endif
-#ifdef _PAGE_CLEAN
-       printdef("PAGE_CLEAN",          _PAGE_CLEAN);
-#endif
-       printdef("TSS_MEMMAP",          (int)tss_memmap);
-       printdef("TSS_SAVE",            (int)tss_save);
-#ifdef __HAS_tss_memcmap
-       printdef("TSS_MEMCMAP",         (int)tss_memcmap);
-#endif
-#ifdef __HAS_addr_limit
-       printdef("ADDR_LIMIT",          (int)addr_limit);
-#endif
-#ifdef __HAS_kernel_domain
-       printdef("KERNEL_DOMAIN",       kernel_domain);
-#endif
-#ifdef __HAS_user_domain
-       printdef("USER_DOMAIN",         user_domain);
-#endif
-       printdef("TSS_FPESAVE",         (int)tss_fpesave);
-       printdef("MM",                  (int)mm);
-       printdef("PGD",                 (int)pgd);
-
-       printf("#define KSWI_BASE       0x900000\n");
-       printf("#define KSWI_SYS_BASE   0x9F0000\n");
-       printf("#define SYS_ERROR0      0x9F0000\n");
-       return 0;
-}
diff --git a/arch/arm/lib/getconstants.h b/arch/arm/lib/getconstants.h
deleted file mode 100644 (file)
index ef96377..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * *** THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT! ***
- */
-unsigned long addr_limit = 56;
-#define __HAS_addr_limit
-unsigned long tss_memmap = 640;
-#define __HAS_tss_memmap
-unsigned long mm = 1676;
-#define __HAS_mm
-unsigned long pgd = 8;
-#define __HAS_pgd
-unsigned long tss_save = 636;
-#define __HAS_tss_save
-unsigned long tss_fpesave = 492;
-#define __HAS_tss_fpesave
-unsigned long tss_memcmap = 644;
-#define __HAS_tss_memcmap
index 172783b02646b0a7ea35a282fbd9a7019c86140d..51550e014746703a226d530ec43dd84d7a9bb53e 100644 (file)
@@ -57,7 +57,7 @@ ENTRY(insw)
                mov     r2, r2, lsl#1
 ENTRY(inswb)
                mov     ip, sp
-               stmfd   sp!, {r4 - r10 ,fp ,ip ,lr ,pc}
+               stmfd   sp!, {r4 - r10, fp, ip, lr, pc}
                sub     fp, ip, #4
                addr    r3, r0
                add     r0, r3, r0, lsl #2
@@ -70,7 +70,7 @@ ENTRY(inswb)
                strgeb  r4, [r1], #1
                movgt   r4, r4, LSR#8
                strgtb  r4, [r1], #1
-               ldmleea fp, {r4 - r10, fp, sp, pc}^
+               LOADREGS(leea, fp, {r4 - r10, fp, sp, pc})
                sub     r2, r2, #2
 Linswok:       mov     ip, #0xFF
                orr     ip, ip, ip, lsl #8
diff --git a/arch/arm/lib/io-ebsa285.S b/arch/arm/lib/io-ebsa285.S
new file mode 100644 (file)
index 0000000..a5c6386
--- /dev/null
@@ -0,0 +1,109 @@
+#define __ASSEMBLER__
+#include <linux/linkage.h>
+
+ENTRY(insl)
+               add     r0, r0, #0xff000000
+               add     r0, r0, #0x00e00000
+               ands    ip, r1, #3
+               bne     2f
+
+1:             ldr     r3, [r0]
+               str     r3, [r1], #4
+               subs    r2, r2, #1
+               bne     1b
+               mov     pc, lr
+
+2:             cmp     ip, #2
+               ldr     ip, [r0]
+               blt     3f
+               bgt     4f
+
+               strh    ip, [r1], #2
+               mov     ip, ip, lsr #16
+1:             subs    r2, r2, #1
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, lsl #16
+               strne   ip, [r1], #4
+               movne   ip, r3, lsr #16
+               bne     1b
+               strh    ip, [r1], #2
+               mov     pc, lr
+
+3:             strb    ip, [r1], #1
+               mov     ip, ip, lsr #8
+               strh    ip, [r1], #2
+               mov     ip, ip, lsr #16
+1:             subs    r2, r2, #1
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, lsl #8
+               strne   ip, [r1], #4
+               movne   ip, r3, lsr #24
+               bne     1b
+               strb    ip, [r1], #1
+               mov     pc, lr
+
+4:             strb    ip, [r1], #1
+               mov     ip, ip, lsr #8
+1:             subs    r2, r2, #1
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, lsl #24
+               strne   ip, [r1], #4
+               movne   ip, r3, lsr #8
+               bne     1b
+               strb    ip, [r1], #1
+               mov     ip, ip, lsr #8
+               strh    ip, [r1], #2
+               mov     pc, lr
+
+ENTRY(outsl)
+               add     r0, r0, #0xff000000
+               add     r0, r0, #0x00e00000
+               ands    ip, r1, #3
+               bne     2f
+
+1:             ldr     r3, [r1], #4
+               str     r3, [r0]
+               subs    r2, r2, #1
+               bne     1b
+               mov     pc, lr
+
+2:             bic     r1, r1, #3
+               cmp     ip, #2
+               ldr     ip, [r1], #4
+               mov     ip, ip, lsr #16
+               blt     3f
+               bgt     4f
+
+1:             ldr     r3, [r1], #4
+               orr     ip, ip, r3, lsl #16
+               str     ip, [r0]
+               mov     ip, r3, lsr #16
+               subs    r2, r2, #1
+               bne     1b
+               mov     pc, lr
+
+3:             ldr     r3, [r1], #4
+               orr     ip, ip, r3, lsl #8
+               str     ip, [r0]
+               mov     ip, r3, lsr #24
+               subs    r2, r2, #1
+               bne     3b
+               mov     pc, lr
+
+4:             ldr     r3, [r1], #4
+               orr     ip, ip, r3, lsl #24
+               str     ip, [r0]
+               mov     ip, r3, lsr #8
+               subs    r2, r2, #1
+               bne     4b
+               mov     pc, lr
+
+
+ENTRY(outsw)
+ENTRY(outswb)
+               mov     pc, lr
+
+ENTRY(insw)
+ENTRY(inswb)
+               mov     pc, lr
+
index 7df08d93bd545e300e8d966a7760d4bfe8ec2799..fb1a5c5a49928b78be8565fd707c38a88b67f374 100644 (file)
@@ -3,9 +3,10 @@
  *
  * Copyright (C) 1995, 1996 Russell King.
  *
- * Speedups & 1bpp code (C) 1996 Philip Blundel & Russell King.
+ * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King.
  *
  * 10-04-96    RMK     Various cleanups & reduced register usage.
+ * 08-04-98    RMK     Shifts re-ordered
  */
 
 @ Regs: [] = corruptable
@@ -32,22 +33,22 @@ ENTRY(ll_write_char)
 @
 @ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc)
 @
-               eor     ip, r1, #UNDERLINE << 24
+               eor     ip, r1, #UNDERLINE << 9
 /*
  * calculate colours
  */
-               tst     r1, #INVERSE << 24
-               moveq   r2, r1, lsr #8
-               moveq   r3, r1, lsr #16
-               movne   r2, r1, lsr #16
-               movne   r3, r1, lsr #8
+               tst     r1, #INVERSE << 9
+               moveq   r2, r1, lsr #16
+               moveq   r3, r1, lsr #24
+               movne   r2, r1, lsr #24
+               movne   r3, r1, lsr #16
                and     r3, r3, #255
                and     r2, r2, #255
 /*
  * calculate offset into character table
  */
-               and     r1, r1, #255
-               mov     r1, r1, lsl #3
+               mov     r1, r1, lsl #23
+               mov     r1, r1, lsr #20
 /*
  * calculate offset required for each row [maybe I should make this an argument to this fn.
  * Have to see what the register usage is like in the calling routines.
@@ -67,7 +68,7 @@ ENTRY(ll_write_char)
                add     r0, r0, r5, lsl #3              @ Move to bottom of character
                add     r1, r1, #7
                ldrb    r7, [r6, r1]
-               tst     ip, #UNDERLINE << 24
+               tst     ip, #UNDERLINE << 9
                eoreq   r7, r7, #255
                teq     r4, #8
                beq     Lrow8bpplp
@@ -131,7 +132,7 @@ Lrow8bpplp: mov     ip, r7, lsr #4
 @
 Lrow1bpp:      add     r6, r6, r1
                ldmia   r6, {r4, r7}
-               tst     ip, #INVERSE << 24
+               tst     ip, #INVERSE << 9
                mvnne   r4, r4
                mvnne   r7, r7
                strb    r4, [r0], r5
@@ -147,7 +148,7 @@ Lrow1bpp:   add     r6, r6, r1
                mov     r7, r7, lsr #8
                strb    r7, [r0], r5
                mov     r7, r7, lsr #8
-               tst     ip, #UNDERLINE << 24
+               tst     ip, #UNDERLINE << 9
                mvneq   r7, r7
                strb    r7, [r0], r5
                LOADREGS(fd, sp!, {r4 - r7, pc})
index 209768f9f106b830dc02d20b9378b9cb5e93f223..f26e6cb1cf83b0ff4f4db82d7f05058da0569af2 100644 (file)
@@ -8,6 +8,12 @@
 #include <asm/assembler.h>
 #include <linux/linkage.h>
 
+#ifndef ENTRY
+#define ENTRY(x...)                            \
+               .globl  _##x;                   \
+_##x:
+#endif
+
                .text
 #define ENTER  \
                mov     ip,sp   ;\
@@ -84,6 +90,7 @@ ENTRY(memmove)
                blt     6b
                ands    ip, r1, #3
                beq     1b
+
 8:             bic     r1, r1, #3
                ldr     r7, [r1], #4
                cmp     ip, #2
@@ -105,14 +112,14 @@ ENTRY(memmove)
                subs    r2, r2, #16
                bge     9b
                adds    r2, r2, #12
-               blt     1b
+               blt     100f
 10:            mov     r3, r7, lsr #8
                ldr     r7, [r1], #4
                orr     r3, r3, r7, lsl #24
                str     r3, [r0], #4
                subs    r2, r2, #4
                bge     10b
-               sub     r1, r1, #3
+100:           sub     r1, r1, #3
                b       6b
 
 11:            cmp     r2, #12
index a1524bee969b1ee8db33fbb57ebbcd453849d06e..78256b319c2a5eee44f5def7d0e16fd3e755afc5 100644 (file)
 #include <asm/errno.h>
 
                .text
-
+#ifdef ENTRY
 #define USER(x...)                                     \
 9999:          x;                                      \
                .section __ex_table,"a";                \
                .align  3;                              \
                .long   9999b,9001f;                    \
                .previous
+#else
+#define USER(x...)                                     \
+               x
+#define ENTRY(x...)                                    \
+               .globl  _##x;                           \
+_##x:
+#define TESTING
+#endif
 
 #define PAGE_SHIFT 12
 
@@ -278,12 +286,12 @@ USER(             strgebt r3, [r0], #1)                   // May fault
 USER(          strgtbt r3, [r0], #1)                   // May fault
                b       .c2u_finished
 
+#ifndef TESTING
                .section .fixup,"ax"
                .align  0
 9001:          LOADREGS(fd,sp!, {r0, r4 - r7, pc})
                .previous
-
-
+#endif
 
 /* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n);
  * Purpose  : copy a block from user memory to kernel memory
@@ -538,10 +546,12 @@ USER(             ldrget  r3, [r1], #0)                   // May fault
                strgtb  r3, [r0], #1
                b       .cfu_finished
 
+#ifndef TESTING
                .section .fixup,"ax"
                .align  0
 9001:          LOADREGS(fd,sp!, {r0, r4 - r7, pc})
                .previous
+#endif
 
 /* Prototype: int __arch_clear_user(void *addr, size_t sz)
  * Purpose  : clear some user memory
@@ -556,7 +566,7 @@ ENTRY(__arch_clear_user)
                blt     2f
                ands    ip, r0, #3
                beq     1f
-               cmp     ip, #1
+               cmp     ip, #2
 USER(          strbt   r2, [r0], #1)
 USER(          strlebt r2, [r0], #1)
 USER(          strltbt r2, [r0], #1)
@@ -566,9 +576,9 @@ USER(               strltbt r2, [r0], #1)
 USER(          strplt  r2, [r0], #4)
 USER(          strplt  r2, [r0], #4)
                bpl     1b
-2:             adds    r1, r1, #4              @  3  2  1  0 -1 -2 -3
+               adds    r1, r1, #4              @  3  2  1  0 -1 -2 -3
 USER(          strplt  r2, [r0], #4)
-               tst     r1, #2                  @ 1x 1x 0x 0x 1x 1x 0x
+2:             tst     r1, #2                  @ 1x 1x 0x 0x 1x 1x 0x
 USER(          strnebt r2, [r0], #1)
 USER(          strnebt r2, [r0], #1)
                tst     r1, #1                  @ x1 x0 x1 x0 x1 x0 x1
@@ -576,6 +586,7 @@ USER(               strnebt r2, [r0], #1)
                mov     r0, #0
                LOADREGS(fd,sp!, {r1, pc})
 
+#ifndef TESTING
                .section .fixup,"ax"
                .align  0
 9001:          LOADREGS(fd,sp!, {r0, pc})
@@ -611,21 +622,25 @@ USER(             ldrbt   r1, [r0], #1)
  */
 ENTRY(__arch_strncpy_from_user)
                stmfd   sp!, {lr}
-               mov     ip, r2
+               add     ip, r1, #1
 1:             subs    r2, r2, #1
                bmi     2f
 USER(          ldrbt   r3, [r1], #1)
                strb    r3, [r0], #1
                teq     r3, #0
                bne     1b
-2:             subs    r0, ip, r2
-               LOADREGS(fd,sp!, {pc})
+               sub     r0, r1, ip
+               LOADREGS(fd, sp!, {pc})
+2:             sub     ip, ip, #1
+               sub     r0, r1, ip
+               LOADREGS(fd, sp!, {pc})
 
                .section .fixup,"ax"
                .align  0
 9001:          mov     r0, #-EFAULT
-               LOADREGS(fd,sp!, {pc})
+               LOADREGS(fd, sp!, {pc})
                .previous
 
                .align
+#endif
 
index 0488da561c2959d16a246636e24d5517e3b02a67..be9be35f0f8521391d6470113d6b2a18c8474a28 100644 (file)
@@ -7,8 +7,14 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
+ifeq ($(MACHINE),a5k)
+MMARCH=arc
+else
+MMARCH=$(MACHINE)
+endif
+
 O_TARGET := mm.o
-O_OBJS   := init.o extable.o fault-$(PROCESSOR).o mm-$(MACHINE).o
+O_OBJS   := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o
 
 ifeq ($(PROCESSOR),armo)
  O_OBJS += proc-arm2,3.o
@@ -28,9 +34,9 @@ proc-sa110.o: ../lib/constants.h
 ../lib/constants.h:
        @$(MAKE) -C ../lib constants.h
 
+ifneq ($(CONFIG_BINUTILS_NEW),y)
 %.o: %.S
-ifndef $(CONFIG_BINUTILS_NEW)
-       $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.s
-       $(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.s
-       $(RM) ..tmp.s
+       $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s
+       $(CC) $(CFLAGS:-pipe=) -c -o $@ ..$@.tmp.s
+       $(RM) ..$@.tmp.s
 endif
index 02cde532ff706d176bb9cff369e2d53ea1861ecd..051b336bfe9a294853bbf72378887dc17c134bb4 100644 (file)
 
 struct pgtable_cache_struct quicklists;
 
-void __bad_pte(pmd_t *pmd)
+void __bad_pmd(pmd_t *pmd)
 {
        printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
        set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
 }
 
-void __bad_pte_kernel(pmd_t *pmd)
+void __bad_pmd_kernel(pmd_t *pmd)
 {
        printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
        set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
@@ -72,7 +72,7 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
        }
        free_small_page ((unsigned long) pte);
        if (pmd_bad(*pmd)) {
-               __bad_pte(pmd);
+               __bad_pmd(pmd);
                return NULL;
        }
        return (pte_t *) pmd_page(*pmd) + offset;
@@ -94,7 +94,7 @@ pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
        }
        free_small_page ((unsigned long) pte);
        if (pmd_bad(*pmd)) {
-               __bad_pte_kernel(pmd);
+               __bad_pmd_kernel(pmd);
                return NULL;
        }
        return (pte_t *) pmd_page(*pmd) + offset;
@@ -102,6 +102,19 @@ pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
 
 extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
 
+#ifdef DEBUG
+static int sp_valid (unsigned long *sp)
+{
+       unsigned long addr = (unsigned long) sp;
+
+       if (addr >= 0xb0000000 && addr < 0xd0000000)
+               return 1;
+       if (addr >= 0x03ff0000 && addr < 0x04000000)
+               return 1;
+       return 0;
+}
+#endif
+
 static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
                               struct task_struct *tsk, struct mm_struct *mm)
 {
@@ -178,6 +191,16 @@ bad_area:
                printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
                        tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
 #ifdef DEBUG
+               {
+                       unsigned int i, j;
+                       unsigned long *sp = (unsigned long *) (regs->ARM_sp - 128);
+                       for (j = 0; j < 20 && sp_valid (sp); j++) {
+                               printk ("%p: ", sp);
+                               for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
+                                       printk ("%08lx ", *sp);
+                               printk ("\n");
+                       }
+               }
                show_regs (regs);
                c_backtrace (regs->ARM_fp, regs->ARM_cpsr);
 #endif
@@ -208,7 +231,6 @@ do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
 {
        if (user_mode(regs))
                error_code |= FAULT_CODE_USER;
-
 #define DIE(signr,nam)\
                force_sig(signr, current);\
                die_if_kernel(nam, regs, fsr, signr);\
@@ -229,18 +251,22 @@ do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
        case 11:
                DIE(SIGSEGV, "Domain fault")
        case 13:/* permission fault on section */
-#ifndef DEBUG
+#ifdef DEBUG
                {
-                       unsigned int i, j, a;
-static int count=2;
-if (count-- == 0) while (1);
-                       a = regs->ARM_sp;
-                       for (j = 0; j < 10; j++) {
-                               printk ("%08x: ", a);
-                               for (i = 0; i < 8; i += 1, a += 4)
-                                       printk ("%08lx ", *(unsigned long *)a);
+                       unsigned int i, j;
+                       unsigned long *sp;
+
+                       printk ("%s: section permission fault (bad address=0x%08lx, code %d)\n",
+                               current->comm, addr, error_code);
+                       sp = (unsigned long *) (regs->ARM_sp - 128);
+                       for (j = 0; j < 20 && sp_valid (sp); j++) {
+                               printk ("%p: ", sp);
+                               for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
+                                       printk ("%08lx ", *sp);
                                printk ("\n");
                        }
+                       show_regs (regs);
+                       c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
                }
 #endif
                DIE(SIGSEGV, "Permission fault")
index 4bc17c8c15e64d15028bdbdb298c3599cb37f378..36b118eb2c3ac797fc13d0e17cc6222cc9b25131 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/smp.h>
+#include <linux/init.h>
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>
 #endif
@@ -102,7 +103,7 @@ void show_mem(void)
 /*
  * paging_init() sets up the page tables...
  */
-unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem))
 {
        extern unsigned long free_area_init(unsigned long, unsigned long);
 
@@ -129,7 +130,7 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
  * memory is free.  This is done after various parts of the system have
  * claimed their memory after the kernel image.
  */
-void mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 {
        extern void sound_init(void);
        int codepages = 0;
diff --git a/arch/arm/mm/mm-a5k.c b/arch/arm/mm/mm-a5k.c
deleted file mode 100644 (file)
index 3906a29..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * arch/arm/mm/mm-a5k.c
- *
- * Extra MM routines for the Archimedes architecture
- *
- * Copyright (C) 1998 Russell King
- */
index 4a4b4718c9b4b7c0bb23500b2952906f471d3133..ff447a6be3387567065191efd3e05a4394ca9337 100644 (file)
@@ -5,3 +5,4 @@
  *
  * Copyright (C) 1998 Russell King
  */
+#include <asm/arch/mm-init.h>
index 907a3f399f8518bb53067fadd17a57e9618f2354..a937e098d8509abe118e879efff4d8c41654e4d8 100644 (file)
@@ -5,3 +5,22 @@
  *
  * Copyright (C) 1998 Russell King
  */
+
+#include <asm/io.h>
+/* map in IO */
+void setup_io_pagetables(void)
+{
+       unsigned long address = IO_START;
+       int spi = IO_BASE >> PGDIR_SHIFT;
+
+       pgd_val(swapper_pg_dir[spi-1]) = 0xc0000000 | PMD_TYPE_SECT |
+                                        PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
+
+       while (address < IO_START + IO_SIZE && address) {
+               pgd_val(swapper_pg_dir[spi++]) = address | PMD_TYPE_SECT |
+                                               PMD_DOMAIN(DOMAIN_IO) |
+                                               PMD_SECT_AP_WRITE;
+               address += PGDIR_SIZE;
+       }
+}
diff --git a/arch/arm/mm/mm-ebsa285.c b/arch/arm/mm/mm-ebsa285.c
new file mode 100644 (file)
index 0000000..eb5d715
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * arch/arm/mm/mm-ebsa285.c
+ *
+ * Extra MM routines for the EBSA285 architecture
+ *
+ * Copyright (C) 1998 Russell King
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/proc/mm-init.h>
+/*    Logical    Physical
+ * 0xfff00000  0x40000000      X-Bus
+ * 0xffe00000  0x7c000000      PCI I/O space
+ * 0xfe000000  0x42000000      CSR
+ * 0xfd000000  0x78000000      Outbound write flush
+ * 0xfc000000  0x79000000      PCI IACK/special space
+ * 0xf9000000  0x7a000000      PCI Config type 1
+ * 0xf8000000  0x7b000000      PCI Config type 0
+ */
+
+static struct mapping {
+       unsigned long virtual;
+       unsigned long physical;
+       unsigned long length;
+} io_mapping[] = {
+       /*
+        * This is to allow us to fiddle with the EEPROM
+        *  This entry will go away in time
+        */
+       { 0xd8000000, 0x41000000, 0x00400000 },
+
+       /*
+        * These ones are so that we can fiddle
+        *  with the various cards (eg VGA)
+        *  until we're happy with them...
+        */
+       { 0xdc000000, 0x7c000000, 0x00100000 },
+       { 0xe0000000, 0x80000000, 0x10000000 },
+
+       { 0xf8000000, 0x7b000000, 0x01000000 }, /* Type 0 Config */
+
+       { 0xf9000000, 0x7a000000, 0x01000000 }, /* Type 1 Config */
+
+       { 0xfc000000, 0x79000000, 0x01000000 }, /* PCI IACK      */
+       { 0xfd000000, 0x78000000, 0x01000000 }, /* Outbound wflsh*/
+       { 0xfe000000, 0x42000000, 0x01000000 }, /* CSR           */
+       { 0xffe00000, 0x7c000000, 0x00100000 }, /* PCI I/O       */
+       { 0xfff00000, 0x40000000, 0x00100000 }, /* X-Bus         */
+};
+
+#define SIZEOFIO (sizeof(io_mapping) / sizeof(io_mapping[0]))
+
+/* map in IO */
+unsigned long setup_io_pagetables(unsigned long start_mem)
+{
+       struct mapping *mp;
+       int i;
+
+       for (i = 0, mp = io_mapping; i < SIZEOFIO; i++, mp++) {
+               while ((mp->virtual & 1048575 || mp->physical & 1048575) && mp->length >= PAGE_SIZE) {
+                       alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+                                       PTE_AP_WRITE);
+
+                       mp->length -= PAGE_SIZE;
+                       mp->virtual += PAGE_SIZE;
+                       mp->physical += PAGE_SIZE;
+               }
+
+               while (mp->length >= 1048576) {
+if (mp->virtual > 0xf0000000)
+                       alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+                                          PMD_SECT_AP_WRITE);
+else
+alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_USER, PMD_SECT_AP_WRITE | PMD_SECT_AP_READ);
+
+                       mp->length -= 1048576;
+                       mp->virtual += 1048576;
+                       mp->physical += 1048576;
+               }
+
+               while (mp->length >= PAGE_SIZE) {
+                       alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+                                       PTE_AP_WRITE);
+
+                       mp->length -= PAGE_SIZE;
+                       mp->virtual += PAGE_SIZE;
+                       mp->physical += PAGE_SIZE;
+               }
+       }
+       return start_mem;
+}
+
index bbae80b190170da181c138ac4c06a025782f89e3..2bb2d0fabc81687d1f646150bbc49e2c266feec4 100644 (file)
@@ -1,7 +1,28 @@
 /*
  * arch/arm/mm/mm-nexuspci.c
+ *  from arch/arm/mm/mm-ebsa110.c
  *
- * Extra MM routines for the Archimedes architecture
+ * Extra MM routines for the NexusPCI architecture
  *
  * Copyright (C) 1998 Russell King
  */
+
+#include <asm/io.h>
+/* map in IO */
+void setup_io_pagetables(void)
+{
+       unsigned long address = IO_START;
+       int spi = IO_BASE >> PGDIR_SHIFT;
+
+       pgd_val(swapper_pg_dir[spi-1]) = 0xc0000000 | PMD_TYPE_SECT |
+                                        PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
+
+       while (address < IO_START + IO_SIZE && address) {
+               pgd_val(swapper_pg_dir[spi++]) = address | PMD_TYPE_SECT |
+                                               PMD_DOMAIN(DOMAIN_IO) |
+                                               PMD_SECT_AP_WRITE;
+               address += PGDIR_SIZE;
+       }
+}
+
index 5eccb1f812c0dd921778f292e0040115d1f9bf3f..f789b8f7970a29e28551d6e81fe730e9b92f4f8c 100644 (file)
@@ -6,7 +6,14 @@
  * Copyright (C) 1998 Russell King
  */
 
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/pgtable.h>
 #include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/proc/mm-init.h>
+#include <asm/arch/mm-init.h>
 
 #define NR_DRAM_BANKS  4
 #define NR_VRAM_BANKS  1
@@ -21,8 +28,8 @@
 #define FIRST_DRAM_ADDR        0x10000000
 
 #define PHYS_TO_BANK(x)        (((x) >> BANK_SHIFT) & (NR_DRAM_BANKS - 1))
-#define BANK_TO_PHYS(x)        ((FIRST_DRAM_ADDR) +
-                           (((x) - FIRST_DRAM_BANK) << BANK_SHIFT)
+#define BANK_TO_PHYS(x)        ((FIRST_DRAM_ADDR) + \
+                           (((x) - FIRST_DRAM_BANK) << BANK_SHIFT))
 
 struct ram_bank {
        unsigned int virt_addr;         /* virtual address of the *end* of this bank + 1 */
@@ -75,6 +82,56 @@ void init_dram_banks(struct param_struct *params)
                rambank[bank].virt_addr   = PAGE_OFFSET + bytes;
        }
 
-       drambank[4].phys_offset = 0xd6000000;
-       drambank[4].virt_addr   = 0xd8000000;
+       rambank[FIRST_VRAM_BANK].phys_offset = 0xd6000000;
+       rambank[FIRST_VRAM_BANK].virt_addr   = 0xd8000000;
+
+       current->tss.memmap = __virt_to_phys((unsigned long)swapper_pg_dir);
+}
+
+static struct mapping {
+       unsigned long virtual;
+       unsigned long physical;
+       unsigned long length;
+} io_mapping[] = {
+       { SCREEN2_BASE, SCREEN_START,   2*1048576       },      /* VRAM         */
+       { IO_BASE,      IO_START,       IO_SIZE         }       /* IO space     */
+};
+
+#define SIZEOFIO (sizeof(io_mapping) / sizeof(io_mapping[0]))
+
+/* map in IO */
+unsigned long setup_io_pagetables(unsigned long start_mem)
+{
+       struct mapping *mp;
+       int i;
+
+       for (i = 0, mp = io_mapping; i < SIZEOFIO; i++, mp++) {
+               while ((mp->virtual & 1048575 || mp->physical & 1048575) && mp->length >= PAGE_SIZE) {
+                       alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+                                       PTE_AP_WRITE);
+
+                       mp->length -= PAGE_SIZE;
+                       mp->virtual += PAGE_SIZE;
+                       mp->physical += PAGE_SIZE;
+               }
+
+               while (mp->length >= 1048576) {
+                       alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+                                          PMD_SECT_AP_WRITE);
+                       mp->length -= 1048576;
+                       mp->virtual += 1048576;
+                       mp->physical += 1048576;
+               }
+
+               while (mp->length >= PAGE_SIZE) {
+                       alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+                                       PTE_AP_WRITE);
+
+                       mp->length -= PAGE_SIZE;
+                       mp->virtual += PAGE_SIZE;
+                       mp->physical += PAGE_SIZE;
+               }
+       }
+
+       return start_mem;
 }
index 776d0d57c1ed4122966a9d1d190dd72e913e1fc3..a853671fc131e113eb1c73987ff4cbc1692329fa 100644 (file)
@@ -72,10 +72,10 @@ _arm6_7_switch_to:
                stmfd   sp!, {ip}                       @ Save cpsr_SVC
                str     sp, [r0, #TSS_SAVE]             @ Save sp_SVC
                ldr     sp, [r1, #TSS_SAVE]             @ Get saved sp_SVC
-               ldr     r0, [r1, #ADDR_LIMIT]
+               ldr     r0, [r1, #TSK_ADDR_LIMIT]
                teq     r0, #0
-               moveq   r0, #KERNEL_DOMAIN
-               movne   r0, #USER_DOMAIN
+               moveq   r0, #DOM_KERNELDOMAIN
+               movne   r0, #DOM_USERDOMAIN
                mcr     p15, 0, r0, c3, c0              @ Set domain reg
                ldr     r0, [r1, #TSS_MEMMAP]           @ Page table pointer
                mov     r1, #0
index 7d53bf2302c088ca8f94ee3656b43e566ed6f581..633e8c164a23952f31db86896425f8cd8c9007bc 100644 (file)
@@ -161,8 +161,6 @@ _sa110_flush_icache_area:
                blt     1b
                mcr     p15, 0, r0, c7, c5, 0           @ flush I cache
                mov     pc, lr
-
-@LC0:          .word   _current
 /*
  * Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next)
  *
@@ -183,10 +181,10 @@ _sa110_switch_to:
                stmfd   sp!, {ip}                       @ Save cpsr_SVC
                str     sp, [r0, #TSS_SAVE]             @ Save sp_SVC
                ldr     sp, [r1, #TSS_SAVE]             @ Get saved sp_SVC
-               ldr     r0, [r1, #ADDR_LIMIT]
+               ldr     r0, [r1, #TSK_ADDR_LIMIT]
                teq     r0, #0
-               moveq   r0, #KERNEL_DOMAIN
-               movne   r0, #USER_DOMAIN
+               moveq   r0, #DOM_KERNELDOMAIN
+               movne   r0, #DOM_USERDOMAIN
                mcr     p15, 0, r0, c3, c0              @ Set segment
                ldr     r0, [r1, #TSS_MEMMAP]           @ Page table pointer
                ldr     r3, =Lclean_switch
@@ -227,8 +225,6 @@ _sa110_data_abort:
                mov     r2, r2, lsr #19                 @ b1 = L
                and     r3, r2, #0x69 << 2
                and     r2, r2, #2
-//             teq     r3, #0x21 << 2
-//             orreq   r2, r2, #1                      @ b0 = {LD,ST}RT
                mrc     p15, 0, r1, c5, c0, 0           @ get FSR
                and     r1, r1, #255
                mov     pc, lr
index 787e5c99d8953c65026058e7407fa83927a46f48..db1f720e72c41d4f3030f596d3da011d4de9a16c 100644 (file)
@@ -1,4 +1,5 @@
-/* ld script to make i386 Linux kernel
+/* ld script to make ARM Linux kernel
+ * taken from the i386 version
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")
@@ -34,11 +35,15 @@ SECTIONS
 
   _edata = .;                  /* End of data section */
 
-  . = ALIGN(4096);             /* Init code and data */
+  /* This has to be aligned to a page boundary to do us any good.  This
+     alignment is overkill for ARM6 up but needed for ARM3.  Since all this
+     data will be thrown away I don't think the extra padding will hurt.
+       -- pb */
+  . = ALIGN(32768);            /* Init code and data */
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
-  . = ALIGN(4096);
+  . = ALIGN(32768);
   __init_end = .;
 
   __bss_start = .;             /* BSS */
index 662acf9fdf616a1e7259c3239595820c8fb57be2..5b46c8302c9da2c42b10eb7b234de4ee87267214 100644 (file)
@@ -112,7 +112,6 @@ static void read_intr (ide_drive_t *drive)
        int i;
        unsigned int msect, nsect;
        struct request *rq;
-       unsigned long flags;
 
        if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
                ide_error(drive, "read_intr", stat);
@@ -162,7 +161,6 @@ static void write_intr (ide_drive_t *drive)
        int i;
        ide_hwgroup_t *hwgroup = HWGROUP(drive);
        struct request *rq = hwgroup->rq;
-       unsigned long flags;
        int error = 0;
 
        if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
@@ -239,7 +237,6 @@ static void multwrite_intr (ide_drive_t *drive)
        int i;
        ide_hwgroup_t *hwgroup = HWGROUP(drive);
        struct request *rq = &hwgroup->wrq;
-       unsigned long flags;
        int error = 0;
 
        if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
index 3f3a9cd6c6280006f4d466c4c150efb797c15480..6f123108234eed9fff6d9c4c797db4fd5fd230ee 100644 (file)
@@ -1267,7 +1267,6 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
 
 static void do_ide_intr (int irq, void *dev_id, struct pt_regs *regs)
 {
-       unsigned long flags;
        ide_hwgroup_t *hwgroup = dev_id;
        ide_hwif_t *hwif = hwgroup->hwif;
        ide_handler_t *handler;
index eecd46c2bd9bc964cc84aefffad75c604fc38370..d1ae0a8b63b212266bed0298602ba216ff5dc0b7 100644 (file)
@@ -84,9 +84,9 @@ __initfunc(void ide_probe_for_rz100x (void))  /* called from ide.c */
 {
        struct pci_dev *dev = NULL;
 
-       while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_PD_PCTECH_RZ1000, dev))
+       while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))
                init_rz1000 (dev, "RZ1000");
-       while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_PD_PCTECH_RZ1001, dev))
+       while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))
                init_rz1000 (dev, "RZ1001");
 }
 
index 775c8fe2a065340b9bab4e30f3f93a78355cb0d1..9f51607fe63d7504a81432357f110c51f2558147 100644 (file)
@@ -1,6 +1,9 @@
 #define BLOCKMOVE
+#define        NEW_INTR_FLOW
+#define        Z_WAKE
+#define        NEW_PCI
 static char rcsid[] =
-"$Revision: 2.1.1.1 $$Date: 1997/12/03 17:31:19 $";
+"$Revision: 2.2.1.1 $$Date: 1998/03/19 16:43:12 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -30,11 +33,28 @@ static char rcsid[] =
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.2.1.1  1998/03/19 16:43:12 ivan
+ * added conditional compilation for new/old PCI structure support;
+ * removed kernel series (2.0.x / 2.1.x) conditional compilation.
+ *
+ * Revision 2.1.1.3  1998/03/16 18:01:12 ivan
+ * cleaned up the data loss fix;
+ * fixed XON/XOFF handling once more (Cyclades-Z);
+ * general revision in the driver routines;
+ * introduction of a mechanism to prevent data loss with slow 
+ * printers, by forcing a delay before closing the port.
+ *
+ * Revision 2.1.1.2  1998/02/17 16:50:00 ivan
+ * fixed detection/handling of new CD1400 in Ye boards;
+ * fixed XON/XOFF handling (Cyclades-Z);
+ * fixed data loss caused by a premature port close;
+ * introduction of a flag that holds the CD1400 version ID per port
+ * (used by the CYGETCD1400VER new ioctl).
+ *
  * Revision 2.1.1.1  1997/12/03 17:31:19 ivan
- * Code review for the module cleanup routine (fixed memory leak);
+ * Code review for the module cleanup routine;
  * fixed RTS and DTR status report for new CD1400's in get_modem_info;
- * purged conditional code for older kernels;
- * includes anonymous changes regarding signal_pending
+ * includes anonymous changes regarding signal_pending.
  * 
  * Revision 2.1  1997/11/01 17:42:41 ivan
  * Changes in the driver to support Alpha systems (except 8Zo V_1);
@@ -461,17 +481,16 @@ static char rcsid[] =
 #define ZO_V2  1
 #define ZE_V1  2
 
-#define SERIAL_PARANOIA_CHECK
-#undef  SERIAL_DEBUG_OPEN
-#undef  SERIAL_DEBUG_THROTTLE
-#undef  SERIAL_DEBUG_OTHER
-#undef  SERIAL_DEBUG_IO
-#undef  SERIAL_DEBUG_COUNT
-#undef  SERIAL_DEBUG_DTR
-#undef  CYCLOM_16Y_HACK
-#undef  CYCLOM_ENABLE_MONITORING
-#undef  CY_PCI_DEBUG
-
+#define        SERIAL_PARANOIA_CHECK
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_THROTTLE
+#undef SERIAL_DEBUG_OTHER
+#undef SERIAL_DEBUG_IO
+#undef SERIAL_DEBUG_COUNT
+#undef SERIAL_DEBUG_DTR
+#undef CYCLOM_16Y_HACK
+#undef CYCLOM_ENABLE_MONITORING
+#undef CY_PCI_DEBUG
 
 #if 0
 #define PAUSE __asm__("nop");
@@ -525,6 +544,9 @@ static char rcsid[] =
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#ifndef NEW_PCI
+#include <linux/bios32.h>
+#endif
 #include <linux/pci.h>
 
 #include <linux/version.h>
@@ -566,10 +588,9 @@ static unsigned long cy_get_user(unsigned long *addr)
 #define SERIAL_TYPE_NORMAL  1
 #define SERIAL_TYPE_CALLOUT 2
 
+static DECLARE_TASK_QUEUE(tq_cyclades);
 
-DECLARE_TASK_QUEUE(tq_cyclades);
-
-struct tty_driver cy_serial_driver, cy_callout_driver;
+static struct tty_driver cy_serial_driver, cy_callout_driver;
 
 static volatile int cy_irq_triggered;
 static volatile int cy_triggered;
@@ -856,7 +877,6 @@ do_cyclades_bh(void)
     run_task_queue(&tq_cyclades);
 } /* do_cyclades_bh */
 
-
 static void
 do_softint(void *private_)
 {
@@ -883,6 +903,11 @@ do_softint(void *private_)
         }
         wake_up_interruptible(&tty->write_wait);
     }
+#ifdef Z_WAKE
+    if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
+        wake_up_interruptible(&info->shutdown_wait);
+    }
+#endif
 } /* do_softint */
 
 
@@ -1014,6 +1039,7 @@ get_auto_irq(volatile ucchar *address)
   unsigned long        timeout;
   volatile ucchar      *base_addr;
   int                  index;
+  unsigned long                flags;
 
     index = 0;  /* IRQ probing is only for ISA */
     base_addr = address;
@@ -1023,13 +1049,13 @@ get_auto_irq(volatile ucchar *address)
      * Enable interrupts and see who answers
      */
     cy_irq_triggered = 0;
-    cli();
+    save_flags(flags); cli();
         cy_writeb((u_long)base_addr+(CyCAR<<index), 0);
         cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
         cy_writeb((u_long)base_addr+(CySRER<<index), 
              cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
         probe_ready = 1;
-    sti();
+    restore_flags(flags);
     
     timeout = jiffies+(HZ/50);
     while (timeout >= jiffies) {
@@ -1050,7 +1076,7 @@ do_auto_irq(volatile ucchar *address)
   int                   irq_lines = 0;
   int                   irq_try_1 = 0, irq_try_2 = 0;
   int                   retries;
-  unsigned long flags;
+  unsigned long                flags;
 
     /* Turn on interrupts (they may be off) */
     save_flags(flags); sti();
@@ -1346,7 +1372,7 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
                        /* delay a bit */
                         cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
                         cy_writeb((u_long)base_addr + (CyTDR<<index), 0x82);
-                        if (cy_readb(base_addr + (CyGFRCR<<index)) >= 0x48 ) {
+                        if (info->chip_rev >= CD1400_REV_J ) {
                            /* It is a CD1400 rev. J or later */
                             cy_writeb((u_long)base_addr + (CyTDR<<index), 
                                      info->x_break*500/HZ);
@@ -1361,7 +1387,30 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
                         info->x_break = 0;
                     }
 
+#ifdef NEW_INTR_FLOW
+                    if (!info->xmit_cnt){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+                        goto txdone;
+                    }
+                    if (info->xmit_buf == 0){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        goto txdone;
+                    }
+                    if (info->tty->stopped || info->tty->hw_stopped){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        goto txdone;
+                    }
+#endif
                     while (char_count-- > 0){
+#ifdef NEW_INTR_FLOW
+                        if (!info->xmit_cnt){
+                            goto txdone;
+                        }
+#else
                         if (!info->xmit_cnt){
                             cy_writeb((u_long)base_addr+(CySRER<<index),
                                cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
@@ -1375,8 +1424,8 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
                         if (info->tty->stopped || info->tty->hw_stopped){
                             cy_writeb((u_long)base_addr+(CySRER<<index),
                                cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
-                            goto txdone;
-                        }
+                       }
+#endif
                         /* Because the Embedded Transmit Commands have
                            been enabled, we must check to see if the
                           escape character, NULL, is being sent.  If it
@@ -1412,7 +1461,6 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
                     if (info->xmit_cnt < WAKEUP_CHARS) {
                         cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
                     }
-
         txend:
                     /* end of service */
                     cy_writeb((u_long)base_addr+(CyTIR<<index), 
@@ -1491,7 +1539,6 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
    /* clear interrupts */
    cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<<index), 0);
                                 /* Cy_ClrIntr is 0x1800 */
-
 } /* cyy_interrupt */
 
 /***********************************************************/
@@ -1714,6 +1761,11 @@ cyz_poll(unsigned long arg)
                break;
            case C_CM_MDSR:
                break;
+#ifdef Z_WAKE
+           case C_CM_IOCTLW:
+               cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+               break;
+#endif
            case C_CM_FATAL:
                /* should do something with this !!! */
                break;
@@ -1994,7 +2046,13 @@ startup(struct cyclades_port * info)
 #endif
 
        cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
-       cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD|C_IN_MCTS);
+#ifdef Z_WAKE
+       cy_writel(&ch_ctrl[channel].intr_enable, 
+                 C_IN_MDCD|C_IN_MCTS|C_IN_IOCTLW);
+#else
+       cy_writel(&ch_ctrl[channel].intr_enable, 
+                 C_IN_MDCD|C_IN_MCTS);
+#endif
        retval = cyz_issue_cmd( &cy_card[card],
            channel, C_CM_IOCTL, 0L);   /* was C_CM_RESET */
        if (retval != 0){
@@ -2089,20 +2147,14 @@ shutdown(struct cyclades_port * info)
                card, chip, channel, (long)base_addr);
 #endif
 
-       /* REALLY SHOULD WAIT FOR LAST CHARACTER TO BE
-          SENT BEFORE DROPPING THE LINE !!!  (Perhaps
-          set some flag that is read when XMTY happens.)
-          Other choices are to delay some fixed interval
-          or schedule some later processing.
-        */
        save_flags(flags); cli();
+
            if (info->xmit_buf){
                unsigned char * temp;
                temp = info->xmit_buf;
                info->xmit_buf = 0;
                free_page((unsigned long) temp);
            }
-
            cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
            if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
                cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
@@ -2147,14 +2199,15 @@ shutdown(struct cyclades_port * info)
        board_ctrl = &(zfw_ctrl->board_ctrl);
        ch_ctrl = zfw_ctrl->ch_ctrl;
 
-
        save_flags(flags); cli();
+
            if (info->xmit_buf){
                unsigned char * temp;
                temp = info->xmit_buf;
                info->xmit_buf = 0;
                free_page((unsigned long) temp);
            }
+           
            if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
                cy_writel((u_long)&ch_ctrl[channel].rs_control,
                    (uclong)(cy_readl(&ch_ctrl[channel].rs_control) & 
@@ -2162,14 +2215,13 @@ shutdown(struct cyclades_port * info)
                retval = cyz_issue_cmd(&cy_card[info->card],
                        channel, C_CM_IOCTLM, 0L);
                if (retval != 0){
-                   printk("cyc:shutdown retval was %x\n",
-                       retval);
+                   printk("cyc:shutdown retval (2) was %x\n", retval);
                }
 #ifdef SERIAL_DEBUG_DTR
                printk("cyc:shutdown dropping Z DTR\n");
 #endif
            }
-
+           
            if (info->tty){
                set_bit(TTY_IO_ERROR, &info->tty->flags);
            }
@@ -2206,8 +2258,10 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
      * If the device is in the middle of being closed, then block
      * until it's done, and then try again.
      */
-    if (info->flags & ASYNC_CLOSING) {
-        interruptible_sleep_on(&info->close_wait);
+    if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+       if (info->flags & ASYNC_CLOSING) {
+            interruptible_sleep_on(&info->close_wait);
+       }
         if (info->flags & ASYNC_HUP_NOTIFY){
             return -EAGAIN;
         }else{
@@ -2241,7 +2295,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
      * If non-blocking mode is set, then make the check up front
      * and then exit.
      */
-    if (filp->f_flags & O_NONBLOCK) {
+    if ((filp->f_flags & O_NONBLOCK) ||
+       (tty->flags & (1 << TTY_IO_ERROR))) {
         if (info->flags & ASYNC_CALLOUT_ACTIVE){
             return -EBUSY;
         }
@@ -2262,7 +2317,10 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
     printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
            info->line, info->count);/**/
 #endif
-    info->count--;
+    save_flags(flags); cli();
+    if (!tty_hung_up_p(filp))
+       info->count--;
+    restore_flags(flags);
 #ifdef SERIAL_DEBUG_COUNT
     printk("cyc block_til_ready: (%d): decrementing count to %d\n",
         current->pid, info->count);
@@ -2568,8 +2626,54 @@ cy_close(struct tty_struct * tty, struct file * filp)
         info->normal_termios = *tty->termios;
     if (info->flags & ASYNC_CALLOUT_ACTIVE)
         info->callout_termios = *tty->termios;
-    if (info->flags & ASYNC_INITIALIZED)
-        tty_wait_until_sent(tty, 5*HZ); /* 5 seconds timeout */
+
+    /*
+    * Now we wait for the transmit buffer to clear; and we notify
+    * the line discipline to only process XON/XOFF characters.
+    */
+    tty->closing = 1;
+    if (info->closing_wait2 != 0) { /* The port's being forced to wait, 
+                                      independent on the port settings */
+       tty_wait_until_sent(tty, info->closing_wait2*HZ);
+    } else {
+       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+           tty_wait_until_sent(tty, info->closing_wait*HZ);
+    }
+
+    /* Waiting for on-board buffers to be empty before closing the port */
+    if (!IS_CYC_Z(cy_card[info->card])) {
+#ifdef NEW_INTR_FLOW
+       unsigned char *base_addr = (unsigned char *) 
+                                       cy_card[info->card].base_addr;
+       int index = cy_card[info->card].bus_index;
+
+       if (cy_readb(base_addr+(CySRER<<index)) & CyTxMpty) {
+           /* Interrupts are enabled, so go to sleep */
+            interruptible_sleep_on(&info->shutdown_wait);
+       }
+#endif
+    } else {
+#ifdef Z_WAKE
+       unsigned char *base_addr = (unsigned char *) 
+                                       cy_card[info->card].base_addr;
+       struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+       struct ZFW_CTRL *zfw_ctrl = 
+           (struct ZFW_CTRL *) (base_addr + cy_readl(&firm_id->zfwctrl_addr));
+       struct CH_CTRL *ch_ctrl = zfw_ctrl->ch_ctrl;
+       int channel = info->line - cy_card[info->card].first_line;
+       int retval;
+
+       if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+           retval = cyz_issue_cmd(&cy_card[info->card], channel, 
+                                  C_CM_IOCTLW, 0L);
+           if (retval != 0){
+               printk("cyc:shutdown retval (1) was %x\n", retval);
+           }
+           interruptible_sleep_on(&info->shutdown_wait);
+       }
+#endif
+    }
+
     shutdown(info);
     if (tty->driver.flush_buffer)
         tty->driver.flush_buffer(tty);
@@ -2634,14 +2738,13 @@ cy_write(struct tty_struct * tty, int from_user,
 
     if (from_user)
        down(&tmp_buf_sem);
+    save_flags(flags);               
     while (1) {
-        save_flags(flags); cli();               
+        cli();               
         c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                            SERIAL_XMIT_SIZE - info->xmit_head));
-        if (c <= 0){
-            restore_flags(flags);
+        if (c <= 0)
             break;
-        }
 
         if (from_user) {
             copy_from_user(tmp_buf, buf, c);
@@ -2664,13 +2767,10 @@ cy_write(struct tty_struct * tty, int from_user,
     }
     if (from_user)
        up(&tmp_buf_sem);
-
-
-    if (info->xmit_cnt
-    && !tty->stopped
-    && !tty->hw_stopped ) {
+    if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
         start_xmit(info);
     }
+    restore_flags(flags);
     return total;
 } /* cy_write */
 
@@ -2788,16 +2888,47 @@ static int
 cy_chars_in_buffer(struct tty_struct *tty)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  int card, channel;
                                 
-#ifdef SERIAL_DEBUG_IO
-    printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
-        info->line, info->xmit_cnt); /* */
-#endif
-
     if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer"))
         return 0;
 
-    return info->xmit_cnt;
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
+
+    if (!IS_CYC_Z(cy_card[card])) {
+#ifdef SERIAL_DEBUG_IO
+       printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+               info->line, info->xmit_cnt); /* */
+#endif
+       return info->xmit_cnt;
+    } else {
+       static volatile struct FIRM_ID *firm_id;
+       static volatile struct ZFW_CTRL *zfw_ctrl;
+       static volatile struct CH_CTRL *ch_ctrl;
+       static volatile struct BUF_CTRL *buf_ctrl;
+       int char_count;
+       volatile uclong tx_put, tx_get, tx_bufsize;
+
+       firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
+       zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
+                               cy_readl(&firm_id->zfwctrl_addr));
+       ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+       buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+       tx_get = cy_readl(&buf_ctrl->tx_get);
+       tx_put = cy_readl(&buf_ctrl->tx_put);
+       tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+       if (tx_put >= tx_get)
+           char_count = tx_put - tx_get;
+       else
+           char_count = tx_put - tx_get + tx_bufsize;
+#ifdef SERIAL_DEBUG_IO
+       printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+               info->line, info->xmit_cnt + char_count); /* */
+#endif
+       return (info->xmit_cnt + char_count);
+    }
 } /* cy_chars_in_buffer */
 
 
@@ -2818,7 +2949,8 @@ set_line_char(struct cyclades_port * info)
   unsigned long flags;
   unsigned char *base_addr;
   int card,chip,channel,index;
-  unsigned cflag;
+  unsigned cflag, iflag;
+  unsigned short chip_number;
   int   i;
 
 
@@ -2829,9 +2961,11 @@ set_line_char(struct cyclades_port * info)
         return;
     }
     cflag = info->tty->termios->c_cflag;
+    iflag = info->tty->termios->c_iflag;
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
+    chip_number = channel / 4;
 
     if (!IS_CYC_Z(cy_card[card])) {
 
@@ -2843,17 +2977,16 @@ set_line_char(struct cyclades_port * info)
        if (i & CBAUDEX) {
            if (i == B57600)
                i = 16;
+#ifdef B76800
+           else if(i == B76800) 
+               i = 17;
+#endif
            else if(i == B115200) 
                i = 18;
-           else if(i == B230400 && 
-                 cy_readb(cy_card[card].base_addr+(CyGFRCR<<index)) >= 0x48) {
+           else if(i == B230400 && (info->chip_rev >= CD1400_REV_J)) {
                /* It is a CD1400 rev. J or later */
                i = 20;
            }
-#ifdef B76800
-           else if(i == B76800) 
-               i = 17;
-#endif
            else
                info->tty->termios->c_cflag &= ~CBAUDEX;
        }
@@ -2867,6 +3000,10 @@ set_line_char(struct cyclades_port * info)
                 switch(info->baud) {
                    case 57600:
                        i += 1; break;
+#ifdef B76800
+                   case 76800: 
+                       i += 2; break;
+#endif
                    case 115200:
                        i += 3; break;
                    case 230400:
@@ -2876,7 +3013,7 @@ set_line_char(struct cyclades_port * info)
                }
             }
        }
-        if(cy_readb(cy_card[card].base_addr+(CyGFRCR<<index)) >= 0x48) {
+       if(info->chip_rev >= CD1400_REV_J) {
            /* It is a CD1400 rev. J or later */
            info->tbpr = baud_bpr_60[i]; /* Tx BPR */
            info->tco = baud_co_60[i]; /* Tx CO */
@@ -3115,6 +3252,16 @@ set_line_char(struct cyclades_port * info)
         case B460800: cy_writel(&ch_ctrl->comm_baud , 460800); break;
        }
 
+       if ((i = cy_readl(&ch_ctrl->comm_baud)) == 134) {
+           info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+           /* get it right for 134.5 baud */
+       } else if (i) {
+           info->timeout = (info->xmit_fifo_size*HZ*15/i) + 2;
+           /* this needs to be propagated into the card info */
+       } else {
+           info->timeout = 0;
+       }
+
        /* byte size and parity */
        switch(cflag & CSIZE){
        case CS5: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS5); break;
@@ -3150,7 +3297,7 @@ set_line_char(struct cyclades_port * info)
                cy_readl(&ch_ctrl->hw_flow) & ~(C_RS_CTS | C_RS_RTS));
        }
 
-       retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L);
+       retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
        if (retval != 0){
            printk("cyc:set_line_char retval at %d was %x\n",
                __LINE__, retval);
@@ -3163,6 +3310,14 @@ set_line_char(struct cyclades_port * info)
            info->flags |= ASYNC_CHECK_CD;
        }
 
+       if (iflag & IXON){
+           cy_writel(&ch_ctrl->sw_flow, 
+               cy_readl(&ch_ctrl->sw_flow) | C_FL_OXX);
+       } else {
+           cy_writel(&ch_ctrl->sw_flow, 
+               cy_readl(&ch_ctrl->sw_flow) & ~C_FL_OXX);
+       }
+
        if(i == 0){ /* baud rate is zero, turn off line */
            cy_writel(&ch_ctrl->rs_control,
                cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
@@ -3182,7 +3337,6 @@ set_line_char(struct cyclades_port * info)
            printk("cyc:set_line_char retval at %d was %x\n",
                __LINE__, retval);
        }
-       cy_readl(&ch_ctrl->comm_baud);
 
        if (info->tty){
            clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -3230,8 +3384,9 @@ set_serial_info(struct cyclades_port * info,
 
     if (!suser()) {
             if ((new_serial.close_delay != info->close_delay) ||
-                ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
-                 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
+               (new_serial.baud_base != info->baud) ||
+               ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
+                (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
                     return -EPERM;
             info->flags = ((info->flags & ~ASYNC_USR_MASK) |
                            (new_serial.flags & ASYNC_USR_MASK));
@@ -3245,11 +3400,12 @@ set_serial_info(struct cyclades_port * info,
      * At this point, we start making changes.....
      */
 
+    info->baud = new_serial.baud_base;
     info->flags = ((info->flags & ~ASYNC_FLAGS) |
                     (new_serial.flags & ASYNC_FLAGS));
-    info->baud = new_serial.baud_base;
-    info->close_delay = new_serial.close_delay;
-
+    info->close_delay = new_serial.close_delay * HZ/100;
+    info->closing_wait = new_serial.closing_wait * HZ/100;
 
 check_and_exit:
     if (info->flags & ASYNC_INITIALIZED){
@@ -3806,25 +3962,44 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
             ret_val = set_default_timeout(info, (unsigned long)arg);
             break;
        case CYSETRFLOW:
-           info->rflow = 1;
+           info->rflow = (int)arg;
            ret_val = 0;
            break;
-       case CYRESETRFLOW:
-           info->rflow = 0;
-           ret_val = 0;
+       case CYGETRFLOW:
+           ret_val = info->rflow;
            break;
        case CYSETRTSDTR_INV:
-           info->rtsdtr_inv = 1;
+           info->rtsdtr_inv = (int)arg;
            ret_val = 0;
            break;
-       case CYRESETRTSDTR_INV:
-           info->rtsdtr_inv = 0;
+       case CYGETRTSDTR_INV:
+           ret_val = info->rtsdtr_inv;
+           break;
+       case CYGETCARDINFO:
+            error = verify_area(VERIFY_WRITE, (void *) arg
+                                ,sizeof(struct cyclades_card));
+            if (error){
+                ret_val = error;
+                break;
+            }
+            copy_to_user((void *)arg, (void *)&cy_card[info->card], 
+                        sizeof (struct cyclades_card));
            ret_val = 0;
+            break;
+       case CYGETCD1400VER:
+           ret_val = info->chip_rev;
            break;
        case CYZPOLLCYCLE:
             cyz_polling_cycle = (HZ * arg) / 1000;
            ret_val = 0;
            break;
+       case CYSETWAIT:
+           info->closing_wait2 = (unsigned short)arg;
+           ret_val = 0;
+           break;
+       case CYGETWAIT:
+           ret_val = info->closing_wait2;
+           break;
         case TCSBRK:    /* SVID version: non-zero arg --> no break */
             ret_val = tty_check_change(tty);
             if (ret_val)
@@ -3968,12 +4143,13 @@ cy_throttle(struct tty_struct * tty)
 
 #ifdef SERIAL_DEBUG_THROTTLE
   char buf[64];
-        
-    printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+
+    printk("cyc:throttle %s: %d....ttyC%d\n", 
+          tty_name(tty, buf),
            tty->ldisc.chars_in_buffer(tty), info->line);
 #endif
 
-    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+    if (serial_paranoia_check(info, tty->device, "cy_throttle")){
             return;
     }
 
@@ -4024,17 +4200,21 @@ cy_unthrottle(struct tty_struct * tty)
 #ifdef SERIAL_DEBUG_THROTTLE
   char buf[64];
         
-    printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+    printk("cyc:unthrottle %s: %d....ttyC%d\n", 
+          tty_name(tty, buf),
            tty->ldisc.chars_in_buffer(tty), info->line);
 #endif
 
-    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+    if (serial_paranoia_check(info, tty->device, "cy_unthrottle")){
             return;
     }
 
     if (I_IXOFF(tty)) {
-        info->x_char = START_CHAR(tty);
-        /* Should use the "Send Special Character" feature!!! */
+       if (info->x_char)
+           info->x_char = 0;
+       else
+           info->x_char = START_CHAR(tty);
+            /* Should use the "Send Special Character" feature!!! */
     }
 
     card = info->card;
@@ -4146,6 +4326,49 @@ cy_start(struct tty_struct *tty)
 } /* cy_start */
 
 
+static void
+cy_flush_buffer(struct tty_struct *tty)
+{
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  int card, channel;
+  unsigned long flags;
+                                
+#ifdef SERIAL_DEBUG_IO
+    printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
+#endif
+
+    if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
+        return;
+    save_flags(flags); cli();
+    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+    restore_flags(flags);
+
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
+
+    if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board 
+                                     buffers as well */
+       static volatile struct FIRM_ID *firm_id;
+       static volatile struct ZFW_CTRL *zfw_ctrl;
+       static volatile struct CH_CTRL *ch_ctrl;
+       static volatile struct BUF_CTRL *buf_ctrl;
+
+       firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
+       zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
+                               cy_readl(&firm_id->zfwctrl_addr));
+       ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+       buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+       while (cy_readl(&buf_ctrl->tx_get) != cy_readl(&buf_ctrl->tx_put))
+               cy_writel(&buf_ctrl->tx_put, cy_readl(&buf_ctrl->tx_get));
+    }
+    wake_up_interruptible(&tty->write_wait);
+    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+       && tty->ldisc.write_wakeup)
+           (tty->ldisc.write_wakeup)(tty);
+} /* cy_flush_buffer */
+
+
 /*
  * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
  */
@@ -4160,7 +4383,8 @@ cy_hangup(struct tty_struct *tty)
 
     if (serial_paranoia_check(info, tty->device, "cy_hangup"))
         return;
-    
+
+    cy_flush_buffer(tty);
     shutdown(info);
     info->event = 0;
     info->count = 0;
@@ -4173,28 +4397,6 @@ cy_hangup(struct tty_struct *tty)
 } /* cy_hangup */
 
 
-static void
-cy_flush_buffer(struct tty_struct *tty)
-{
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
-                                
-#ifdef SERIAL_DEBUG_IO
-    printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
-#endif
-
-    if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
-        return;
-    save_flags(flags); cli();
-        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-    restore_flags(flags);
-    wake_up_interruptible(&tty->write_wait);
-    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-    && tty->ldisc.write_wakeup)
-        (tty->ldisc.write_wakeup)(tty);
-} /* cy_flush_buffer */
-
-
 /*
  * ---------------------------------------------------------------------
  * cy_init() and friends
@@ -4265,7 +4467,7 @@ cyy_init_card(volatile ucchar *true_base_addr,int index))
             return chip_number;
         }
         cy_writeb((u_long)base_addr+(CyGCR<<index), CyCH0_SERIAL);
-        if (cy_readb(base_addr+(CyGFRCR<<index)) >= 0x48){
+        if (cy_readb(base_addr+(CyGFRCR<<index)) >= CD1400_REV_J){
            /* It is a CD1400 rev. J or later */
            /* Impossible to reach 5ms with this chip. 
               Changed to 2ms instead (f = 500 Hz). */
@@ -4275,11 +4477,11 @@ cyy_init_card(volatile ucchar *true_base_addr,int index))
            cy_writeb((u_long)base_addr+(CyPPR<<index), CyCLOCK_25_5MS);
        }
 
-        /*
+    /*
         printk(" chip #%d at %#6lx is rev 0x%2x\n",
                chip_number, (unsigned long)base_addr,
-              base_addr[CyGFRCR<<index]);
-        */
+              cy_readb(base_addr+(CyGFRCR<<index)));
+    */
     }
     return chip_number;
 } /* cyy_init_card */
@@ -4308,7 +4510,7 @@ cy_detect_isa(void))
 
                 /* probe for CD1400... */
 
-#if !defined(__alpha__) 
+#if !defined(__alpha__)
                cy_isa_address = ioremap((unsigned int)cy_isa_address,
                                                        CyISA_Ywin);
 #endif
@@ -4390,45 +4592,89 @@ __initfunc(static int
 cy_detect_pci(void))
 {
 #ifdef CONFIG_PCI
-  unsigned char         cyy_rev_id;
+
+#ifdef NEW_PCI
+  struct pci_dev       *pdev = NULL;
+  unsigned char                cyy_rev_id;
+#else
+  unsigned char         cyy_bus, cyy_dev_fn, cyy_rev_id;
+#endif
   unsigned long         pci_intr_ctrl;
   unsigned char         cy_pci_irq;
   uclong                cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
   unsigned short        i,j,cy_pci_nchan;
-  unsigned short        device_id,dev_index = 0,board_index = 0;
+  unsigned short        device_id,dev_index = 0;
+#ifndef NEW_PCI
+  unsigned short       board_index = 0;
+#endif
   uclong               mailbox;
   uclong               Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
-  struct pci_dev       *pdev = NULL;
 
+#ifdef NEW_PCI
         if(pci_present() == 0) {    /* PCI bus not present */
+#else
+        if(pcibios_present() == 0) {    /* PCI bus not present */
+#endif
                 return(0);
         }
         for (i = 0; i < NR_CARDS; i++) {
                 /* look for a Cyclades card by vendor and device id */
                 while((device_id = cy_pci_dev_id[dev_index]) != 0) {
-                       if ((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES, device_id, pdev)) == NULL)
+#ifdef NEW_PCI
+                        if((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES,
+                                        device_id, pdev)) == NULL) {
                                 dev_index++;    /* try next device id */
-                        else {
+                        } else {
+                                break;          /* found a board */
+                        }
+#else
+                        if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
+                                        device_id,board_index,
+                                        &cyy_bus, &cyy_dev_fn) != 0) {
+                                dev_index++;    /* try next device id */
+                                board_index = 0;
+                        } else {
                                 board_index++;
                                 break;          /* found a board */
                         }
+#endif
                 }
 
                if (device_id == 0)
                    break;
 
                 /* read PCI configuration area */
+#ifdef NEW_PCI
                cy_pci_irq = pdev->irq;
                cy_pci_addr0 = pdev->base_address[0];
-               cy_pci_addr1 = pdev->base_address[1];
-               cy_pci_addr2 = pdev->base_address[2];
-               pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
+               cy_pci_addr1 = pdev->base_address[1]; 
+               cy_pci_addr2 = pdev->base_address[2]; 
+                pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
+#else
+                pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+                                 PCI_INTERRUPT_LINE, &cy_pci_irq);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_0, 
+                                 (unsigned int *) &cy_pci_addr0);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_1, 
+                                 (unsigned int *) &cy_pci_addr1);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_2, 
+                                 (unsigned int *) &cy_pci_addr2);
+                pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+                                  PCI_REVISION_ID, &cyy_rev_id);
+#endif
 
     if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
           || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
 #ifdef CY_PCI_DEBUG
             printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+#ifdef NEW_PCI
                pdev->bus->number, pdev->devfn);
+#else
+               cyy_bus, cyy_dev_fn);
+#endif
             printk("rev_id=%d) IRQ%d\n",
                cyy_rev_id, (int)cy_pci_irq);
             printk("Cyclom-Y/PCI:found  winaddr=0x%lx ioaddr=0x%lx\n",
@@ -4440,7 +4686,11 @@ cy_detect_pci(void))
 #if defined(__alpha__)
                 if (device_id  == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
                    printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
-                       pdev->bus->number, pdev->devfn);
+#ifdef NEW_PCI
+                       pdev->bus->number, pdev->devfn);
+#else
+                       cyy_bus, cyy_dev_fn);
+#endif
                    printk("rev_id=%d) IRQ%d\n",
                        cyy_rev_id, (int)cy_pci_irq);
                     printk("Cyclom-Y/PCI:found  winaddr=0x%lx ioaddr=0x%lx\n",
@@ -4525,7 +4775,11 @@ cy_detect_pci(void))
     }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
            /* print message */
                printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+#ifdef NEW_PCI
                    pdev->bus->number, pdev->devfn);
+#else
+                   cyy_bus, cyy_dev_fn);
+#endif
                printk("rev_id=%d) IRQ%d\n",
                    cyy_rev_id, (int)cy_pci_irq);
                printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
@@ -4535,7 +4789,11 @@ cy_detect_pci(void))
     }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
 #ifdef CY_PCI_DEBUG
             printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
-               pdev->bus->number, pdev->devfn);
+#ifdef NEW_PCI
+               pdev->bus->number, pdev->devfn);
+#else
+               cyy_bus, cyy_dev_fn);
+#endif
             printk("rev_id=%d) IRQ%d\n",
                cyy_rev_id, (int)cy_pci_irq);
             printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
@@ -4777,7 +5035,7 @@ show_version(void)
     tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
     rcsdate = strchr(tmp, ' '); rcsdate++;
     tmp = strrchr(rcsdate, ' '); *tmp = '\0';
-    printk("Cyclom driver %s %s\n",
+    printk("Cyclades driver %s %s\n",
         rcsvers, rcsdate);
     printk("        built %s %s\n",
        __DATE__, __TIME__);
@@ -4810,6 +5068,7 @@ cy_init(void))
   int number_z_boards = 0;
   int board,port,i,index;
   unsigned long mailbox;
+  unsigned short chip_number;
   int nports;
 
     show_version();
@@ -4858,9 +5117,9 @@ cy_init(void))
     cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 
     if (tty_register_driver(&cy_serial_driver))
-            panic("Couldn't register Cyclom serial driver\n");
+            panic("Couldn't register Cyclades serial driver\n");
     if (tty_register_driver(&cy_callout_driver))
-            panic("Couldn't register Cyclom callout driver\n");
+            panic("Couldn't register Cyclades callout driver\n");
 
     init_bh(CYCLADES_BH, do_cyclades_bh);
 
@@ -4922,9 +5181,13 @@ cy_init(void))
                     info->type = PORT_STARTECH;
                     info->card = board;
                     info->line = port;
+                   info->chip_rev = 0;
                     info->flags = STD_COM_FLAGS;
                     info->tty = 0;
-                    info->xmit_fifo_size = 0;
+                   if (mailbox == ZO_V1)
+                       info->xmit_fifo_size = CYZ_FIFO_SIZE;
+                   else
+                       info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
                     info->cor1 = 0;
                     info->cor2 = 0;
                     info->cor3 = 0;
@@ -4934,7 +5197,9 @@ cy_init(void))
                     info->tco = 0;
                     info->rbpr = 0;
                     info->rco = 0;
-                    info->close_delay = 0;
+                    info->close_delay = 5*HZ/10;
+                   info->closing_wait = CLOSING_WAIT_DELAY;
+                   info->closing_wait2 = 0;
                     info->x_char = 0;
                     info->event = 0;
                     info->count = 0;
@@ -4952,6 +5217,7 @@ cy_init(void))
                                cy_serial_driver.init_termios;
                     info->open_wait = 0;
                     info->close_wait = 0;
+                    info->shutdown_wait = 0;
                     /* info->session */
                     /* info->pgrp */
                     info->read_status_mask = 0;
@@ -4976,14 +5242,19 @@ cy_init(void))
                     info->line = port;
                     info->flags = STD_COM_FLAGS;
                     info->tty = 0;
-                    info->xmit_fifo_size = 12;
+                    info->xmit_fifo_size = CyMAX_CHAR_FIFO;
                     info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
                     info->cor2 = CyETC;
                     info->cor3 = 0x08; /* _very_ small rcv threshold */
                     info->cor4 = 0;
                     info->cor5 = 0;
-                    info->close_delay = 0;
-                    if (cy_readb(cinfo->base_addr+(CyGFRCR<<index)) >= 0x48) {
+                    info->close_delay = 5*HZ/10;
+                   info->closing_wait = CLOSING_WAIT_DELAY;
+                   info->closing_wait2 = 0;
+                   chip_number = (port - cinfo->first_line) / 4;
+                    if ((info->chip_rev = cy_readb(cinfo->base_addr +
+                                (cy_chip_offset[chip_number]<<index) +
+                                (CyGFRCR<<index))) >= CD1400_REV_J) {
                         /* It is a CD1400 rev. J or later */
                         info->tbpr = baud_bpr_60[13]; /* Tx BPR */
                         info->tco = baud_co_60[13]; /* Tx CO */
@@ -5016,6 +5287,7 @@ cy_init(void))
                               cy_serial_driver.init_termios;
                     info->open_wait = 0;
                     info->close_wait = 0;
+                    info->shutdown_wait = 0;
                     /* info->session */
                     /* info->pgrp */
                     info->read_status_mask =
@@ -5054,21 +5326,19 @@ cleanup_module(void)
     int i;
     unsigned long flags;
 
-
     if (cyz_timeron){
        cyz_timeron = 0;
        del_timer(&cyz_timerlist);
     }
 
-    save_flags(flags);
-    cli();
+    save_flags(flags); cli();
     remove_bh(CYCLADES_BH);
 
     free_page((unsigned long)tmp_buf);
     if (tty_unregister_driver(&cy_callout_driver))
-            printk("Couldn't unregister Cyclom callout driver\n");
+            printk("Couldn't unregister Cyclades callout driver\n");
     if (tty_unregister_driver(&cy_serial_driver))
-            printk("Couldn't unregister Cyclom serial driver\n");
+            printk("Couldn't unregister Cyclades serial driver\n");
 
     restore_flags(flags);
 
index 65262720d12be5573a5dacbf16483f14eaeb3b13..4bcd9748f7bdfb82fe097627406dbdcfcf09c358 100644 (file)
@@ -239,23 +239,32 @@ static void lp_error(int minor)
 }
 
 static int lp_check_status(int minor) {
+       static unsigned char last = 0;
        unsigned char status = r_str(minor);
        if ((status & LP_POUTPA)) {
-               printk(KERN_INFO "lp%d out of paper\n", minor);
-               if (LP_F(minor) & LP_ABORT)
-                       return 1;
-               lp_error(minor);
+               if (last != LP_POUTPA) {
+                       last = LP_POUTPA;
+                       printk(KERN_INFO "lp%d out of paper\n", minor);
+               }
        } else if (!(status & LP_PSELECD)) {
-               printk(KERN_INFO "lp%d off-line\n", minor);
-               if (LP_F(minor) & LP_ABORT)
-                       return 1;
-               lp_error(minor);
+               if (last != LP_PSELECD) {
+                       last = LP_PSELECD;
+                       printk(KERN_INFO "lp%d off-line\n", minor);
+               }
        } else if (!(status & LP_PERRORP)) {
-               printk(KERN_ERR "lp%d printer error\n", minor);
+               if (last != LP_PERRORP) {
+                       last = LP_PERRORP;
+                       printk(KERN_ERR "lp%d on fire!\n", minor);
+               }
+       }
+       else last = 0;
+
+       if (last != 0) {
                if (LP_F(minor) & LP_ABORT)
                        return 1;
                lp_error(minor);
        }
+
        return 0;
 }
 
index bb7e9cf767a18cb0a671fd2e02bb6b13aec63eb4..acd348c92c14b5d0a9390f48b4d551da6d085e56 100644 (file)
@@ -145,12 +145,12 @@ __initfunc(static char *initialize_kbd2(void))
         */
 
         do {
-       kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
+               kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
                 status = kbd_wait_for_input();
                 if (status == KBD_REPLY_ACK)
                        break;
                 else if (status != KBD_REPLY_RESEND)
-               return "Keyboard reset failed, no ACK";
+                       return "Keyboard reset failed, no ACK";
         } while (1);
 
        if (kbd_wait_for_input() != KBD_REPLY_POR)
@@ -164,12 +164,12 @@ __initfunc(static char *initialize_kbd2(void))
         */
 
        do {
-       kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+               kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
                status = kbd_wait_for_input();
                if (status == KBD_REPLY_ACK)
                        break;
                else if (status != KBD_REPLY_RESEND)
-               return "Disable keyboard: no ACK";
+                       return "Disable keyboard: no ACK";
        } while (1);
 
        kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
index 31753dc1a31a38edfc9bb25cd3202b36332be298..9b90bae8b39889d039635294e1a4759befe311d2 100644 (file)
@@ -20,7 +20,7 @@
 
 #ifndef MODULE
 static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
-static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_NONE };
+static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
 static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
 
 extern int parport_pc_init(int *io, int *irq, int *dma);
@@ -30,26 +30,68 @@ static int parport_setup_ptr __initdata = 0;
 
 __initfunc(void parport_setup(char *str, int *ints))
 {
-       if (ints[0] == 0 || ints[1] == 0) {
-               /* Disable parport if "parport=" or "parport=0" in cmdline */
+       if (ints[0] == 0) {
+               if (str && !strncmp(str, "auto", 4)) {
+                       irq[0] = PARPORT_IRQ_AUTO;
+                       dma[0] = PARPORT_DMA_AUTO;
+               }
+               else if (str)
+                       printk (KERN_ERR "parport: `%s': huh?\n", str);
+               else
+                       printk (KERN_ERR "parport: parport=.. what?\n");
+               
+               return;
+       }
+       else if (ints[1] == 0) {
+               /* Disable parport if "parport=0" in cmdline */
                io[0] = PARPORT_DISABLE; 
                return;
        }
+
        if (parport_setup_ptr < PARPORT_MAX) {
+               char *sep;
                io[parport_setup_ptr] = ints[1];
-               if (ints[0]>1) {
+               irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
+               dma[parport_setup_ptr] = PARPORT_DMA_NONE;
+               if (ints[0] > 1) {
                        irq[parport_setup_ptr] = ints[2];
-                       if (ints[0]>2) dma[parport_setup_ptr] = ints[3];
+                       if (ints[0] > 2) {
+                               dma[parport_setup_ptr] = ints[3];
+                               goto done;
+                       }
+
+                       if (str == NULL)
+                               goto done;
+
+                       goto dma_from_str;
                }
-               parport_setup_ptr++;
-       } else {
-               printk(KERN_ERR "parport=0x%x", ints[1]);
-               if (ints[0]>1) {
-                       printk(",%d", ints[2]);
-                       if (ints[0]>2) printk(",%d", ints[3]);
+               else if (str == NULL)
+                       goto done;
+               else if (!strncmp(str, "auto", 4))
+                       irq[parport_setup_ptr] = PARPORT_IRQ_AUTO;
+               else if (strncmp(str, "none", 4) != 0) {
+                       printk(KERN_ERR "parport: bad irq `%s'\n", str);
+                       return;
                }
-               printk(" ignored, too many ports.\n");
-       }
+
+               if ((sep = strchr(str, ',')) == NULL) goto done;
+               str = sep+1;
+       dma_from_str:
+               if (!strncmp(str, "auto", 4))
+                       dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
+               else if (strncmp(str, "none", 4) != 0) {
+                       char *ep;
+                       dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0);
+                       if (ep == str) {
+                               printk(KERN_ERR "parport: bad dma `%s'\n",
+                                      str);
+                               return;
+                       }
+               }
+       done:
+               parport_setup_ptr++;
+       } else
+               printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
 }
 #endif
 
@@ -100,6 +142,7 @@ EXPORT_SYMBOL(parport_wait_peripheral);
 EXPORT_SYMBOL(parport_proc_register);
 EXPORT_SYMBOL(parport_proc_unregister);
 EXPORT_SYMBOL(parport_probe_hook);
+EXPORT_SYMBOL(parport_parse_irqs);
 
 void inc_parport_count(void)
 {
index 5852b775dcf49ab15c19c5085b5370c135957e33..0926262d94afa8a25476ec4373236daa8b4eedee 100644 (file)
@@ -36,7 +36,6 @@
 
 #include <asm/ptrace.h>
 #include <asm/io.h>
-#include <asm/dma.h>
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -276,159 +275,6 @@ struct parport_operations parport_pc_ops =
        parport_pc_dec_use_count
 };
 
-/* --- DMA detection -------------------------------------- */
-
-/*
- * Prepare DMA channels from 0-8 to transmit towards buffer
- */
-static int parport_prepare_dma(char *buff, int size)
-{
-       int tmp = 0;
-       int i,retv;
-       
-       for (i = 0; i < 8; i++) {
-               retv = request_dma(i, "probe");
-               if (retv)
-                       continue;
-               tmp |= 1 << i;
-
-               cli();
-               disable_dma(i);
-               clear_dma_ff(i);
-               set_dma_addr(i, virt_to_bus(buff));
-               set_dma_count(i, size);
-               set_dma_mode(i, DMA_MODE_READ);
-               sti();
-       }
-
-       return tmp;
-}
-
-/*
- * Activate all DMA channels passed in dma
- */
-static int parport_enable_dma(int dma)
-{
-       int i;
-       
-       for (i = 0; i < 8; i++)
-               if (dma & (1 << i)) {
-                       cli();
-                       enable_dma(i);
-                       sti();
-               }
-
-       return dma;
-}
-
-static int parport_detect_dma_transfer(int dma, int size)
-{
-       int i,n,retv;
-       int count=0;
-
-       retv = PARPORT_DMA_NONE;
-       for (i = 0; i < 8; i++)
-               if (dma & (1 << i)) {
-                       disable_dma(i);
-                       clear_dma_ff(i);
-                       n = get_dma_residue(i);
-                       if (n != size) {
-                               retv = i;
-                               if (count > 0) {
-                                       retv = PARPORT_DMA_NONE; /* Multiple DMA's */
-                                       printk(KERN_ERR "parport: multiple DMA detected.  Huh?\n");
-                               }
-                               count++;
-                       }
-                       free_dma(i);
-               }
-
-       return retv;    
-}
-
-/* Only if supports ECP mode */
-static int programmable_dma_support(struct parport *pb)
-{
-       unsigned char dma, oldstate = parport_pc_read_econtrol(pb);
-
-       parport_pc_write_econtrol(pb, 0xe0); /* Configuration MODE */
-       
-       dma = parport_pc_read_configb(pb) & 0x07;
-
-       parport_pc_write_econtrol(pb, oldstate);
-       
-       if (dma == 0 || dma == 4) /* Jumper selection */
-               return PARPORT_DMA_NONE;
-       else
-               return dma;
-}
-
-/* Only called if port supports ECP mode.
- *
- * The only restriction on DMA channels is that it has to be
- * between 0 to 7 (inclusive). Used only in an ECP mode, DMAs are
- * considered a shared resource and hence they should be registered
- * when needed and then immediately unregistered.
- *
- * DMA autoprobes for ECP mode are known not to work for some
- * main board BIOS configs. I had to remove everything from the
- * port, set the mode to SPP, reboot to DOS, set the mode to ECP,
- * and reboot again, then I got IRQ probes and DMA probes to work.
- * [Is the BIOS doing a device detection?]
- *
- * A value of PARPORT_DMA_NONE is allowed indicating no DMA support.
- *
- * if( 0 < DMA < 4 )
- *    1Byte DMA transfer
- * else // 4 < DMA < 8
- *    2Byte DMA transfer
- *
- */
-static int parport_dma_probe(struct parport *pb)
-{
-       int dma,retv;
-       unsigned char dsr,dsr_read;
-       char *buff;
-
-       retv = programmable_dma_support(pb);
-       if (retv != PARPORT_DMA_NONE)
-               return retv;
-       
-       if (!(buff = kmalloc(2048, GFP_KERNEL | GFP_DMA))) {
-           printk(KERN_ERR "parport: memory squeeze\n");
-           return PARPORT_DMA_NONE;
-       }
-       
-       dsr = pb->ops->read_control(pb);
-       dsr_read = (dsr & ~(0x20)) | 0x04;    /* Direction == read */
-
-       pb->ops->write_econtrol(pb, 0xc0);         /* ECP MODE */
-       pb->ops->write_control(pb, dsr_read );
-       dma = parport_prepare_dma(buff, 1000);
-       pb->ops->write_econtrol(pb, 0xd8);         /* ECP FIFO + enable DMA */
-       parport_enable_dma(dma);
-       udelay(500);           /* Give some for DMA tranfer */
-       retv = parport_detect_dma_transfer(dma, 1000);
-       
-       /*
-        * National Semiconductors only supports DMA tranfers
-        * in ECP MODE
-        */
-       if (retv == PARPORT_DMA_NONE) {
-               pb->ops->write_econtrol(pb, 0x60);         /* ECP MODE */
-               pb->ops->write_control(pb, dsr_read );
-               dma=parport_prepare_dma(buff,1000);
-               pb->ops->write_econtrol(pb, 0x68);         /* ECP FIFO + enable DMA */
-               parport_enable_dma(dma);
-               udelay(500);           /* Give some for DMA tranfer */
-               retv = parport_detect_dma_transfer(dma, 1000);
-       }
-       
-       kfree(buff);
-       
-       return retv;
-}
-
 /* --- Mode detection ------------------------------------- */
 
 /*
@@ -807,6 +653,7 @@ out:
 static int probe_one_port(unsigned long int base, int irq, int dma)
 {
        struct parport tmpport, *p;
+       int probedirq = PARPORT_IRQ_NONE;
        if (check_region(base, 3)) return 0;
        tmpport.base = base;
        tmpport.ops = &parport_pc_ops;
@@ -830,12 +677,16 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
        if (p->irq == PARPORT_IRQ_AUTO) {
                p->irq = PARPORT_IRQ_NONE;
                parport_irq_probe(p);
+       } else if (p->irq == PARPORT_IRQ_PROBEONLY) {
+               p->irq = PARPORT_IRQ_NONE;
+               parport_irq_probe(p);
+               probedirq = p->irq;
+               p->irq = PARPORT_IRQ_NONE;
        }
        if (p->irq != PARPORT_IRQ_NONE)
                printk(", irq %d", p->irq);
        if (p->dma == PARPORT_DMA_AUTO)         
-               p->dma = (p->modes & PARPORT_MODE_PCECP)?
-                       parport_dma_probe(p):PARPORT_DMA_NONE;
+               p->dma = PARPORT_DMA_NONE;
        if (p->dma != PARPORT_DMA_NONE)
                printk(", dma %d", p->dma);
        printk(" [");
@@ -851,6 +702,8 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
        }
 #undef printmode
        printk("]\n");
+       if (probedirq != PARPORT_IRQ_NONE) 
+               printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
        parport_proc_register(p);
        p->flags |= PARPORT_FLAG_COMA;
 
@@ -875,9 +728,9 @@ int parport_pc_init(int *io, int *irq, int *dma)
                } while (*io && (++i < PARPORT_PC_MAX_PORTS));
        } else {
                /* Probe all the likely ports. */
-               count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
-               count += probe_one_port(0x378, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
-               count += probe_one_port(0x278, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
+               count += probe_one_port(0x3bc, irq[0], dma[0]);
+               count += probe_one_port(0x378, irq[0], dma[0]);
+               count += probe_one_port(0x278, irq[0], dma[0]);
        }
 
        /* Give any attached devices a chance to gather their thoughts */
@@ -890,15 +743,22 @@ int parport_pc_init(int *io, int *irq, int *dma)
 
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
-static int irq[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_AUTO };
+static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
+static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
+static char *irq = NULL;
 MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
 
 int init_module(void)
 {      
-       return (parport_pc_init(io, irq, dma)?0:1);
+       /* Work out how many ports we have, then get parport_share to parse
+          the irq values. */
+       unsigned int i;
+       for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
+       parport_parse_irqs(i, irq, irqval);
+
+       return (parport_pc_init(io, irqval, dma)?0:1);
 }
 
 void cleanup_module(void)
index dab46ec6585825255a99b91a2daa499bbb0668bd..5c582ef47386a5868ec071c5f8245a4ceeda0018 100644 (file)
@@ -441,3 +441,26 @@ void parport_release(struct pardevice *dev)
                        pd->wakeup(pd->private);
        }
 }
+
+void parport_parse_irqs(int nports, const char *irqstr, int irqval[])
+{
+       unsigned int i;
+       for (i = 0; i < nports && irqstr; i++) {
+               if (!strncmp(irqstr, "auto", 4))
+                       irqval[i] = PARPORT_IRQ_AUTO;
+               else if (!strncmp(irqstr, "none", 4))
+                       irqval[i] = PARPORT_IRQ_NONE;
+               else {
+                       char *ep;
+                       unsigned long r = simple_strtoul(irqstr, &ep, 0);
+                       if (ep != irqstr)
+                               irqval[i] = r;
+                       else {
+                               printk("parport: bad irq specifier `%s'\n", irqstr);
+                               return;
+                       }
+               }
+               irqstr = strchr(irqstr, ',');
+               if (irqstr) irqstr++;
+       }
+}
index 3b19ba4fe0fb8810f01876849168b4e2dca400f5..5bdae66dd4d589f148af3244902b96719f01b476 100644 (file)
@@ -253,6 +253,7 @@ typedef unsigned int  u32;
 #include <linux/time.h>
 #include <linux/blk.h>
 #include <linux/init.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -290,6 +291,7 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host);
 static int NCR53c8xx_script_len;
 static int NCR53c8xx_dsa_len;
 static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
 static int ncr_halt (struct Scsi_Host *host);
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
     *cmd);
@@ -1134,9 +1136,9 @@ NCR53c7x0_init (struct Scsi_Host *host) {
 
     if (!search) {
 #ifdef __powerpc__
-       if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL)) 
+       if (request_irq(host->irq, do_NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL)) 
 #else
-       if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+       if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
 #endif
          {
          
@@ -4390,6 +4392,22 @@ intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
     }
 }
 
+/*
+ * Function : do_NCR53c7x0_intr()
+ *
+ * Purpose : A quick wrapper function added to grab the io_request_lock
+ *      spin lock prior to entering the real interrupt handler.  Needed
+ *      for 2.1.95 and above.
+ */
+static void
+do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs) {
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    NCR53c7x0_intr(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 /*
  * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
  *
index f123c8b2f15eaef5b919aa4f9aaa50e048fe698a..be68e101d3eb12c798323b50b8d53ed21ed243e5 100644 (file)
 #include <linux/ioport.h>
 #include <linux/time.h>
 #include <linux/blk.h>
+#include <asm/spinlock.h>
 
 #ifdef CONFIG_AMIGA
 #include <asm/pgtable.h>
@@ -313,7 +314,8 @@ static int shutdown (struct Scsi_Host *host);
 static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
 static int disable (struct Scsi_Host *host);
 static int NCR53c7xx_run_tests (struct Scsi_Host *host);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
 static int ncr_halt (struct Scsi_Host *host);
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
     *cmd);
@@ -1069,10 +1071,10 @@ NCR53c7x0_init (struct Scsi_Host *host) {
      */
 
 #ifdef CONFIG_MVME16x
-    if (request_irq(IRQ_MVME16x_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
+    if (request_irq(IRQ_MVME16x_SCSI, do_NCR53c7x0_intr, 0, "SCSI-script", NULL))
        panic ("Couldn't get SCSI IRQ");
 #ifdef MVME16x_INTFLY
-    else if (request_irq(IRQ_MVME16x_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
+    else if (request_irq(IRQ_MVME16x_FLY, do_NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
        panic ("Couldn't get INT_FLY IRQ");
 #endif
 #else
@@ -1081,9 +1083,9 @@ NCR53c7x0_init (struct Scsi_Host *host) {
 
     if (!search) {
 #ifdef CONFIG_AMIGA
-       if (request_irq(IRQ_AMIGA_PORTS, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
+       if (request_irq(IRQ_AMIGA_PORTS, do_NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
 #else
-       if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
+       if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
 #endif
            printk("scsi%d : IRQ%d not free, detaching\n"
                   "         You have either a configuration problem, or a\n"
@@ -4068,6 +4070,20 @@ void dump_log(void)
 }
 #endif
 
+/* Function : NCR53c7x0_intr
+ *
+ * Purpose : grab the global io_request_lock spin lock before entering the
+ *      real interrupt routine.
+ */
+static void
+do_NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    NCR53c7x0_intr(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 /*
  * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
  *
@@ -4082,7 +4098,7 @@ void dump_log(void)
  * script interrupt handler will call back to this function.
  */
 
-void 
+static void 
 NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
     NCR53c7x0_local_declare();
     struct Scsi_Host *host;                    /* Host we are looking at */
index b21de77047106c6371c5abed33ad1cc86ae04167..06c60edfbfceae0cff4d05f75f31f85621528c43 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/pci.h>
 #include <linux/string.h>
 #include <linux/blk.h>
+#incldue <asm/spinlock.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -361,6 +362,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd);
 static __inline__ void run_main(void);
 static void AM53C974_main (void);
 static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void AM53C974_intr_disconnect(struct Scsi_Host *instance); 
 static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg);
 static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target);
@@ -716,7 +718,7 @@ for (search = first_host;
                  (search->irq != instance->irq) || (search == instance) );
      search = search->next);
 if (!search) {
-   if (request_irq(instance->irq, AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) {
+   if (request_irq(instance->irq, do_AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) {
       printk("scsi%d: IRQ%d not free, detaching\n", instance->host_no, instance->irq);
       scsi_unregister(instance);
       return 0; } 
@@ -976,6 +978,24 @@ do {
 main_running = 0;
 }
 
+/************************************************************************
+* Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) *
+*                                                                       *
+* Purpose : interrupt handler                                           *
+*                                                                       *
+* Inputs : irq - interrupt line, regs - ?                               *
+*                                                                       *
+* Returns : nothing                                                     *
+************************************************************************/
+static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+unsigned long flags;
+
+spin_lock_irqsave(&io_request_lock, flags);
+AM53C974_intr(irq, dev_id, regs);
+spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 /************************************************************************
 * Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) *
 *                                                                       *
index 207f24c4a7f1608392431e34a856f1143480d48c..1527361d4ce78b25e2fae24f684462b686d1e948 100644 (file)
@@ -24,14 +24,12 @@ dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
 dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
-    bool '   Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
     bool '   Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
     if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
-      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24
     fi
-    bool '   Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
     bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
-    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
 fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
index 557fbe9b7bc8bd857349fa55255b5c56e5e24865..2a339f426b2f9507a5e98d20cf4f385874d8e154 100644 (file)
@@ -1279,6 +1279,9 @@ static void NCR5380_main (void) {
 }
 
 #ifndef DONT_USE_INTR
+#include <linux/blk.h>
+#include <asm/spinlock.h>
+
 /*
  * Function : void NCR5380_intr (int irq)
  * 
@@ -1390,6 +1393,16 @@ static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs) {
            } /* if (instance->irq == irq) */
     } while (!done);
 }
+
+
+static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs) {
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    NCR5380_intr(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 #endif
 
 #ifdef NCR5380_STATS
index 08e2897a6f1a193724954340f02c39e1bca1adc1..d84534dd407461babd0700c4f6a9c210eb71740c 100644 (file)
@@ -286,6 +286,7 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags);
 static void NCR5380_information_transfer (struct Scsi_Host *instance);
 #ifndef DONT_USE_INTR
 static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
 #endif
 static void NCR5380_main (void);
 static void NCR5380_print_options (struct Scsi_Host *instance);
index 8e94585b097e890f9984390ed628f0d6305a0c7f..a133a7d72b79cc785ab378ea146d430099d08338 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/irq.h>
 
 #include <linux/blk.h>
+#include <asm/spinlock.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
@@ -171,6 +172,7 @@ enum Phase {
 
 /* Static function prototypes */
 static  void NCR53c406a_intr(int, void *, struct pt_regs *);
+static  void do_NCR53c406a_intr(int, void *, struct pt_regs *);
 static  void internal_done(Scsi_Cmnd *);
 static  void wait_intr(void);
 static  void chip_init(void);
@@ -539,7 +541,7 @@ NCR53c406a_detect(Scsi_Host_Template * tpnt)){
     request_region(port_base, 0x10, "NCR53c406a");
     
     if(irq_level > 0) {
-        if(request_irq(irq_level, NCR53c406a_intr, 0, "NCR53c406a", NULL)){
+        if(request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", NULL)){
             printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level);
             return 0;
         }
@@ -764,6 +766,15 @@ NCR53c406a_biosparm(Scsi_Disk *disk, kdev_t dev, int* info_array){
     return 0;
   }
      
+     static void
+do_NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    NCR53c406a_intr(0, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
      static void
 NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
     DEB(unsigned char fifo_size;)
index 5ec8a51d2e065d1194adb08789b2a85e36c1cf97..7cbe9fbdc1faa661ab4030056b4f8cb342d43052 100644 (file)
@@ -1,8 +1,7 @@
                            AIC7xxx Driver for Linux
-                                July 20, 1997
 
 Introduction
-------------------------
+----------------------------
 The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
 SCSI controllers and chipsets. Major portions of the driver and driver
 development are shared between both Linux and FreeBSD. Support for the
@@ -11,32 +10,42 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
 2.1.0 or later.
 
   Supported cards/chipsets
-  ------------------------
+  ----------------------------
     Adaptec Cards
-    -----------------------
-    AHA-274x               
-    AHA-2842               
+    ----------------------------
+    AHA-274x
+    AHA-274xT               
+    AHA-2842
+    AHA-2910B               
     AHA-2940               
     AHA-2940W              
     AHA-2940U              
-    AHA-2940UW             
+    AHA-2940UW
+    AHA-2940AU             
     AHA-2944D              
     AHA-2944WD
+    AHA-2944UD
+    AHA-2944UWD
     AHA-3940
+    AHA-3940U
     AHA-3940W
+    AHA-3940UW
     AHA-3985
+    AHA-3985U
     AHA-3985W
+    AHA-3985UW
 
     Motherboard Chipsets
-    -----------------------
+    ----------------------------
     AIC-777x   
     AIC-785x
     AIC-786x
     AIC-787x
     AIC-788x
+    AIC-7895
 
     Bus Types
-    -----------------------
+    ----------------------------
     W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
         SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
     U - Ultra SCSI, transfer rates up to 40MB/s.
@@ -50,23 +59,28 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     AHA-398x - PCI RAID controllers with three separate SCSI controllers
                on-board.
 
-    NOTE: The AHA-2920 is NOT a AIC-7xxx based controller, and is not
+    NOTE: The AHA-2920 is NOT an AIC-7xxx based controller, and is not
           handled by this driver.
 
   People
-  ------------------------
-    Justin T Gibbs  gibbs@freefall.FreeBSD.org     (BSD Driver Author)
-    Dan Eischen     deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
-    Dean Gehnert    deang@teleport.com             (Linux FTP/patch maintainer)
-    Jess Johnson    jester@frenzy.com              (AIC7xxx FAQ author)
-    Doug Ledford    dledford@dialnet.net           (Stress tester/bug squasher)
-
+  ------------------------------
+    Justin T Gibbs  gibbs@plutotech.com
+      (BSD Driver Author)
+    Dan Eischen     deischen@iworks.InterWorks.org
+      (Original Linux Driver Co-maintainer)
+    Dean Gehnert    deang@teleport.com
+      (Original Linux FTP/patch maintainer)
+    Jess Johnson    jester@frenzy.com
+      (AIC7xxx FAQ author)
+    Doug Ledford    dledford@dialnet.net
+      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer)
+    
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
     author of the driver. John has since retired from the project. Thanks
     again for all his work!
-
+    
   Mailing list
-  ------------------------
+  ------------------------------
     There is a mailing list available for users who want to track development
     and converse with other users and developers. This list is for both
     FreeBSD and Linux support of the AIC7xxx chipsets.
@@ -84,20 +98,150 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
 
     Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
     
-  Command line options ("aic7xxx=option[,option...]")
-  ---------------------------------------------------
+  Boot Command line options
+  ------------------------------
     "aic7xxx=no_reset" -  Eliminate the SCSI reset delay during startup.
         Some SCSI devices need some extra time to reset.
-    "aic7xxx=extended" - Force extended translation.
-    "aic7xxx=ultra" - Force Ultra mode
-    "aic7xxx=irq_trigger:[0,1]" - Edge (0) or Level (1) triggered
-        interrupts.  AFAIK, the driver only works with level triggered
-        interrupts.  This only applies to EISA adapters.
-    "aic7xxx=verbose" - Enable more bootup messages.  PLEASE use this
-        if you have problems with the driver.
+    "aic7xxx=reverse_scan" - Have the driver register the SCSI cards in the
+        reverse of the normal order.  This may help those people who have more
+        than one PCI Adaptec controller force the correct controller to be
+        scsi0 under linux so that their boot hard drive is also sda under
+        linux
+    "aic7xxx=extended" - Force the driver to detect extended drive translation
+        on your controller.  This helps those people who have cards without
+        a SEEPROM make sure that linux and all other operating systems think
+        the same way about your hard drives.
+    "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
+        to use the correct IRQ type for your card.  This only applies to EISA
+        based controllers.  On these controllers, 0 is for Edge triggered
+        interrupts, and 1 is for Level triggered interrupts.  If you aren't
+        sure or don't know which IRQ trigger type your EISA card uses, then
+        let the kernel autodetect the trigger type.
+    "aic7xxx=verbose" - This option can be used in one of two ways.  If you
+        simply specify aic7xxx=verbose, then the kernel will automatically pick
+        the default set of verbose messages for you to see.  Alternatively, you
+        can specify the command as "aic7xxx=verbose:0xXXXX" where the X entries
+        are replaced with hexadecimal digits.  This option is a bit field type
+        option.  For a full listing of the available options, search for the
+        #define VERBOSE_xxxxxx lines in the aic7xxx.c file.  If you want verbose
+        messages, then it is recommended that you simply use the aic7xxx=verbose
+        variant of this command.
+    "aic7xxx=7895_irq_hack:x" - This option enables some work around code to
+        fix a bug in the Tyan Thunder II motherboard BIOS.  The BIOS
+        incorrectly sets the IRQs on the two channels of the 7895 to two
+        different values even though the motherboard hardware doesn't support
+        this mode of operation.  The valid values for x are: 0 to force
+        both channels to use the IRQ assigned to Channel A, 1 to force both
+        channels to use the IRQ assigned to Channel B, and -1 will disable
+        this horrible abomination of a hack.  The default is disabled (-1).
+    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to enable
+        tagged queueing on specific devices.  As of driver version 5.0.6, we
+        now globally enable tagged queueing by default, but we also disable
+        tagged queueing on all individual devices by default.  In order to
+        enable tagged queueing for certian devices at boot time, a user may
+        use this boot param.  The driver will then parse this message out
+        and enable the specific device entries that are present based upon
+        the value given.  The param line is parsed in the following manner:
+
+          { - first instance indicates the start of this parameter values
+              second instance is the start of entries for a particular
+              device entry
+          } - end the entries for a particular host adapter, or end the entire
+              set of parameter entries
+          , - move to next entry.  Inside of a set of device entries, this
+              moves us to the next device on the list.  Outside of device
+              entries, this moves us to the next host adapter
+          . - Same effect as , but is safe to use with insmod.
+          x - the number to enter into the array at this position.  
+              0 = Enable tagged queueing on this device and use the default
+                  queue depth
+              1-254 = Enable tagged queueing on this device and use this
+                      number as the queue depth
+              255 = Disable tagged queueing on this device.
+              Note: anything above 32 for an actual queue depth is wasteful
+                    and not recommended.
+
+        A few examples of how this can be used:
+
+        tag_info:{{8,12,,0,,255,4}}
+          This line will only effect the first aic7xxx card registered.  It
+          will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+          at the default, set id 3 to tagged queueing enabled and use the
+          default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+          Any not specified entries stay at the default value, repeated
+          commas with no value specified will simply increment to the next id
+          without changing anything for the missing values.
+
+        tag_info:{{8,8},,{8,8}}
+          First adapter, scsi id 0 to 8, id 1 to 8, remainder stay at their
+          default.  Second adapter stays entirely at default.  Third
+          adapter, id 0 to 8, id 1 to 8, remainder at default (identical to
+          first adapter).
+
+        tag_info:{,,,{,,,64}}
+          First, second, and third adapters at default values.  Fourth
+          adapter, id 3 to 64.  Notice that leading commas simply increment
+          what the first number effects, and there are no need for trailing
+          commas.  When you close out an adapter, or the entire entry,
+          anything not explicitly set stays at the default value.
+
+        A final note on this option.  The scanner I used for this isn't
+        perfect or highly robust.  If you mess the line up, the worst that
+        should happen is that the line will get ignored.  If you don't
+        close out the entire entry with the final bracket, then any other
+        aic7xxx options after this will get ignored.  So, in general, be
+        sure of what you are entering, and after you have it right, just
+        add it to the lilo.conf file so there won't be any mistakes.  As
+        a means of checking this parser, the entire tag_info array for
+        each card is now printed out in the /proc/scsi/aic7xxx/x file.  You
+        can use that to verify that your options were parsed correctly. 
+        
+    Boot command line options may be combined to form the proper set of options
+    a user might need.  For example, the following is valid:
+    
+    aic7xxx=verbose,extended,irq_trigger:1
+    
+    The only requirement is that individual options be separated by a comma on
+    the command line.
+        
+  Module Loading command options
+  ------------------------------
+    When loading the aic7xxx driver as a module, the exact same options are
+    available to the user.  However, the syntax to specify the options changes
+    slightly.  For insmod, you need to wrap the aic7xxx= argument in quotes
+    and replace all ',' with '.'.  So, for example, a valid insmod line
+    would be:
+
+    insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+    This line should result in the *exact* same behaviour as if you typed
+    it in at the lilo prompt and the driver was compiled into the kernel
+    instead of being a module.  The reason for the single quote is so that
+    the shell won't try to interpret anything in the line, such as {. 
+    Insmod assumes any options starting with a letter instead of a number
+    is a character string (which is what we want) and by switching all of
+    the commas to periods, insmod won't interpret this as more than one
+    string and write junk into our binary image.  I consider it a bug in
+    the insmod program that even if you wrap your string in quotes (quotes
+    that pass the shell mind you and that insmod sees) it still treates
+    a comma inside of those quotes as starting a new variable, resulting
+    in memory scribbles if you don't switch the commas to periods.
+
+
+  Kernel Compile options
+  ------------------------------
+    The various kernel compile time options for this driver are now fairly
+    well documented in the file Documentation/Configure.help.  In order to
+    see this documentation, you need to use one of the advanced configuration
+    programs (menuconfig and xconfig).  If you are using the "make menuconfig"
+    method of configuring your kernel, then you would simply highlight the
+    option in question and hit the F1 key.  If you are using the "make xconfig"
+    method of configuring your kernel, then simply click on the help button next
+    to the option you have questions about.  The help information from the
+    Configure.help file will then get automatically displayed.
 
   /proc support
-  ------------------------
+  ------------------------------
     The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
     directory. That directory contains a file for each SCSI controller in
     the system. Each file presents the current configuration and transfer
@@ -107,45 +251,19 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     Matthew Jacob for statistics support.
 
   FTP sites
-  ------------------------
-    ftp://ftp.teleport.com/users/deang/Linux/aic7xxx/
-      - Main Linux AIC7xxx driver release/pre-release site
-      - Experimental/development patches and bootdisks
+  ------------------------------
     ftp://ftp.dialnet.net/pub/linux/aic7xxx/
+      - Primary site for Doug Ledford developed driver releases
       - US Linux mirror of Teleport site
+    ftp://ftp.pcnet.com/users/eischen/Linux/
+      - Dan Eischen's driver distribution area
     ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
       - European Linux mirror of Teleport site
-    ftp://ftp.pcnet.com/users/eischen/Linux/
-      - Daniel Eischens experimental/development ftp site that is
-        also home of the Linux aic7xxx sequencer assembler source.
-
-  Sequencer assembler
-  ------------------------
-    The sequencer assembler is no longer being distributed with the
-    Linux kernel.  The sequencer assembler (aic7xxx_asm) is now being
-    maintained by Justin Gibbs under a BSD copyright (which pretty
-    much lets you do anything you want with it).  I keep a Linux
-    version of the assembler at my ftp site should you wish to hack
-    the sequencer code (ftp://ftp.pcnet.com/users/eischen/Linux/).
-    Please note that you do NOT need the assembler to build a kernel
-    with aic7xxx support.  The assembler generates the code that is
-    downloaded to the aic7xxx controllers; this code IS part of the
-    Linux kernel (aic7xxx_seq.h and aic7xxx_reg.h).
-
-  Problems compiling the kernel with aic7xxx support
-  --------------------------------------------------
-    This is probably due to having modified the sequencer files in
-    some way.  If you are not modifying the sequencer source (in
-    drivers/scsi/aic7xxx/aic7xxx.seq), then you can just re-extract
-    the necessary files from your kernel tarball.  Otherwise, visit
-    my anonymous ftp site (ftp.pcnet.com) and grab the sequencer
-    assembler source.
 
 
 Dean W. Gehnert
 deang@teleport.com
 
-(Modified by D. Eischen, 7/20/97)
-
-$Revision: 3.1a $
+$Revision: 3.0 $
 
+Modified by Doug Ledford 1998
index fedb3ed66da1e69c5fd0faeec194e01e49b9f68d..eb440ca6d476a481ab65dfc80f05a3424b89a719 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -35,7 +36,6 @@ static void a2091_intr (int irq, void *dummy, struct pt_regs *fp)
 {
     unsigned int status;
     struct Scsi_Host *instance;
-
     for (instance = first_instance; instance &&
         instance->hostt == a2091_template; instance = instance->next)
     {
@@ -54,6 +54,15 @@ static void a2091_intr (int irq, void *dummy, struct pt_regs *fp)
     }
 }
 
+static void do_a2091_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    a2091_intr(irq, dummy, fp);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
 {
     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
@@ -220,7 +229,7 @@ __initfunc(int a2091_detect(Scsi_Host_Template *tpnt))
        if (num_a2091++ == 0) {
            first_instance = instance;
            a2091_template = instance->hostt;
-           request_irq(IRQ_AMIGA_PORTS, a2091_intr, 0, "A2091 SCSI", a2091_intr);
+           request_irq(IRQ_AMIGA_PORTS, do_a2091_intr, 0, "A2091 SCSI", a2091_intr);
        }
        DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
        zorro_config_board(key, 0);
index fdc7fd41d229b5a1984218be16adea41417af8fb..099d33704aa2153d73f7d0de0f6bc561b721e636 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -35,7 +36,6 @@ static void a3000_intr (int irq, void *dummy, struct pt_regs *fp)
 
     if (!(status & ISTR_INT_P))
        return;
-
     if (status & ISTR_INTS)
     {
        /* disable PORTS interrupt */
@@ -48,6 +48,14 @@ static void a3000_intr (int irq, void *dummy, struct pt_regs *fp)
     }
 }
 
+static void do_a3000_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    a3000_intr(irq, dummy, fp);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
 static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
 {
     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
@@ -186,7 +194,7 @@ __initfunc(int a3000_detect(Scsi_Host_Template *tpnt))
     DMA(a3000_host)->DAWR = DAWR_A3000;
     wd33c93_init(a3000_host, (wd33c93_regs *)&(DMA(a3000_host)->SASR),
                 dma_setup, dma_stop, WD33C93_FS_12_15);
-    request_irq(IRQ_AMIGA_PORTS, a3000_intr, 0, "A3000 SCSI", a3000_intr);
+    request_irq(IRQ_AMIGA_PORTS, do_a3000_intr, 0, "A3000 SCSI", a3000_intr);
     DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
     called = 1;
 
index 315de3935946236737dce63564ad763fe4ceaf07..37af86d358fe9c9e03f4c121e682dd9e1aa03eaf 100644 (file)
 #include <linux/blk.h>
 #include <linux/stat.h>
 #endif /* version >= v1.3.0 */
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
@@ -4880,10 +4883,14 @@ advansys_detect(Scsi_Host_Template *tpnt)
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
             if ((ret = request_irq(shp->irq, advansys_interrupt,
                             SA_INTERRUPT, "advansys")) != 0)
-#else /* version >= v1.3.70 */
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95)
             if ((ret = request_irq(shp->irq, advansys_interrupt,
                             SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
                             "advansys", boardp)) != 0)
+#else /* version >= 2.1.95 */
+            if ((ret = request_irq(shp->irq, do_advansys_interrupt,
+                            SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
+                            "advansys", boardp)) != 0)
 #endif /* version >= v1.3.70 */
             {
                 ASC_PRINT2(
@@ -6205,6 +6212,18 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     return;
 }
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
+static void
+do_advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    advansys_interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+#endif
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 /*
  * Set the number of commands to queue per device for the
index c291a95e66f5c5c466791eaf898064db1acbb7fc..c0003a18d3ca95b9b9a778fe1c2f5939b93772ac 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -129,6 +130,8 @@ static struct Scsi_Host * aha_host[7] = {NULL,};  /* One for each IRQ level (9-1
 
 static void setup_mailboxes(int base_io, struct Scsi_Host * shpnt);
 static int aha1542_restart(struct Scsi_Host * shost);
+static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
+static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
 
 #define aha1542_intr_reset(base)  outb(IRST, CONTROL(base))
 
@@ -363,6 +366,16 @@ static int aha1542_test_port(int bse, struct Scsi_Host * shpnt)
     return 0;                                  /* 0 = not ok */
 }
 
+/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
+static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    aha1542_intr_handle(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 /* A "high" level interrupt handler */
 static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -1013,7 +1026,7 @@ int aha1542_detect(Scsi_Host_Template * tpnt)
                    DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
                    save_flags(flags);
                    cli();
-                   if (request_irq(irq_level,aha1542_intr_handle, 0, "aha1542", NULL)) {
+                   if (request_irq(irq_level,do_aha1542_intr_handle, 0, "aha1542", NULL)) {
                            printk("Unable to allocate IRQ for adaptec controller.\n");
                            restore_flags(flags);
                            goto unregister;
index 5c6cbcd1f974c4793dc8b17a7b79e2dadde67c20..09eb26bd57ef8bf6b90bce40112800cc799cc093 100644 (file)
@@ -38,7 +38,7 @@
  *  Parts of this driver were also based on the FreeBSD driver by
  *  Justin T. Gibbs.  His copyright follows:
  *
- * --------------------------------------------------------------------------
+ * --------------------------------------------------------------------------  
  * Copyright (c) 1994-1997 Justin Gibbs.
  * All rights reserved.
  *
  *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
  *-M*************************************************************************/
 
+/*+M**************************************************************************
+ *
+ * Further driver modifications made by Doug Ledford <dledford@dialnet.net>
+ *
+ * Copyright (c) 1997-1998 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs.  Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ *  1: Import of the latest FreeBSD sequencer code for this driver
+ *  2: Modification of kernel code to accomodate different sequencer semantics
+ *  3: Extensive changes throughout kernel portion of driver to improve
+ *     abort/reset processing and error hanndling
+ *  4: Other work contributed by various people on the Internet
+ *  5: Changes to printk information and verbosity selection code
+ *  6: General reliability related changes, especially in IRQ management
+ *  7: Modifications to the default probe/attach order for supported cards
+ *  8: SMP friendliness has been improved
+ *
+ * Overall, this driver represents a significant departure from the official
+ * aic7xxx driver released by Dan Eischen in two ways.  First, in the code
+ * itself.  A diff between the two version of the driver is now a several
+ * thousand line diff.  Second, in approach to solving the same problem.  The
+ * problem is importing the FreeBSD aic7xxx driver code to linux can be a
+ * difficult and time consuming process, that also can be error prone.  Dan
+ * Eischen's official driver uses the approach that the linux and FreeBSD
+ * drivers should be as identical as possible.  To that end, his next version
+ * of this driver will be using a mid-layer code library that he is developing
+ * to moderate communications between the linux mid-level SCSI code and the
+ * low level FreeBSD driver.  He intends to be able to essentially drop the
+ * FreeBSD driver into the linux kernel with only a few minor tweaks to some
+ * include files and the like and get things working, making for fast easy
+ * imports of the FreeBSD code into linux.
+ *
+ * I disagree with Dan's approach.  Not that I don't think his way of doing
+ * things would be nice, easy to maintain, and create a more uniform driver
+ * between FreeBSD and Linux.  I have no objection to those issues.  My
+ * disagreement is on the needed functionality.  There simply are certain
+ * things that are done differently in FreeBSD than linux that will cause
+ * problems for this driver regardless of any middle ware Dan implements.
+ * The biggest example of this at the moment is interrupt semantics.  Linux
+ * doesn't provide the same protection techniques as FreeBSD does, nor can
+ * they be easily implemented in any middle ware code since they would truly
+ * belong in the kernel proper and would effect all drivers.  For the time
+ * being, I see issues such as these as major stumbling blocks to the 
+ * reliability of code based upon such middle ware.  Therefore, I choose to
+ * use a different approach to importing the FreeBSD code that doesn't
+ * involve any middle ware type code.  My approach is to import the sequencer
+ * code from FreeBSD wholesale.  Then, to only make changes in the kernel
+ * portion of the driver as they are needed for the new sequencer semantics.
+ * In this way, the portion of the driver that speaks to the rest of the
+ * linux kernel is fairly static and can be changed/modified to solve
+ * any problems one might encounter without concern for the FreeBSD driver.
+ *
+ * Note: If time and experience should prove me wrong that the middle ware
+ * code Dan writes is reliable in its operation, then I'll retract my above
+ * statements.  But, for those that don't know, I'm from Missouri (in the US)
+ * and our state motto is "The Show-Me State".  Well, before I will put
+ * faith into it, you'll have to show me that it works :)
+ *
+ *_M*************************************************************************/
+
 #ifdef MODULE
 #include <linux/module.h>
 #endif
 #include <stdarg.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
+#include <linux/tqueue.h>
+#include <linux/tasks.h>
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
 #include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
 #include "aic7xxx_seq.h"
+
 #include <linux/stat.h>
-#include <linux/malloc.h>      /* for kmalloc() */
+#include <linux/malloc.h>        /* for kmalloc() */
 
-#include <linux/config.h>      /* for CONFIG_PCI */
+#include <linux/config.h>        /* for CONFIG_PCI */
 
 /*
  * To generate the correct addresses for the controller to issue
@@ -138,13 +209,13 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 4.1 $"
+#define AIC7XXX_C_VERSION  "5.0.12"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
 #define ALL_TARGETS -1
-#define ALL_CHANNELS '\0'
+#define ALL_CHANNELS -1
 #define ALL_LUNS -1
 #define MAX_TARGETS  16
 #define MAX_LUNS     8
@@ -155,75 +226,72 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
 #  define FALSE 0
 #endif
 
+#ifndef KERNEL_VERSION
+#  define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
 /*
- * Defines for PCI bus support, testing twin bus support, DMAing of
- * SCBs, tagged queueing, commands (SCBs) per lun, and SCSI bus reset
- * delay time.
- *
- *   o PCI bus support - this has been implemented and working since
- *     the December 1, 1994 release of this driver. If you don't have
- *     a PCI bus, then you can configure your kernel without PCI
- *     support because all PCI dependent code is bracketed with
- *     "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
- *
- *   o Twin bus support - this has been tested and does work.  It is
- *     not an option anymore.
- *
- *   o Tagged queueing - this driver is capable of tagged queueing
- *     but I am unsure as to how well the higher level driver implements
- *     tagged queueing. Therefore, the maximum commands per lun is
- *     set to 2. If you want to implement tagged queueing, ensure
- *     this define is not commented out.
- *
- *   o Commands per lun - If tagged queueing is enabled, then you
- *     may want to try increasing AIC7XXX_CMDS_PER_LUN to more
- *     than 2.  By default, we limit the SCBs per LUN to 2 with
- *     or without tagged queueing enabled.  If tagged queueing is
- *     disabled, the sequencer will keep the 2nd SCB in the input
- *     queue until the first one completes - so it is OK to to have
- *     more than 1 SCB queued.  If tagged queueing is enabled, then
- *     the sequencer will attempt to send the 2nd SCB to the device
- *     while the first SCB is executing and the device is disconnected.
- *     For adapters limited to 4 SCBs, you may want to actually
- *     decrease the commands per LUN to 1, if you often have more
- *     than 2 devices active at the same time.  This will allocate
- *     1 SCB for each device and ensure that there will always be
- *     a free SCB for up to 4 devices active at the same time.
- *     When SCB paging is enabled, set the commands per LUN to 8
- *     or higher (see SCB paging support below).  Note that if
- *     AIC7XXX_CMDS_PER_LUN is not defined and tagged queueing is
- *     enabled, the driver will attempt to set the commands per
- *     LUN using its own heuristic based on the number of available
- *     SCBs.
- *
- *   o 3985 support - The 3985 adapter is much like the 3940, but has
- *     three 7870 controllers as opposed to two for the 3940.  It will
- *     be probed and recognized as three different adapters, but all
- *     three controllers can share the same external bank of 255 SCBs.
- *     If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
- *     to use and share the common bank of SCBs between the three
- *     controllers of the 3985.  This is experimental and hasn't been
- *     been tested.  By default, we do not use external SCB RAM, and
- *     force the controllers to use their own internal bank of 16 SCBs.
- *     Please let us know if using the external SCB array works.
- *
- *   o SCB paging support - SCB paging is enabled by defining
- *     AIC7XXX_PAGE_ENABLE.  Support for this was taken from the
- *     FreeBSD driver (by Justin Gibbs) and allows for up to 255
- *     active SCBs.  This will increase performance when tagged
- *     queueing is enabled.  Note that you should increase the
- *     AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices
- *     allow at least this many.
- *
- *  Note that sharing of IRQs is not an option any longer.  Linux supports
- *  it so we support it.
- *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
+ * We need the bios32.h file if we are kernel version 2.1.92 or less.  The
+ * full set of pci_* changes wasn't in place until 2.1.93
  */
 
-/* Uncomment this for tagged queueing. */
-#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
-#define AIC7XXX_TAGGED_QUEUEING
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
+#  if defined(__sparc_v9__) || defined(__powerpc__)
+#    error "PPC and Sparc platforms are only support under 2.1.x and above"
+#  endif
+#  include <linux/bios32.h>
+#endif
+
+#if !defined(__alpha__)
+#  define MMAPIO
+#endif
+
+#if defined(__powerpc__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("eieio" ::: "memory")
+#elif defined(__i386__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("lock ; addl $0,0(%%esp)": : :"memory")
+#elif defined(__alpha__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("mb": : :"memory")
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+#  include <asm/spinlock.h>
+#  include <linux/smp.h>
+#  define cpuid smp_processor_id()
+#  define DRIVER_LOCK_INIT \
+     spin_lock_init(&p->spin_lock);
+#  define DRIVER_LOCK \
+       if(!p->cpu_lock_count[cpuid]) { \
+         spin_lock_irqsave(&p->spin_lock, cpu_flags); \
+         p->cpu_lock_count[cpuid]++; \
+       } else { \
+         p->cpu_lock_count[cpuid]++; \
+       }
+#  define DRIVER_UNLOCK \
+     if(--p->cpu_lock_count[cpuid] == 0) \
+       spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
+#else
+#  define cpuid 0
+#  define DRIVER_LOCK_INIT
+#  define DRIVER_LOCK \
+       save_flags(cpu_flags); \
+       cli();
+#  define DRIVER_UNLOCK \
+       restore_flags(cpu_flags);
+#  define le32_to_cpu(x) (x)
+#  define cpu_to_le32(x) (x)
 #endif
 
 /*
@@ -238,7 +306,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
 #ifdef CONFIG_AIC7XXX_RESET_DELAY
 #define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
 #else
-#define AIC7XXX_RESET_DELAY 15
+#define AIC7XXX_RESET_DELAY 5
 #endif
 
 /*
@@ -252,32 +320,18 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
 #endif
 
 /*
- * Enable SCB paging.
- */
-#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
-#define AIC7XXX_PAGE_ENABLE
-#endif
-
-/*
- * Uncomment the following to enable use of the external bank
- * of 255 SCBs.  For 3985 adapters, this will also enable sharing
- * of the SCB array across all three controllers.
- */
-#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
-#define AIC7XXX_USE_EXT_SCBRAM
-#endif
-
-/*
- * For debugging the abort/reset code.
- */
-#define AIC7XXX_DEBUG_ABORT
-
-/*
- * For general debug messages
- */
-#define AIC7XXX_DEBUG
-
-/*
+ * NOTE: Uncommenting the define below no longer has any effect, the
+ *       tagged queue value array is always active now.  I've added
+ *       a setup option to set this particular array and I'm hoping
+ *       insmod will be smart enough to set it properly as well.  It's
+ *       by use of this array that a person can disable tagged queueing.
+ *       The DEFAULT_TAG_COMMANDS define has been changed to disable
+ *       tagged queueing by default, so if your devices can handle tagged
+ *       queueing you will need to add a line to their lilo.conf file like:
+ *       append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
+ *       which will result in the first four devices on the first two
+ *       controllers being set to a tagged queue depth of 32.
+ *
  * Set this for defining the number of tagged commands on a device
  * by device, and controller by controller basis.  The first set
  * of tagged commands will be used for the first detected aic7xxx
@@ -292,37 +346,36 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  * 
  * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
  * own algorithm to determine the commands/LUN.  If SCB paging is
- * enabled, the commands/LUN is 8.  When SCB paging is not enabled,
- * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
- * and 4 commands/LUN for adapters with 3 or 4 SCBs.
- *
+ * enabled, which is always now, the default is 8 commands per lun
+ * that indicates it supports tagged queueing.  All non-tagged devices
+ * use an internal queue depth of 3, with no more than one of those
+ * three commands active at one time.
  */
 /* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
 
-#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
 typedef struct
 {
-  unsigned char tag_commands[16];   /* Allow for wide/twin channel adapters. */
+  unsigned char tag_commands[16];   /* Allow for wide/twin adapters. */
 } adapter_tag_info_t;
 
 /*
- * Make a define that will tell the driver to use it's own algorithm
- * for determining commands/LUN (see Determining commands per LUN
- * above).
+ * Make a define that will tell the driver not to use tagged queueing
+ * by default.
  */
-#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
+                              255, 255, 255, 255, 255, 255, 255, 255}
 
 /*
  * Modify this as you see fit for your system.  By setting tag_commands
  * to 0, the driver will use it's own algorithm for determining the
- * number of commands to use (see above).  When -1, the driver will
+ * number of commands to use (see above).  When 255, the driver will
  * not enable tagged queueing for that particular device.  When positive
- * (> 0) the values in the array are used for the queue_depth.  Note
- * that the maximum value for an entry is 127.
+ * (> 0) and (< 255) the values in the array are used for the queue_depth.
+ * Note that the maximum value for an entry is 254, but you're insane if
+ * you try to use that many commands on one device.
  *
- * In this example, the first line will enable tagged queueing for all
- * the devices on the first probed aic7xxx adapter and tells the driver
- * to use it's own algorithm for determining commands/LUN.
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
  *
  * The second line enables tagged queueing with 4 commands/LUN for IDs
  * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
@@ -335,107 +388,42 @@ typedef struct
  * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
  * IDs 2, 5-7, and 9-15.
  */
+
+/*
 adapter_tag_info_t aic7xxx_tag_info[] =
 {
   {DEFAULT_TAG_COMMANDS},
-  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4}},
+  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
   {DEFAULT_TAG_COMMANDS},
-  {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+  {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
 };
-#endif
-
-/*
- * Don't define this unless you have problems with the driver
- * interrupt handler.  The old method would register the drivers
- * interrupt handler as a "fast" type interrupt handler that would
- * lock out other interrupts.  Since this driver can spend a lot
- * of time in the interrupt handler, this is _not_ a good idea.
- * It also conflicts with some of the more common ethernet drivers
- * that don't use fast interrupts.  Currently, Linux does not allow
- * IRQ sharing unless both drivers can agree on the type of interrupt
- * handler.
- */
-/* #define AIC7XXX_OLD_ISR_TYPE */
-
-
-/*
- * Controller type and options
- */
-typedef enum {
-  AIC_NONE,
-  AIC_7770,    /* EISA aic7770 on motherboard */
-  AIC_7771,    /* EISA aic7771 on 274x */
-  AIC_284x,    /* VLB  aic7770 on 284x, BIOS disabled */
-  AIC_7850,    /* PCI  aic7850 */
-  AIC_7855,    /* PCI  aic7855 */
-  AIC_7860,    /* PCI  aic7860 (7850 Ultra) */
-  AIC_7861,     /* PCI  aic7861 on 2940AU */
-  AIC_7870,    /* PCI  aic7870 on motherboard */
-  AIC_7871,    /* PCI  aic7871 on 294x */
-  AIC_7872,    /* PCI  aic7872 on 3940 */
-  AIC_7873,    /* PCI  aic7873 on 3985 */
-  AIC_7874,    /* PCI  aic7874 on 294x Differential */
-  AIC_7880,    /* PCI  aic7880 on motherboard */
-  AIC_7881,    /* PCI  aic7881 on 294x Ultra */
-  AIC_7882,    /* PCI  aic7882 on 3940 Ultra */
-  AIC_7883,    /* PCI  aic7883 on 3985 Ultra */
-  AIC_7884     /* PCI  aic7884 on 294x Ultra Differential */
-} aha_chip_type;
-
-typedef enum {
-  AIC_777x,    /* AIC-7770 based */
-  AIC_785x,    /* AIC-7850 based (3 SCBs)*/
-  AIC_786x,    /* AIC-7860 based (7850 ultra) */
-  AIC_787x,    /* AIC-7870 based */
-  AIC_788x     /* AIC-7880 based (ultra) */
-} aha_chip_class_type;
-
-typedef enum {
-  AIC_SINGLE,  /* Single Channel */
-  AIC_TWIN,    /* Twin Channel */
-  AIC_WIDE     /* Wide Channel */
-} aha_bus_type;
-
-typedef enum {
-  AIC_UNKNOWN,
-  AIC_ENABLED,
-  AIC_DISABLED
-} aha_status_type;
-
-typedef enum {
-  LIST_HEAD,
-  LIST_SECOND
-} insert_type;
-
-typedef enum {
-  ABORT_RESET_INACTIVE,
-  ABORT_RESET_PENDING,
-  ABORT_RESET_SUCCESS
-} aha_abort_reset_type;
+*/
 
 /*
  * Define an array of board names that can be indexed by aha_type.
  * Don't forget to change this when changing the types!
  */
 static const char *board_names[] = {
-  "AIC-7xxx Unknown",                                  /* AIC_NONE */
-  "Adaptec AIC-7770 SCSI host adapter",                        /* AIC_7770 */
-  "Adaptec AHA-274X SCSI host adapter",                        /* AIC_7771 */
-  "Adaptec AHA-284X SCSI host adapter",                        /* AIC_284x */
-  "Adaptec AIC-7850 SCSI host adapter",                        /* AIC_7850 */
-  "Adaptec AIC-7855 SCSI host adapter",                        /* AIC_7855 */
-  "Adaptec AIC-7860 Ultra SCSI host adapter",          /* AIC_7860 */
-  "Adaptec AHA-2940A Ultra SCSI host adapter",         /* AIC_7861 */
-  "Adaptec AIC-7870 SCSI host adapter",                        /* AIC_7870 */
-  "Adaptec AHA-294X SCSI host adapter",                        /* AIC_7871 */
-  "Adaptec AHA-394X SCSI host adapter",                        /* AIC_7872 */
-  "Adaptec AHA-398X SCSI host adapter",                        /* AIC_7873 */
-  "Adaptec AHA-2944 SCSI host adapter",                        /* AIC_7874 */
-  "Adaptec AIC-7880 Ultra SCSI host adapter",          /* AIC_7880 */
-  "Adaptec AHA-294X Ultra SCSI host adapter",          /* AIC_7881 */
-  "Adaptec AHA-394X Ultra SCSI host adapter",          /* AIC_7882 */
-  "Adaptec AHA-398X Ultra SCSI host adapter",          /* AIC_7883 */
-  "Adaptec AHA-2944 Ultra SCSI host adapter"           /* AIC_7884 */
+  "AIC-7xxx Unknown",                                   /* AIC_NONE */
+  "Adaptec AIC-7810 Hardware RAID Controller",          /* AIC_7810 */
+  "Adaptec AIC-7770 SCSI host adapter",                 /* AIC_7770 */
+  "Adaptec AHA-274X SCSI host adapter",                 /* AIC_7771 */
+  "Adaptec AHA-284X SCSI host adapter",                 /* AIC_284x */
+  "Adaptec AIC-7850 SCSI host adapter",                 /* AIC_7850 */
+  "Adaptec AIC-7855 SCSI host adapter",                 /* AIC_7855 */
+  "Adaptec AIC-7860 Ultra SCSI host adapter",           /* AIC_7860 */
+  "Adaptec AHA-2940A Ultra SCSI host adapter",          /* AIC_7861 */
+  "Adaptec AIC-7870 SCSI host adapter",                 /* AIC_7870 */
+  "Adaptec AHA-294X SCSI host adapter",                 /* AIC_7871 */
+  "Adaptec AHA-394X SCSI host adapter",                 /* AIC_7872 */
+  "Adaptec AHA-398X SCSI host adapter",                 /* AIC_7873 */
+  "Adaptec AHA-2944 SCSI host adapter",                 /* AIC_7874 */
+  "Adaptec AIC-7880 Ultra SCSI host adapter",           /* AIC_7880 */
+  "Adaptec AHA-294X Ultra SCSI host adapter",           /* AIC_7881 */
+  "Adaptec AHA-394X Ultra SCSI host adapter",           /* AIC_7882 */
+  "Adaptec AHA-398X Ultra SCSI host adapter",           /* AIC_7883 */
+  "Adaptec AHA-2944 Ultra SCSI host adapter",           /* AIC_7884 */
+  "Adaptec AIC-7895 Ultra SCSI host adapter"            /* AIC_7895 */
 };
 
 /*
@@ -460,58 +448,58 @@ static const char *board_names[] = {
 #define DID_RETRY_COMMAND DID_ERROR
 
 #define HSCSIID        0x07
-#define HWSCSIID       0x0F
 #define SCSI_RESET     0x040
 
 /*
  * EISA/VL-bus stuff
  */
-#define MINSLOT                1
-#define MAXSLOT                15
-#define SLOTBASE(x)    ((x) << 12)
+#define MINSLOT                1
+#define MAXSLOT                15
+#define SLOTBASE(x)        ((x) << 12)
 #define BASE_TO_SLOT(x) ((x) >> 12)
 
 /*
  * Standard EISA Host ID regs  (Offset from slot base)
  */
-#define HID0           0x80   /* 0,1: msb of ID2, 2-7: ID1      */
-#define HID1           0x81   /* 0-4: ID3, 5-7: LSB ID2         */
-#define HID2           0x82   /* product                        */
-#define HID3           0x83   /* firmware revision              */
+#define HID0                0x80   /* 0,1: msb of ID2, 2-7: ID1      */
+#define HID1                0x81   /* 0-4: ID3, 5-7: LSB ID2         */
+#define HID2                0x82   /* product                        */
+#define HID3                0x83   /* firmware revision              */
 
 /*
  * AIC-7770 I/O range to reserve for a card
  */
-#define MINREG         0xC00
-#define MAXREG         0xCBF
+#define MINREG                0xC00
+#define MAXREG                0xCBF
 
-#define INTDEF         0x5C            /* Interrupt Definition Register */
+#define INTDEF                0x5C      /* Interrupt Definition Register */
 
 /*
  * AIC-78X0 PCI registers
  */
-#define        CLASS_PROGIF_REVID      0x08
-#define                DEVREVID        0x000000FFul
-#define                PROGINFC        0x0000FF00ul
-#define                SUBCLASS        0x00FF0000ul
-#define                BASECLASS       0xFF000000ul
-
-#define        CSIZE_LATTIME           0x0C
-#define                CACHESIZE       0x0000003Ful    /* only 5 bits */
-#define                LATTIME         0x0000FF00ul
-
-#define        DEVCONFIG               0x40
-#define                MPORTMODE       0x00000400ul    /* aic7870 only */
-#define                RAMPSM          0x00000200ul    /* aic7870 only */
-#define                VOLSENSE        0x00000100ul
-#define                SCBRAMSEL       0x00000080ul
-#define                MRDCEN          0x00000040ul
-#define                EXTSCBTIME      0x00000020ul    /* aic7870 only */
-#define                EXTSCBPEN       0x00000010ul    /* aic7870 only */
-#define                BERREN          0x00000008ul
-#define                DACEN           0x00000004ul
-#define                STPWLEVEL       0x00000002ul
-#define                DIFACTNEGEN     0x00000001ul    /* aic7870 only */
+#define        CLASS_PROGIF_REVID        0x08
+#define                DEVREVID        0x000000FFul
+#define                PROGINFC        0x0000FF00ul
+#define                SUBCLASS        0x00FF0000ul
+#define                BASECLASS        0xFF000000ul
+
+#define        CSIZE_LATTIME                0x0C
+#define                CACHESIZE        0x0000003Ful        /* only 5 bits */
+#define                LATTIME                0x0000FF00ul
+
+#define        DEVCONFIG                0x40
+#define                SCBSIZE32        0x00010400ul        /* aic789X only */
+#define                MPORTMODE        0x00000400ul        /* aic7870 only */
+#define                RAMPSM           0x00000200ul        /* aic7870 only */
+#define                VOLSENSE         0x00000100ul
+#define                SCBRAMSEL        0x00000080ul
+#define                MRDCEN           0x00000040ul
+#define                EXTSCBTIME       0x00000020ul        /* aic7870 only */
+#define                EXTSCBPEN        0x00000010ul        /* aic7870 only */
+#define                BERREN           0x00000008ul
+#define                DACEN            0x00000004ul
+#define                STPWLEVEL        0x00000002ul
+#define                DIFACTNEGEN      0x00000001ul        /* aic7870 only */
 
 
 /*
@@ -535,69 +523,72 @@ struct seeprom_config {
 /*
  * SCSI ID Configuration Flags
  */
-#define CFXFER         0x0007          /* synchronous transfer rate */
-#define CFSYNCH                0x0008          /* enable synchronous transfer */
-#define CFDISC         0x0010          /* enable disconnection */
-#define CFWIDEB                0x0020          /* wide bus device (wide card) */
-/* UNUSED              0x00C0 */
-#define CFSTART                0x0100          /* send start unit SCSI command */
-#define CFINCBIOS      0x0200          /* include in BIOS scan */
-#define CFRNFOUND      0x0400          /* report even if not found */
-/* UNUSED              0xF800 */
-  unsigned short device_flags[16];     /* words 0-15 */
+#define CFXFER                0x0007      /* synchronous transfer rate */
+#define CFSYNCH               0x0008      /* enable synchronous transfer */
+#define CFDISC                0x0010      /* enable disconnection */
+#define CFWIDEB               0x0020      /* wide bus device (wide card) */
+#define CFSYNCHISULTRA        0x0040      /* CFSYNC is an ultra offset */
+/* UNUSED                0x0080 */
+#define CFSTART               0x0100      /* send start unit SCSI command */
+#define CFINCBIOS             0x0200      /* include in BIOS scan */
+#define CFRNFOUND             0x0400      /* report even if not found */
+#define CFMULTILUN            0x0800      /* probe mult luns in BIOS scan */
+/* UNUSED                0xF000 */
+  unsigned short device_flags[16];        /* words 0-15 */
 
 /*
  * BIOS Control Bits
  */
-#define CFSUPREM       0x0001          /* support all removable drives */
-#define CFSUPREMB      0x0002          /* support removable drives for boot only */
-#define CFBIOSEN       0x0004          /* BIOS enabled */
-/* UNUSED              0x0008 */
-#define CFSM2DRV       0x0010          /* support more than two drives */
-#define CF284XEXTEND   0x0020          /* extended translation (284x cards) */
-/* UNUSED              0x0040 */
-#define CFEXTEND       0x0080          /* extended translation enabled */
-/* UNUSED              0xFF00 */
-  unsigned short bios_control;         /* word 16 */
+#define CFSUPREM        0x0001  /* support all removable drives */
+#define CFSUPREMB       0x0002  /* support removable drives for boot only */
+#define CFBIOSEN        0x0004  /* BIOS enabled */
+/* UNUSED                0x0008 */
+#define CFSM2DRV        0x0010  /* support more than two drives */
+#define CF284XEXTEND    0x0020  /* extended translation (284x cards) */
+/* UNUSED                0x0040 */
+#define CFEXTEND        0x0080  /* extended translation enabled */
+/* UNUSED                0xFF00 */
+  unsigned short bios_control;  /* word 16 */
 
 /*
  * Host Adapter Control Bits
  */
-#define CFAUTOTERM      0x0001          /* Perform Auto termination */
-#define CFULTRAEN       0x0002          /* Ultra SCSI speed enable (Ultra cards) */
-#define CF284XSELTO     0x0003          /* Selection timeout (284x cards) */
-#define CF284XFIFO      0x000C          /* FIFO Threshold (284x cards) */
-#define CFSTERM         0x0004          /* SCSI low byte termination */
-#define CFWSTERM        0x0008          /* SCSI high byte termination (wide card) */
-#define CFSPARITY      0x0010          /* SCSI parity */
-#define CF284XSTERM    0x0020          /* SCSI low byte termination (284x cards) */
-#define CFRESETB       0x0040          /* reset SCSI bus at boot */
-/* UNUSED              0xFF80 */
-  unsigned short adapter_control;      /* word 17 */
+#define CFAUTOTERM      0x0001  /* Perform Auto termination */
+#define CFULTRAEN       0x0002  /* Ultra SCSI speed enable (Ultra cards) */
+#define CF284XSELTO     0x0003  /* Selection timeout (284x cards) */
+#define CF284XFIFO      0x000C  /* FIFO Threshold (284x cards) */
+#define CFSTERM         0x0004  /* SCSI low byte termination */
+#define CFWSTERM        0x0008  /* SCSI high byte termination (wide card) */
+#define CFSPARITY       0x0010  /* SCSI parity */
+#define CF284XSTERM     0x0020  /* SCSI low byte termination (284x cards) */
+#define CFRESETB        0x0040  /* reset SCSI bus at boot */
+#define CFBPRIMARY      0x0100  /* Channel B primary on 7895 chipsets */
+/* UNUSED                0xFE80 */
+  unsigned short adapter_control;        /* word 17 */
 
 /*
  * Bus Release, Host Adapter ID
  */
-#define CFSCSIID       0x000F          /* host adapter SCSI ID */
-/* UNUSED              0x00F0 */
-#define CFBRTIME       0xFF00          /* bus release time */
-  unsigned short brtime_id;            /* word 18 */
+#define CFSCSIID        0x000F                /* host adapter SCSI ID */
+/* UNUSED                0x00F0 */
+#define CFBRTIME        0xFF00                /* bus release time */
+  unsigned short brtime_id;                /* word 18 */
 
 /*
  * Maximum targets
  */
-#define CFMAXTARG      0x00FF  /* maximum targets */
-/* UNUSED              0xFF00 */
-  unsigned short max_targets;          /* word 19 */
+#define CFMAXTARG        0x00FF        /* maximum targets */
+/* UNUSED                0xFF00 */
+  unsigned short max_targets;                /* word 19 */
 
-  unsigned short res_1[11];            /* words 20-30 */
-  unsigned short checksum;             /* word 31 */
+  unsigned short res_1[11];                /* words 20-30 */
+  unsigned short checksum;                /* word 31 */
 };
 
-#define SELBUS_MASK            0x0a
-#define        SELNARROW       0x00
-#define        SELBUSB         0x08
-#define SINGLE_BUS             0x00
+#define SELBUS_MASK                0x0a
+#define         SELNARROW        0x00
+#define         SELBUSB                0x08
+#define SINGLE_BUS                0x00
 
 #define SCB_TARGET(scb)         \
        (((scb)->hscb->target_channel_lun & TID) >> 4)
@@ -612,17 +603,22 @@ struct seeprom_config {
  * condition in this location. This then will modify a DID_OK status
  * into an appropriate error for the higher-level SCSI code.
  */
-#define aic7xxx_error(cmd)     ((cmd)->SCp.Status)
+#define aic7xxx_error(cmd)        ((cmd)->SCp.Status)
 
 /*
  * Keep track of the targets returned status.
  */
-#define aic7xxx_status(cmd)    ((cmd)->SCp.sent_command)
+#define aic7xxx_status(cmd)        ((cmd)->SCp.sent_command)
 
 /*
  * The position of the SCSI commands scb within the scb array.
  */
-#define aic7xxx_position(cmd)  ((cmd)->SCp.have_data_in)
+#define aic7xxx_position(cmd)        ((cmd)->SCp.have_data_in)
+
+/*
+ * So we can keep track of our host structs
+ */
+static struct aic7xxx_host *first_aic7xxx = NULL;
 
 /*
  * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
@@ -637,14 +633,14 @@ struct hw_scatterlist {
 /*
  * Maximum number of SG segments these cards can support.
  */
-#define        AIC7XXX_MAX_SG 27
+#define        AIC7XXX_MAX_SG 128
 
 /*
  * The maximum number of SCBs we could have for ANY type
  * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
  * SEQUENCER CODE IF THIS IS MODIFIED!
  */
-#define AIC7XXX_MAXSCB 255
+#define AIC7XXX_MAXSCB        255
 
 
 struct aic7xxx_hwscb {
@@ -660,53 +656,118 @@ struct aic7xxx_hwscb {
 /*16*/  unsigned int  data_count;
 /*20*/  unsigned int  SCSI_cmd_pointer;
 /*24*/  unsigned char SCSI_cmd_length;
-/*25*/ u_char tag;                     /* Index into our kernel SCB array.
-                                        * Also used as the tag for tagged I/O
-                                        */
-#define SCB_PIO_TRANSFER_SIZE  26      /* amount we need to upload/download
-                                        * via PIO to initialize a transaction.
-                                        */
-/*26*/  unsigned char next;             /* Used to thread SCBs awaiting selection
-                                         * or disconnected down in the sequencer.
-                                         */
+/*25*/  unsigned char tag;          /* Index into our kernel SCB array.
+                                     * Also used as the tag for tagged I/O
+                                     */
+#define SCB_PIO_TRANSFER_SIZE  26   /* amount we need to upload/download
+                                     * via PIO to initialize a transaction.
+                                     */
+/*26*/  unsigned char next;         /* Used to thread SCBs awaiting selection
+                                     * or disconnected down in the sequencer.
+                                     */
 /*27*/  unsigned char prev;
-/*28*/  unsigned int pad;               /*
-                                         * Unused by the kernel, but we require
-                                         * the padding so that the array of
-                                         * hardware SCBs is alligned on 32 byte
-                                         * boundaries so the sequencer can index
-                                         */
+/*28*/  unsigned int pad;           /*
+                                     * Unused by the kernel, but we require
+                                     * the padding so that the array of
+                                     * hardware SCBs is alligned on 32 byte
+                                     * boundaries so the sequencer can index
+                                     */
 };
 
 typedef enum {
-       SCB_FREE                = 0x0000,
-       SCB_ACTIVE              = 0x0001,
-       SCB_ABORTED             = 0x0002,
-       SCB_DEVICE_RESET        = 0x0004,
-       SCB_SENSE               = 0x0008,
-       SCB_TIMEDOUT            = 0x0010,
-       SCB_QUEUED_FOR_DONE     = 0x0020,
-       SCB_RECOVERY_SCB        = 0x0040,
-       SCB_WAITINGQ            = 0x0080,
-       SCB_ASSIGNEDQ           = 0x0100,
-       SCB_SENTORDEREDTAG      = 0x0200,
-       SCB_MSGOUT_SDTR         = 0x0400,
-       SCB_MSGOUT_WDTR         = 0x0800,
-       SCB_ABORT               = 0x1000,
-       SCB_QUEUED_ABORT        = 0x2000
+        SCB_FREE                = 0x0000,
+        SCB_WDTR_16BIT          = 0x0001,
+        SCB_WAITINGQ            = 0x0002,
+        SCB_ACTIVE              = 0x0004,
+        SCB_SENSE               = 0x0008,
+        SCB_ABORT               = 0x0010,
+        SCB_DEVICE_RESET        = 0x0020,
+        SCB_RESET               = 0x0040,
+        SCB_RECOVERY_SCB        = 0x0080,
+        SCB_WAS_BUSY            = 0x0100,
+        SCB_MSGOUT_SDTR         = 0x0400,
+        SCB_MSGOUT_WDTR         = 0x0800,
+        SCB_MSGOUT_WDTR_8BIT    = 0x0800,
+        SCB_MSGOUT_WDTR_16BIT   = 0x0801,
+        SCB_MSGOUT_BITS         = SCB_MSGOUT_SDTR | SCB_MSGOUT_WDTR_16BIT,
+        SCB_QUEUED_ABORT        = 0x1000,
+        SCB_QUEUED_FOR_DONE     = 0x2000
 } scb_flag_type;
 
+typedef enum {
+        AHC_FNONE                 = 0x00000000,
+        AHC_PAGESCBS              = 0x00000001,
+        AHC_CHANNEL_B_PRIMARY     = 0x00000002,
+        AHC_USEDEFAULTS           = 0x00000004,
+        AHC_INDIRECT_PAGING       = 0x00000008,
+        AHC_CHNLB                 = 0x00000020,
+        AHC_CHNLC                 = 0x00000040,
+        AHC_EXTEND_TRANS_A        = 0x00000100,
+        AHC_EXTEND_TRANS_B        = 0x00000200,
+        AHC_TERM_ENB_A            = 0x00000400,
+        AHC_TERM_ENB_B            = 0x00000800,
+        AHC_HANDLING_REQINITS     = 0x00001000,
+        AHC_TARGETMODE            = 0x00002000,
+        AHC_NEWEEPROM_FMT         = 0x00004000,
+ /*
+  *  Here ends the FreeBSD defined flags and here begins the linux defined
+  *  flags.  NOTE: I did not preserve the old flag name during this change
+  *  specifically to force me to evaluate what flags were being used properly
+  *  and what flags weren't.  This way, I could clean up the flag usage on
+  *  a use by use basis.  Doug Ledford
+  */
+        AHC_A_SCANNED             = 0x00100000,
+        AHC_B_SCANNED             = 0x00200000,
+        AHC_MULTI_CHANNEL         = 0x00400000,
+        AHC_BIOS_ENABLED          = 0x00800000,
+        AHC_ABORT_PENDING         = 0x02000000,
+        AHC_RESET_PENDING         = 0x04000000,
+        AHC_IN_ISR                = 0x10000000,
+        AHC_IN_ABORT              = 0x20000000,
+        AHC_IN_RESET              = 0x40000000
+} ahc_flag_type;
+
+typedef enum {
+        AHC_NONE                  = 0x00000000,
+        AHC_ULTRA                 = 0x00000001,
+        AHC_WIDE                  = 0x00000002,
+        AHC_TWIN                  = 0x00000008,
+        AHC_AIC7770               = 0x00000010,
+        AHC_AIC7850               = 0x00000020,
+        AHC_AIC7860               = 0x00000021,
+        AHC_AIC7870               = 0x00000040,
+        AHC_AIC7880               = 0x00000041,
+        AHC_AIC7895               = 0x00000081,
+        AHC_AIC78x0               = 0x000000E0,
+        AHC_274                   = 0x00000110,
+        AHC_284                   = 0x00000210,
+        AHC_294AU                 = 0x00000421,
+        AHC_294                   = 0x00000440,
+        AHC_294U                  = 0x00000441,
+        AHC_394                   = 0x00000840,
+        AHC_394U                  = 0x00000841,
+        AHC_394AU                 = 0x00000881,
+        AHC_398                   = 0x00001040,
+        AHC_398U                  = 0x00001041,
+        AHC_39x                   = 0x00001880
+} ahc_type;
+
 struct aic7xxx_scb {
         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
-       Scsi_Cmnd             *cmd;           /* Scsi_Cmnd for this scb */
+        Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
         struct aic7xxx_scb    *q_next;        /* next scb in queue */
-       scb_flag_type          flags;         /* current state of scb */
-       struct hw_scatterlist *sg_list;       /* SG list in adapter format */
-       unsigned char          sense_cmd[6];  /*
+        scb_flag_type          flags;         /* current state of scb */
+        struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        unsigned char          tag_action;
+        unsigned char          sg_count;
+        unsigned char          sense_cmd[6];  /*
                                                * Allocate 6 characters for
                                                * sense command.
                                                */
-        unsigned char          sg_count;
+        unsigned int           sg_length; /* We init this during buildscb so we
+                                           * don't have to calculate anything
+                                           * during underflow/overflow/stat code
+                                           */
 };
 
 /*
@@ -724,7 +785,7 @@ static struct {
   { ILLHADDR,  "Illegal Host Access" },
   { ILLSADDR,  "Illegal Sequencer Address referenced" },
   { ILLOPCODE, "Illegal Opcode in sequencer program" },
-  { PARERR,    "Sequencer Ram Parity Error" }
+  { SQPARERR,  "Sequencer Ram Parity Error" }
 };
 
 static unsigned char
@@ -740,58 +801,110 @@ typedef struct {
   unsigned char  maxhscbs;         /* hardware scbs */
   unsigned char  maxscbs;          /* max scbs including pageable scbs */
   struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
-  unsigned int   reserve[100];
 } scb_data_type;
 
+typedef struct {
+  unsigned char period;
+  unsigned char offset;
+} syncinfo_type;
+
 /*
- * Define a structure used for each host adapter, only one per IRQ.
+ * Define a structure used for each host adapter.  Note, in order to avoid
+ * problems with architectures I can't test on (because I don't have one,
+ * such as the Alpha based systems) which happen to give faults for
+ * non-aligned memory accesses, care was taken to align this structure
+ * in a way that gauranteed all accesses larger than 8 bits were aligned
+ * on the appropriate boundary.  It's also organized to try and be more
+ * cache line efficient.  Be careful when changing this lest you might hurt
+ * overall performance and bring down the wrath of the masses.
  */
 struct aic7xxx_host {
+  /*
+   *  This is the first 64 bytes in the host struct
+   */
+
   struct Scsi_Host        *host;             /* pointer to scsi host */
-  struct aic7xxx_host     *next;             /* pointer to next aic7xxx device */
+  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
   int                      host_no;          /* SCSI host number */
-  int                      instance;         /* aic7xxx instance number */
-  int                      scsi_id;          /* host adapter SCSI ID */
-  int                      scsi_id_b;        /*   channel B for twin adapters */
-  int                      irq;              /* IRQ for this adapter */
   unsigned long            base;             /* card base address */
-  unsigned long            mbase;            /* I/O memory address */
   volatile unsigned char  *maddr;            /* memory mapped address */
-#define A_SCANNED               0x0001
-#define B_SCANNED               0x0002
-#define EXTENDED_TRANSLATION    0x0004
-#define FLAGS_CHANNEL_B_PRIMARY 0x0008
-#define MULTI_CHANNEL           0x0010
-#define ULTRA_ENABLED           0x0020
-#define PAGE_ENABLED            0x0040
-#define USE_DEFAULTS            0x0080
-#define BIOS_ENABLED            0x0100
-#define IN_ISR                  0x0200
-#define IN_TIMEOUT              0x0400
-#define SHARED_SCBDATA          0x0800
-#define HAVE_SEEPROM            0x1000
-  unsigned int             flags;
-  unsigned int             isr_count;        /* Interrupt count */
-  unsigned short           needsdtr_copy;    /* default config */
-  unsigned short           needsdtr;
-  unsigned short           sdtr_pending;
-  unsigned short           needwdtr_copy;    /* default config */
-  unsigned short           needwdtr;
-  unsigned short           wdtr_pending;
-  unsigned short           orderedtag;
-  unsigned short           discenable;      /* Targets allowed to disconnect */
-  aha_chip_type            chip_type;        /* card type */
-  aha_chip_class_type      chip_class;
-  aha_bus_type             bus_type;         /* normal/twin/wide bus */
-  unsigned char            chan_num;         /* for 39xx, channel number */
+  unsigned long            mbase;            /* I/O memory address */
+  volatile ahc_flag_type   flags;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+  spinlock_t               spin_lock;
+#endif
+  volatile unsigned char   cpu_lock_count[NR_CPUS];
+  ahc_type                 type;             /* card type */
+  unsigned long            last_reset;
+  unsigned long            isr_count;        /* Interrupt count */
+  unsigned long            spurious_int;
+  unsigned short           discenable;       /* Targets allowed to disconnect */
+  unsigned short           tagenable;        /* Targets using tagged I/O */
+  unsigned short           orderedtag;       /* Ordered Q tags allowed */
+  volatile unsigned char   activescbs;       /* active scbs */
+  unsigned char            max_activescbs;
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
-  unsigned char            qcntmask;
-  unsigned char            qfullcount;
-  unsigned char            cmdoutcnt;
-  unsigned char            curqincnt;
-  unsigned char            activescbs;       /* active scbs */
-  scb_queue_type           waiting_scbs;     /*
+  volatile unsigned char   qoutfifonext;
+  volatile unsigned char   qinfifonext;
+
+  /*
+   * MAX_TARGETS is currently == 16, so that makes these entries the next
+   * 64 bytes
+   */
+
+#define  DEVICE_PRESENT                 0x01
+#define  BUS_DEVICE_RESET_PENDING       0x02
+#define  DEVICE_TIMEOUT                 0x04
+#define  DEVICE_PRINT_SDTR              0x08
+#define  DEVICE_PRINT_WDTR              0x10
+#define  DEVICE_SUCCESS                 0x20
+#define  DEVICE_TAGGED_SUCCESS          0x40
+  volatile unsigned char   dev_flags[MAX_TARGETS];
+  volatile unsigned char   dev_active_cmds[MAX_TARGETS];
+  unsigned char            dev_temp_queue_depth[MAX_TARGETS];
+  unsigned char            dev_commands_sent[MAX_TARGETS];
+
+  /*
+   * The next 64.... 
+   */
+
+  long                     dev_last_reset[MAX_TARGETS];
+
+  /*
+   * The next 64....
+   */
+
+  unsigned char            dev_mid_level_queue_depth[MAX_TARGETS];
+  unsigned char            dev_last_queue_full[MAX_TARGETS];
+  unsigned char            dev_last_queue_full_count[MAX_TARGETS];
+  unsigned char            dev_max_queue_depth[MAX_TARGETS];
+
+  /*
+   * The next 128....
+   */
+
+  volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
+
+  /*
+   *
+   */
+
+  struct timer_list        dev_timer[MAX_TARGETS];
+
+  /*
+   * The next 64....
+   */
+
+  unsigned char            msg_buf[9];       /* The message for the target */
+  unsigned char            msg_type;
+#define MSG_TYPE_NONE              0x00
+#define MSG_TYPE_INITIATOR_MSGOUT  0x01
+#define MSG_TYPE_INITIATOR_MSGIN   0x02
+  unsigned char            msg_len;          /* Length of message */
+  unsigned char            msg_index;        /* Index into msg_buf array */
+  syncinfo_type            syncinfo[MAX_TARGETS];
+  volatile scb_queue_type  waiting_scbs;     /*
                                               * SCBs waiting for space in
                                               * the QINFIFO.
                                               */
@@ -801,14 +914,41 @@ struct aic7xxx_host {
     Scsi_Cmnd *head;
     Scsi_Cmnd *tail;
   } completeq;
-  struct aic7xxx_device_status {
-    long last_reset;
-#define  DEVICE_SUCCESS                 0x01
-#define  BUS_DEVICE_RESET_PENDING       0x02
-    int  flags;
-    int  commands_sent;
-    int  active_cmds;
-  } device_status[16];
+
+
+  /*
+   * We put the less frequently used host structure items after the more
+   * frequently used items to try and ease the burden on the cache subsystem.
+   * These entries are not *commonly* accessed, whereas the preceding entries
+   * are accessed very often.  The only exceptions are the qinfifo, qoutfifo,
+   * and untagged_scbs array.  But, they are often accessed only once and each
+   * access into these arrays is likely to blow a cache line, so they are put
+   * down here so we can minimize the number of cache lines required to hold
+   * the preceeding entries.
+   */
+
+  volatile unsigned char   untagged_scbs[256];
+  volatile unsigned char   qoutfifo[256];
+  volatile unsigned char   qinfifo[256];
+  unsigned short           needsdtr;
+  unsigned short           sdtr_pending;
+  unsigned short           needwdtr;
+  unsigned short           wdtr_pending;
+  int                      instance;         /* aic7xxx instance number */
+  int                      scsi_id;          /* host adapter SCSI ID */
+  int                      scsi_id_b;        /* channel B for twin adapters */
+  unsigned int             bios_address;
+  int                      board_name_index;
+  unsigned long            reset_start;
+  unsigned short           needsdtr_copy;    /* default config */
+  unsigned short           needwdtr_copy;    /* default config */
+  unsigned short           ultraenb;         /* Ultra mode target list */
+  unsigned short           bios_control;     /* bios control - SEEPROM */
+  unsigned short           adapter_control;  /* adapter control - SEEPROM */
+  unsigned char            pci_bus;
+  unsigned char            pci_device_fn;
+  unsigned char            irq;              /* IRQ for this adapter */
+
 #ifdef AIC7XXX_PROC_STATS
   /*
    * Statistics Kept:
@@ -820,6 +960,10 @@ struct aic7xxx_host {
    *    < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K
    *
    * Total amounts read/written above 512 bytes (amts under ignored)
+   *
+   * NOTE: Enabling this feature is likely to cause a noticeable performance
+   * decrease as the accesses into the stats structures blows apart multiple
+   * cache lines and is CPU time consuming.
    */
   struct aic7xxx_xferstats {
     long xfers;                              /* total xfer count */
@@ -841,7 +985,7 @@ struct aic7xxx_host {
 static struct {
   short period;
   /* Rates in Ultra mode have bit 8 of sxfr set */
-#define                ULTRA_SXFR 0x100
+#define                ULTRA_SXFR 0x100
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
@@ -861,55 +1005,34 @@ static struct {
 static int num_aic7xxx_syncrates =
     sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
 
-#ifdef CONFIG_PCI
-static int number_of_3940s = 0;
-static int number_of_3985s = 0;
-#endif /* CONFIG_PCI */
-
-#ifdef AIC7XXX_DEBUG
-
-#if 0
-static void
-debug_scb(struct aic7xxx_scb *scb)
-{
-  struct aic7xxx_hwscb *hscb = scb->hscb;
-
-  printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
-    scb,
-    hscb->control,
-    hscb->target_channel_lun,
-    hscb->SCSI_cmd_length,
-    le32_to_cpu(hscb->SCSI_cmd_pointer) );
-  printk("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
-    le32_to_cpu(hscb->data_count),
-    le32_to_cpu(hscb->data_pointer),
-    hscb->SG_segment_count,
-    le32_to_cpu(hscb->SG_list_pointer));
-  printk("        sg_addr:%lx sg_len:%ld\n",
-    le32_to_cpu(hscb->sg_list[0].address),
-    le32_to_cpu(hscb->sg_list[0].length));
-}
-#endif
-
-#else
-#  define debug_scb(x)
-#endif AIC7XXX_DEBUG
-
-#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
-                        (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1),  \
+                        (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
                         ((scb->hscb)->target_channel_lun & 0x07)
 
-#define TC_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
-                       (((scb->hscb)->target_channel_lun >> 3) & 0x01)
-
-#define CHAN_TO_INT(chan) ((chan) == 'A' ? 0 : 1)
+#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01),  \
+                        ((cmd->target) & 0x0f), \
+                        ((cmd->lun) & 0x07)
 
 #define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
 
+/*
+ * A nice little define to make doing our printks a little easier
+ */
+
+#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
+#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
+
 /*
  * XXX - these options apply unilaterally to _all_ 274x/284x/294x
  *       cards in the system.  This should be fixed.
  */
+static int aic7xxx_7895_irq_hack = -1;       /* This enables a hack to fix
+                                              * IRQ settings on buggy 7895
+                                              * MB controller setups
+                                              *  -1 == Disable this hack
+                                              *   0 == Use the Channel A IRQ
+                                              *   1 == Use the Channel B IRQ
+                                              */
 static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
 static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
 static int aic7xxx_irq_trigger = -1;         /*
@@ -917,9 +1040,96 @@ static int aic7xxx_irq_trigger = -1;         /*
                                               *  0 use edge triggered
                                               *  1 use level triggered
                                               */
-static int aic7xxx_enable_ultra = 0;         /* enable ultra SCSI speeds */
-static int aic7xxx_verbose = 0;                     /* verbose messages */
-static struct aic7xxx_host *first_aic7xxx = NULL; /* list of all our devices */
+static int aic7xxx_reverse_scan = 0;         /*
+                                              * Set this to anything but 0
+                                              * to make the probe code
+                                              * reverse the order of PCI
+                                              * devices
+                                              */
+static int aic7xxx_override_term = 0;        /*
+                                              * Set this to non-0 to make the
+                                              * driver override any BIOS
+                                              * configured termination
+                                              * settings based upon the
+                                              * results of the cable detect
+                                              * logic.  This only applies
+                                              * to cards that have cable
+                                              * detection logic and a SEEPROM
+                                              */
+static int aic7xxx_panic_on_abort = 0;       /*
+                                              * Set this to non-0 in order
+                                              * to force the driver to panic
+                                              * the kernel and print out
+                                              * debugging info on an abort
+                                              * or reset call into the
+                                              * driver.
+                                              */
+
+/*
+ * So that insmod can find the variable and make it point to something
+ */
+#ifdef MODULE
+static char * aic7xxx = NULL;
+
+/*
+ * Just in case someone uses commas to separate items on the insmod
+ * command line, we define a dummy buffer here to avoid having insmod
+ * write wild stuff into our code segment
+ */
+static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
+
+#endif
+
+/*
+ * See the comments earlier in the file for what this item is all about
+ * If you have more than 4 controllers, you will need to increase the
+ * the number of items in the array below.  Additionally, if you don't
+ * want to have lilo pass a humongous config line to the aic7xxx driver,
+ * then you can get in and manually adjust these instead of leaving them
+ * at the default.  Pay attention to the comments earlier in this file
+ * concerning this array if you are going to hand modify these values.
+ */
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS}
+};
+
+#define VERBOSE_NORMAL         0x0000
+#define VERBOSE_NEGOTIATION    0x0001
+#define VERBOSE_SEQINT         0x0002
+#define VERBOSE_SCSIINT        0x0004
+#define VERBOSE_PROBE          0x0008
+#define VERBOSE_PROBE2         0x0010
+#define VERBOSE_QUEUE          0x0020
+#define VERBOSE_MINOR_ERROR    0x0040
+#define VERBOSE_QUEUE_FULL     0x0080
+#define VERBOSE_ABORT          0x0f00
+#define VERBOSE_ABORT_MID      0x0100
+#define VERBOSE_ABORT_FIND     0x0200
+#define VERBOSE_ABORT_PROCESS  0x0400
+#define VERBOSE_ABORT_RETURN   0x0800
+#define VERBOSE_RESET          0xf000
+#define VERBOSE_RESET_MID      0x1000
+#define VERBOSE_RESET_FIND     0x2000
+#define VERBOSE_RESET_PROCESS  0x4000
+#define VERBOSE_RESET_RETURN   0x8000
+static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
+           VERBOSE_PROBE;                     /* verbose messages */
 
 
 /****************************************************************************
@@ -929,52 +1139,44 @@ static struct aic7xxx_host *first_aic7xxx = NULL; /* list of all our devices */
  *
  ***************************************************************************/
 
+
 static inline unsigned char
 aic_inb(struct aic7xxx_host *p, long port)
 {
-  if (p->maddr != NULL)
-    return (p->maddr[port]);
+  unsigned char x;
+  if(p->maddr)
+    x = p->maddr[port];
   else
-    return (inb(p->base + port));
+    x = inb(p->base + port);
+  mb();
+  return(x);
 }
 
 static inline void
 aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
 {
-  if (p->maddr != NULL)
+  if(p->maddr)
     p->maddr[port] = val;
   else
     outb(val, p->base + port);
+  mb();
 }
 
 static inline void
 aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
 {
-  if (p->maddr != NULL)
+  if(p->maddr)
   {
-#if defined(__alpha__) || defined(__sparc_v9__) || defined(__powerpc__)
     int i;
 
     for (i=0; i < size; i++)
     {
       p->maddr[port] = valp[i];
     }
-#else
-    __asm __volatile("
-      cld;
-    1:  lodsb;
-      movb %%al,(%0);
-      loop 1b"      :
-              :
-      "r" (p->maddr + port),
-      "S" (valp), "c" (size)  :
-      "%esi", "%ecx", "%eax");
-#endif
   }
   else
-  {
     outsb(p->base + port, valp, size);
-  }
+  mb();
 }
 
 /*+F*************************************************************************
@@ -991,6 +1193,7 @@ aic7xxx_setup(char *s, int *dummy)
 {
   int   i, n;
   char *p;
+  char *end;
 
   static struct {
     const char *name;
@@ -999,25 +1202,112 @@ aic7xxx_setup(char *s, int *dummy)
     { "extended",    &aic7xxx_extended },
     { "no_reset",    &aic7xxx_no_reset },
     { "irq_trigger", &aic7xxx_irq_trigger },
-    { "ultra",       &aic7xxx_enable_ultra },
     { "verbose",     &aic7xxx_verbose },
-    { NULL,          NULL }
+    { "reverse_scan",&aic7xxx_reverse_scan },
+    { "7895_irq_hack", &aic7xxx_7895_irq_hack },
+    { "override_term", &aic7xxx_override_term },
+    { "panic_on_abort", &aic7xxx_panic_on_abort },
+    { "tag_info",    NULL }
   };
 
-  for (p = strtok(s, ","); p; p = strtok(NULL, ","))
+  end = strchr(s, '\0');
+
+  for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
   {
-    for (i = 0; options[i].name; i++)
+    for (i = 0; i < NUMBER(options); i++)
     {
       n = strlen(options[i].name);
       if (!strncmp(options[i].name, p, n))
       {
-        if (p[n] == ':')
+        if (!strncmp(p, "tag_info", n))
+        {
+          if (p[n] == ':')
+          {
+            char *base;
+            char *tok, *tok_end, *tok_end2;
+            char tok_list[] = { '.', ',', '{', '}', '\0' };
+            int i, instance = -1, device = -1;
+            unsigned char done = FALSE;
+
+            base = p;
+            tok = base + n + 1;  /* Forward us just past the ':' */
+            tok_end = strchr(tok, '\0');
+            if (tok_end < end)
+              *tok_end = ',';
+            while(!done)
+            {
+              switch(*tok)
+              {
+                case '{':
+                  if (instance == -1)
+                    instance = 0;
+                  else if (device == -1)
+                    device = 0;
+                  tok++;
+                  break;
+                case '}':
+                  if (device != -1)
+                    device = -1;
+                  else if (instance != -1)
+                    instance = -1;
+                  tok++;
+                  break;
+                case ',':
+                case '.':
+                  if (instance == -1)
+                    done = TRUE;
+                  else if (device >= 0)
+                    device++;
+                  else if (instance >= 0)
+                    instance++;
+                  if ( (device >= MAX_TARGETS) || 
+                       (instance >= NUMBER(aic7xxx_tag_info)) )
+                    done = TRUE;
+                  tok++;
+                  if (!done)
+                  {
+                    base = tok;
+                  }
+                  break;
+                case '\0':
+                  done = TRUE;
+                  break;
+                default:
+                  done = TRUE;
+                  tok_end = strchr(tok, '\0');
+                  for(i=0; tok_list[i]; i++)
+                  {
+                    tok_end2 = strchr(tok, tok_list[i]);
+                    if ( (tok_end2) && (tok_end2 < tok_end) )
+                    {
+                      tok_end = tok_end2;
+                      done = FALSE;
+                    }
+                  }
+                  if ( (instance >= 0) && (device >= 0) &&
+                       (instance < NUMBER(aic7xxx_tag_info)) &&
+                       (device < MAX_TARGETS) )
+                    aic7xxx_tag_info[instance].tag_commands[device] =
+                      simple_strtoul(tok, NULL, 0) & 0xff;
+                  tok = tok_end;
+                  break;
+              }
+            }
+            while((p != base) && (p != NULL))
+              p = strtok(NULL, ",.");
+          }
+        }
+        else if (p[n] == ':')
         {
           *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
         }
+        else if (!strncmp(p, "verbose", n))
+        {
+          *(options[i].flag) = 0xff69;
+        }
         else
         {
-          *(options[i].flag) = !0;
+          *(options[i].flag) = ~(*(options[i].flag));
         }
       }
     }
@@ -1036,8 +1326,8 @@ aic7xxx_setup(char *s, int *dummy)
 static inline void
 pause_sequencer(struct aic7xxx_host *p)
 {
-  outb(p->pause, p->base + HCNTRL);
-  while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+  aic_outb(p, p->pause, HCNTRL);
+  while ((aic_inb(p, HCNTRL) & PAUSE) == 0)
   {
     ;
   }
@@ -1055,9 +1345,10 @@ static inline void
 unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
 {
   if (unpause_always ||
-      ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
+      ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) &&
+        !(p->flags & AHC_HANDLING_REQINITS) ) )
   {
-    outb(p->unpause, p->base + HCNTRL);
+    aic_outb(p, p->unpause, HCNTRL);
   }
 }
 
@@ -1073,17 +1364,16 @@ static inline void
 restart_sequencer(struct aic7xxx_host *p)
 {
   /* Set the sequencer address to 0. */
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
 
   /*
    * Reset and unpause the sequencer.  The reset is suppose to
-   * start the sequencer running, but we do an unpause to make
-   * sure.
+   * start the sequencer running, so we immediately do a pause_sequencer
+   * since some of our code expects the sequencer paused after a restart
    */
-  outb(SEQRESET | FASTMODE, p->base + SEQCTL);
-
-  unpause_sequencer(p, /*unpause_always*/ TRUE);
+  aic_outb(p, SEQRESET | FASTMODE, SEQCTL);
+  pause_sequencer(p);
 }
 
 
@@ -1135,11 +1425,12 @@ static void
 aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
 {
   unsigned char opcode;
-  struct ins_format3 *instr;
+  struct ins_format3 instr;
+  unsigned char dconsts[4] = { 0, 0, 0, 0 };
 
-  instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+  instr = *(struct ins_format3 *) &seqprog[instrptr * 4];
   /* Pull the opcode */
-  opcode = instr->opcode_addr >> 1;
+  opcode = (instr.opcode_addr & ~DOWNLOAD_CONST_IMMEDIATE) >> 1;
   switch (opcode)
   {
     case AIC_OP_JMP:
@@ -1152,15 +1443,13 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
     case AIC_OP_JZ:
     {
       int address_offset;
-      struct ins_format3 new_instr;
       unsigned int address;
       struct patch *patch;
       int i;
 
       address_offset = 0;
-      new_instr = *instr;  /* Strucure copy */
-      address = new_instr.address;
-      address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
+      address = instr.address;
+      address |= (instr.opcode_addr & ADDR_HIGH_BIT) << 8;
       for (i = 0; i < NUMBER(patches); i++)
       {
         patch = &patches[i];
@@ -1174,20 +1463,23 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
         }
       }
       address -= address_offset;
-      new_instr.address = address &0xFF;
-      new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
-      new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
-      outsb(p->base + SEQRAM, &new_instr.immediate, 4);
-      break;
+      instr.address = address & 0xFF;
+      instr.opcode_addr &= ~ADDR_HIGH_BIT;
+      instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
     }
-
+       /*  Fall through  */
     case AIC_OP_OR:
     case AIC_OP_AND:
     case AIC_OP_XOR:
     case AIC_OP_ADD:
     case AIC_OP_ADC:
+      if (instr.opcode_addr & DOWNLOAD_CONST_IMMEDIATE)
+      {
+        instr.immediate = dconsts[instr.immediate];
+      }
+      instr.opcode_addr &= ~DOWNLOAD_CONST_IMMEDIATE;
     case AIC_OP_ROL:
-      outsb(p->base + SEQRAM, &instr->immediate, 4);
+      aic_outsb(p, SEQRAM, &instr.immediate, 4);
       break;
 
     default:
@@ -1212,23 +1504,60 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
   int i;
   int downloaded;
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE)
   {
-    printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+    printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
   }
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+    printk("\n");
   options = 1;  /* Code for all options. */
   downloaded = 0;
-  if ((p->flags & ULTRA_ENABLED) != 0)
+  if (p->type & AHC_ULTRA)
+  {
     options |= ULTRA;
-  if (p->bus_type == AIC_TWIN)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option ULTRA\n",
+        p->host_no);
+  }
+  if (p->type & AHC_TWIN)
+  {
     options |= TWIN_CHANNEL;
-  if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option "
+        "TWIN_CHANNEL\n", p->host_no);
+  }
+  if (p->type & AHC_WIDE)
+  {
+    options |= WIDE;
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option WIDE\n",
+        p->host_no);
+  }
+  /* if (p->scb_data->maxscbs > p->scb_data->maxhscbs)  this should always
+                                                        be true, don't test,
+                                                        just do.            */
+  {
     options |= SCB_PAGING;
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option SCB_PAGING\n",
+        p->host_no);
+  }
+  /* We don't actually support target mode yet, so leave this out 
+  if (p->flags & AHC_TARGETMODE)
+    options |= TARGET_MODE; */
+
+  if ( (options & ~(ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01)) )
+  {
+    printk(KERN_INFO "(scsi%d) Unknown bits set in the options field, "
+      "correcting.\n", p->host_no);
+    options &= ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01;
+  }
+
 
   cur_patch = patches;
-  outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, PERRORDIS | LOADRAM, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
 
   for (i = 0; i < sizeof(seqprog) / 4;  i++)
   {
@@ -1242,13 +1571,16 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
     downloaded++;
   }
 
-  outb(FASTMODE, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, FASTMODE, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+    printk(KERN_INFO "(scsi%d) Download complete,", p->host_no);
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE)
   {
-     printk(" %d instructions downloaded\n", downloaded);
+    printk(" %d instructions downloaded\n", downloaded);
   }
 }
 
@@ -1264,7 +1596,7 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
 static void
 aic7xxx_delay(int seconds)
 {
-  int i;
+  unsigned int i;
 
   /*                        
    * Call udelay() for 1 millisecond inside a loop for  
@@ -1278,137 +1610,63 @@ aic7xxx_delay(int seconds)
 
 /*+F*************************************************************************
  * Function:
- *   rcs_version
+ *   aic7xxx_info
  *
  * Description:
- *   Return a string containing just the RCS version number from either
- *   an Id or Revision RCS clause.
+ *   Return a string describing the driver.
  *-F*************************************************************************/
 const char *
-rcs_version(const char *version_info)
+aic7xxx_info(struct Scsi_Host *dooh)
 {
-  static char buf[10];
-  char *bp, *ep;
-
-  bp = NULL;
-  strcpy(buf, "????");
-  if (!strncmp(version_info, "$Id: ", 5))
-  {
-    if ((bp = strchr(version_info, ' ')) != NULL)
-    {
-      bp++;
-      if ((bp = strchr(bp, ' ')) != NULL)
-      {
-       bp++;
-      }
-    }
-  }
-  else
-  {
-    if (!strncmp(version_info, "$Revision: ", 11))
-    {
-      if ((bp = strchr(version_info, ' ')) != NULL)
-      {
-       bp++;
-      }
-    }
-  }
-
-  if (bp != NULL)
-  {
-    if ((ep = strchr(bp, ' ')) != NULL)
-    {
-      register int len = ep - bp;
-
-      strncpy(buf, bp, len);
-      buf[len] = '\0';
-    }
-  }
+  static char buffer[256];
+  char *bp;
+  struct aic7xxx_host *p;
 
-  return buf;
+  bp = &buffer[0];
+  p = (struct aic7xxx_host *)dooh->hostdata;
+  memset(bp, 0, sizeof(buffer));
+  strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+  strcat(bp, AIC7XXX_C_VERSION);
+  strcat(bp, "/");
+  strcat(bp, AIC7XXX_H_VERSION);
+  strcat(bp, "\n");
+  strcat(bp, "       <");
+  strcat(bp, board_names[p->board_name_index]);
+  strcat(bp, ">");
+
+  return(bp);
 }
 
+
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_info
+ *   aic7xxx_scsirate
  *
  * Description:
- *   Return a string describing the driver.
+ *   Look up the valid period to SCSIRATE conversion in our table
  *-F*************************************************************************/
-const char *
-aic7xxx_info(struct Scsi_Host *notused)
+static unsigned char
+aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
+    unsigned char *period, unsigned char *offset, int target, int channel,
+    int set)
 {
-  static char buffer[128];
+  int i = num_aic7xxx_syncrates;
+  unsigned char response_period;
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned char lun;
 
-  strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
-  strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
-  strcat(buffer, "/");
-  strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
-#if 0
-  strcat(buffer, "/");
-  strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
-#endif
+  tindex = target | (channel << 3);
+  target_mask = 0x01 << tindex;
+  lun = aic_inb(p, SCB_TCL) & 0x07;
 
-  return buffer;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_length
- *
- * Description:
- *   How much data should be transferred for this SCSI command?  Assume
- *   all segments are to be transferred except for the last sg_last
- *   segments.  This will allow us to compute underflow easily.  To
- *   calculate the total length of the command, use sg_last = 0.  To
- *   calculate the length of all but the last 2 SG segments, use
- *   sg_last = 2.
- *-F*************************************************************************/
-static unsigned
-aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
-{
-  int i, segments;
-  unsigned length;
-  struct scatterlist *sg;
-
-  segments = cmd->use_sg - sg_last;
-  sg = (struct scatterlist *) cmd->request_buffer;
-
-  if (cmd->use_sg)
-  {
-    for (i = length = 0; i < segments; i++)
-    {
-      length += sg[i].length;
-    }
-  }
-  else
-  {
-    length = cmd->request_bufflen;
-  }
-
-  return (length);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_scsirate
- *
- * Description:
- *   Look up the valid period to SCSIRATE conversion in our table
- *-F*************************************************************************/
-static void
-aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
-    unsigned char *period, unsigned char *offset, int target, char channel)
-{
-  int i = num_aic7xxx_syncrates;
-  unsigned long ultra_enb_addr;
-  unsigned char ultra_enb, sxfrctl0;
+  response_period = *period;
 
   /*
    * If the offset is 0, then the device is requesting asynchronous
    * transfers.
    */
-  if ((*period <= aic7xxx_syncrates[i - 1].period) && *offset != 0)
+  if ((*period != 0) && (*offset != 0))
   {
     for (i = 0; i < num_aic7xxx_syncrates; i++)
     {
@@ -1418,7 +1676,7 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
          * Watch out for Ultra speeds when ultra is not enabled and
          * vice-versa.
          */
-        if (!(p->flags & ULTRA_ENABLED) &&
+        if (!(p->type & AHC_ULTRA) &&
             (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
         {
           /*
@@ -1431,11 +1689,31 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
         *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
         *period = aic7xxx_syncrates[i].period;
 
-        if (aic7xxx_verbose)
+        /*
+         * When responding to a target that requests
+         * sync, that rate may fall between two rates
+         * that we can output, but still be a rate
+         * that we can receive.  Because of this,
+         * we may want to respond to the target with
+         * the same rate that it sent to us even
+         * if the period we use to send data to it
+         * is lower.  Only lower the response period
+         * if we must.
+         */
+        if ((i == 0) ||
+           ((aic7xxx_syncrates[i-1].rate & ULTRA_SXFR) != 0
+             && (p->type & AHC_ULTRA) == 0))
+        {
+          response_period = *period;
+        }
+
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
         {
-          printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
-                 "offset %d.\n", p->host_no, target, channel,
+          printk(INFO_LEAD "Synchronous at %sMHz, "
+                 "offset %d.\n", p->host_no, channel, target, lun,
                  aic7xxx_syncrates[i].english, *offset);
+          p->dev_flags[tindex] &= ~ DEVICE_PRINT_SDTR;
         }
         break;
       }
@@ -1450,35 +1728,43 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
     *scsirate = 0;
     *period = 0;
     *offset = 0;
-    if (aic7xxx_verbose)
+    response_period = 0;
+    if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+         (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
     {
-      printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
-             p->host_no, target, channel);
+      printk(INFO_LEAD "Using asynchronous transfers.\n",
+             p->host_no, channel, target, lun);
+      p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
     }
   }
 
   /*
    * Ensure Ultra mode is set properly for this target.
    */
-  ultra_enb_addr = ULTRA_ENB;
-  if ((channel == 'B') || (target > 7))
+  if ( (*scsirate != 0) && 
+       (aic7xxx_syncrates[i].rate & ULTRA_SXFR) )
   {
-    ultra_enb_addr++;
+    p->ultraenb |= target_mask;
   }
-  ultra_enb = inb(p->base + ultra_enb_addr);
-  sxfrctl0 = inb(p->base + SXFRCTL0);
-  if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+  else
   {
-    ultra_enb |= 0x01 << (target & 0x07);
-    sxfrctl0 |= FAST20;
+    p->ultraenb &= ~target_mask;
   }
-  else
+  if (set)
   {
-    ultra_enb &= ~(0x01 << (target & 0x07));
+    unsigned char sxfrctl0;
+
+    sxfrctl0 = aic_inb(p, SXFRCTL0);
     sxfrctl0 &= ~FAST20;
+    if (p->ultraenb & target_mask)
+    {
+      sxfrctl0 |= FAST20;
+    }
+    aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
+    aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1);
+    aic_outb(p, sxfrctl0, SXFRCTL0);
   }
-  outb(ultra_enb, p->base + ultra_enb_addr);
-  outb(sxfrctl0, p->base + SXFRCTL0);
+  return(response_period);
 }
 
 /*+F*************************************************************************
@@ -1490,7 +1776,7 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
  *
  *-F*************************************************************************/
 static inline void
-scbq_init(scb_queue_type *queue)
+scbq_init(volatile scb_queue_type *queue)
 {
   queue->head = NULL;
   queue->tail = NULL;
@@ -1505,7 +1791,7 @@ scbq_init(scb_queue_type *queue)
  *
  *-F*************************************************************************/
 static inline void
-scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
   scb->q_next = queue->head;
   queue->head = scb;
@@ -1521,13 +1807,16 @@ scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
  *   Remove an SCB from the head of the list.
  *
  *-F*************************************************************************/
-static inline void
-scbq_remove_head(scb_queue_type *queue)
+static __inline struct aic7xxx_scb *
+scbq_remove_head(volatile scb_queue_type *queue)
 {
+  struct aic7xxx_scb * scbp;
+  scbp = queue->head;
   if (queue->head != NULL)
     queue->head = queue->head->q_next;
   if (queue->head == NULL)       /* If list is now empty, update tail. */
     queue->tail = NULL;
+  return(scbp);
 }
 
 /*+F*************************************************************************
@@ -1539,7 +1828,7 @@ scbq_remove_head(scb_queue_type *queue)
  *
  *-F*************************************************************************/
 static inline void
-scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
   if (queue->head == scb)
   {
@@ -1580,12 +1869,11 @@ scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
  *
  *-F*************************************************************************/
 static inline void
-scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
   scb->q_next = NULL;
   if (queue->tail != NULL)       /* Add the scb at the end of the list. */
     queue->tail->q_next = scb;
-
   queue->tail = scb;             /* Update the tail. */
   if (queue->head == NULL)       /* If list was empty, update head. */
     queue->head = queue->tail;
@@ -1602,18 +1890,14 @@ scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
  *   to be reset and all devices on that channel must be aborted.
  *-F*************************************************************************/
 static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
-    int lun, unsigned char tag)
+aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+    int target, int channel, int lun, unsigned char tag)
 {
   int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
-  char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int chan = (scb->hscb->target_channel_lun >> 3) & 0x01;
   int slun = scb->hscb->target_channel_lun & 0x07;
   int match;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("scsi%d: (targ %d/chan %c) matching scb to (targ %d/chan %c)\n",
-         scb->cmd->device->host->host_no, target, channel, targ, chan);
-#endif
   match = ((chan == channel) || (channel == ALL_CHANNELS));
   if (match != 0)
     match = ((targ == target) || (target == ALL_TARGETS));
@@ -1622,6 +1906,14 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
   if (match != 0)
     match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
 
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+  {
+    printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) %s search criteria"
+      " (scsi%d:%d:%d:%d:tag%d)\n", p->host_no, CTL_OF_SCB(scb),
+      scb->hscb->tag, (match) ? "matches" : "doesn't match",
+      p->host_no, channel, target, lun, tag);
+  }
+
   return (match);
 }
 
@@ -1639,10 +1931,11 @@ aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
    * Invalidate the tag so that aic7xxx_find_scb doesn't think
    * it's active
    */
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+  aic_outb(p, 0, SCB_CONTROL);
 
-  outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
-  outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+  aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT);
+  aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH);
 }
 
 /*+F*************************************************************************
@@ -1659,28 +1952,25 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
   unsigned char next;
   unsigned char prev;
 
-  outb(scbptr, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
-  prev = inb(p->base + SCB_PREV);
-
-  outb(0, p->base + SCB_CONTROL);
-
+  aic_outb(p, scbptr, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
+  prev = aic_inb(p, SCB_PREV);
   aic7xxx_add_curscb_to_free_list(p);
 
   if (prev != SCB_LIST_NULL)
   {
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
   }
   else
   {
-    outb(next, p->base + DISCONNECTED_SCBH);
+    aic_outb(p, next, DISCONNECTED_SCBH);
   }
 
   if (next != SCB_LIST_NULL)
   {
-    outb(next, p->base + SCBPTR);
-    outb(prev, p->base + SCB_PREV);
+    aic_outb(p, next, SCBPTR);
+    aic_outb(p, prev, SCB_PREV);
   }
   return next;
 }
@@ -1692,23 +1982,10 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
  * Description:
  *   Set the specified target busy.
  *-F*************************************************************************/
-static void
-aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, unsigned char scbid)
+static __inline void
+aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  unsigned char active_scb;
-  unsigned char info_scb;
-  unsigned int  scb_offset;
-
-  info_scb = target / 4;
-  if (channel == 'B')
-    info_scb = info_scb + 2;
-
-  active_scb = inb(p->base + SCBPTR);
-  outb(info_scb, p->base + SCBPTR);
-  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
-  outb(scbid, p->base + scb_offset);
-  outb(active_scb, p->base + SCBPTR);
+  p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
 }
 
 /*+F*************************************************************************
@@ -1719,28 +1996,17 @@ aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
  *   Returns the index of the busy target, and optionally sets the
  *   target inactive.
  *-F*************************************************************************/
-static unsigned char
-aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, int unbusy)
+static __inline unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
+    int unbusy)
 {
-  unsigned char active_scb;
-  unsigned char info_scb;
   unsigned char busy_scbid;
-  unsigned int  scb_offset;
 
-  info_scb = target / 4;
-  if (channel == 'B')
-    info_scb = info_scb + 2;
-
-  active_scb = inb(p->base + SCBPTR);
-  outb(info_scb, p->base + SCBPTR);
-  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
-  busy_scbid = inb(p->base + scb_offset);
+  busy_scbid = p->untagged_scbs[tcl];
   if (unbusy)
   {
-    outb(SCB_LIST_NULL, p->base + scb_offset);
+    p->untagged_scbs[tcl] = SCB_LIST_NULL;
   }
-  outb(active_scb, p->base + SCBPTR);
   return (busy_scbid);
 }
 
@@ -1760,17 +2026,17 @@ aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   unsigned char saved_scbptr;
   unsigned char curindex;
 
-  saved_scbptr = inb(p->base + SCBPTR);
+  saved_scbptr = aic_inb(p, SCBPTR);
   curindex = 0;
   for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
   {
-    outb(curindex, p->base + SCBPTR);
-    if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+    aic_outb(p, curindex, SCBPTR);
+    if (aic_inb(p, SCB_TAG) == scb->hscb->tag)
     {
       break;
     }
   }
-  outb(saved_scbptr, p->base + SCBPTR);
+  aic_outb(p, saved_scbptr, SCBPTR);
   if (curindex >= p->scb_data->maxhscbs)
   {
     curindex = SCB_LIST_NULL;
@@ -1787,58 +2053,83 @@ aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
  *   Get an SCB from the free list or by allocating a new one.
  *-F*************************************************************************/
 static struct aic7xxx_scb *
-aic7xxx_allocate_scb(struct aic7xxx_host *p)
+aic7xxx_allocate_scb(struct aic7xxx_host *p, int force_alloc)
 {
   struct aic7xxx_scb   *scbp = NULL;
-  struct aic7xxx_hwscb *hscbp = NULL;
-#ifdef AGRESSIVE
-  long processor_flags;
+  int scb_size = sizeof(struct aic7xxx_scb) +
+                 sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+  int i;
+  unsigned long scb_count = 0;
+  struct hw_scatterlist *hsgp;
+  struct aic7xxx_scb *scb_ap;
 
-  save_flags(processor_flags);
-  cli();
-#endif
 
-  scbp = p->scb_data->free_scbs.head;
-  if (scbp != NULL)
+  if (force_alloc == FALSE)
   {
-    scbq_remove_head(&p->scb_data->free_scbs);
+    scbp = scbq_remove_head(&p->scb_data->free_scbs);
+    if (scbp != NULL)
+      return(scbp);
   }
-  else
+  /*
+   * Either there wasn't an SCB or this is a strictly allocation call
+   */
+
+  if (p->scb_data->numscbs < p->scb_data->maxscbs)
   {
-    if (p->scb_data->numscbs < p->scb_data->maxscbs)
-    {
-      int scb_index = p->scb_data->numscbs;
-      int scb_size = sizeof(struct aic7xxx_scb) +
-                     sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
 
-      scbp = kmalloc(scb_size, GFP_ATOMIC);
-      if (scbp != NULL)
+    /*
+     * Optimize for 30 scbs at a time, but allow a final allocation of
+     * fewer than 30 scbs.  Except on 64 bit platforms, we optimize for
+     * 29 SCBs at a time because a pointer is 4 bytes larger and we don't
+     * want to overrun this suppossedly 32K allocation to 64K and waste
+     * tons of space.
+     */
+    if( sizeof(void *) == sizeof(int) )
+      scb_count = MIN(30, p->scb_data->maxscbs - p->scb_data->numscbs);
+    else
+      scb_count = MIN(29, p->scb_data->maxscbs - p->scb_data->numscbs);
+    
+    scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
+    if (scb_ap != NULL)
+    {
+      if (aic7xxx_verbose & VERBOSE_QUEUE)
       {
-        memset(scbp, 0, sizeof(struct aic7xxx_scb));
-        hscbp = &p->scb_data->hscbs[scb_index];
-        scbp->hscb = hscbp;
-        scbp->sg_list = (struct hw_scatterlist *) &scbp[1];
-        memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
-        hscbp->tag = scb_index;
-        p->scb_data->numscbs++;
+        if (p->scb_data->numscbs == 0)
+          printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+            p->host_no, -1, -1, -1, scb_count);
+        else
+          printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+            p->host_no, -1, -1, -1, scb_count);
+      }
+      memset(scb_ap, 0, scb_count * scb_size);
+      hsgp = (struct hw_scatterlist *) &scb_ap[scb_count];
+      for (i=0; i < scb_count; i++)
+      {
+        scbp = &scb_ap[i];
+        scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+        scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+        memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+        scbp->hscb->tag = p->scb_data->numscbs;
         /*
          * Place in the scb array; never is removed
          */
-        p->scb_data->scb_array[scb_index] = scbp;
+        p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+        scbq_insert_head(&p->scb_data->free_scbs, scbp);
       }
     }
+    else
+    {
+      return(NULL);
+    }
   }
-#ifdef AIC7XXX_DEBUG
-  if (scbp != NULL)
+  if (force_alloc == TRUE)
   {
-    p->activescbs++;
+    return((struct aic7xxx_scb *)scb_count);
+  }
+  else
+  {
+    return(scbq_remove_head(&p->scb_data->free_scbs));
   }
-#endif
-
-#ifdef AGRESSIVE
-  restore_flags(processor_flags);
-#endif
-  return (scbp);
 }
 
 /*+F*************************************************************************
@@ -1853,11 +2144,8 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
 static inline void
 aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
-  if (p->completeq.tail == NULL)
-    p->completeq.head = cmd;
-  else
-    p->completeq.tail->host_scribble = (char *) cmd;
-  p->completeq.tail = cmd;
+  cmd->host_scribble = (char *)p->completeq.head;
+  p->completeq.head = cmd;
 }
 
 /*+F*************************************************************************
@@ -1871,16 +2159,19 @@ static inline void
 aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 {
   Scsi_Cmnd *cmd;
-
+  unsigned int cpu_flags = 0;
+  
+  DRIVER_LOCK
   while (p->completeq.head != NULL)
   {
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    p->device_status[TARGET_INDEX(cmd)].active_cmds--;
+    DRIVER_UNLOCK
     cmd->scsi_done(cmd);
+    DRIVER_LOCK
   }
-  p->completeq.tail = NULL;
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -1893,24 +2184,17 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 static void
 aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  struct aic7xxx_hwscb *hscb;
-  long flags;
-
-  hscb = scb->hscb;
-  save_flags(flags);
-  cli();
 
   scb->flags = SCB_FREE;
   scb->cmd = NULL;
-  hscb->control = 0;
-  hscb->target_status = 0;
+  scb->sg_count = 0;
+  scb->sg_length = 0;
+  scb->tag_action = 0;
+  scb->hscb->control = 0;
+  scb->hscb->target_status = 0;
+  scb->hscb->target_channel_lun = SCB_LIST_NULL;
 
   scbq_insert_head(&p->scb_data->free_scbs, scb);
-#ifdef AIC7XXX_DEBUG
-  p->activescbs--;  /* For debugging purposes. */
-#endif
-
-  restore_flags(flags);
 }
 
 /*+F*************************************************************************
@@ -1924,25 +2208,31 @@ static void
 aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   Scsi_Cmnd *cmd = scb->cmd;
+  int tindex = TARGET_INDEX(cmd);
+  struct aic7xxx_scb *scbp;
+  unsigned char queue_depth;
 
   if (scb->flags & SCB_RECOVERY_SCB)
   {
-    p->flags &= ~IN_TIMEOUT;
+    p->flags &= ~AHC_ABORT_PENDING;
   }
-  if (cmd->result == DID_OK)
+  if (scb->flags & SCB_RESET)
   {
-    if (scb->flags & SCB_ABORTED)
-    {
-      cmd->result = (DID_RESET << 16);
-    }
+      cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
+        (cmd->result & 0xffff);
+  }
+  else if (scb->flags & SCB_ABORT)
+  {
+      cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
+        (cmd->result & 0xffff);
   }
   if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
 
-    mask = 0x01 << TARGET_INDEX(scb->cmd);
-
+    mask = 0x01 << tindex;
     /*
      * Check to see if we get an invalid message or a message error
      * after failing to negotiate a wide or sync transfer message.
@@ -1959,6 +2249,17 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       p->wdtr_pending &= ~mask;
       if (message_error)
       {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Wide Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
+        }
         p->needwdtr &= ~mask;
         p->needwdtr_copy &= ~mask;
       }
@@ -1968,27 +2269,74 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       p->sdtr_pending &= ~mask;
       if (message_error)
       {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Sync Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+        }
         p->needsdtr &= ~mask;
         p->needsdtr_copy &= ~mask;
       }
     }
   }
-  aic7xxx_free_scb(p, scb);
-  aic7xxx_queue_cmd_complete(p, cmd);
+  queue_depth = p->dev_temp_queue_depth[tindex];
+  if (queue_depth >= p->dev_active_cmds[tindex])
+  {
+    scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+    if (scbp)
+      scbq_insert_tail(&p->waiting_scbs, scbp);
+    if ( (queue_depth > p->dev_active_cmds[tindex]) && scbp)
+    {
+      scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+      if (scbp)
+        scbq_insert_tail(&p->waiting_scbs, scbp);
+    }
+  }
+  if ( (p->dev_timer[tindex].expires) &&
+      ((p->dev_active_cmds[tindex] == 1) ||
+       (p->dev_max_queue_depth[tindex] ==
+        p->dev_temp_queue_depth[tindex])) )
+  {
+    del_timer(&p->dev_timer[tindex]);
+    p->dev_timer[tindex].expires = 0;
+    p->dev_temp_queue_depth[tindex] = 
+          p->dev_max_queue_depth[tindex];
+  }
+  p->dev_active_cmds[tindex]--;
+  p->activescbs--;
+
+  /*
+   * If this was an untagged I/O, unbusy the target so the sequencer won't
+   * mistake things later
+   */
+  if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
+      scb->hscb->tag)
+  {
+    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
+  }
 
 #ifdef AIC7XXX_PROC_STATS
-  if ( (cmd->cmnd[0] != TEST_UNIT_READY) &&
-       (cmd->cmnd[0] != INQUIRY) )
   {
     int actual;
 
     /*
      * XXX: we should actually know how much actually transferred
      * XXX: for each command, but apparently that's too difficult.
+     * 
+     * We set a lower limit of 512 bytes on the transfer length.  We
+     * ignore anything less than this because we don't have a real
+     * reason to count it.  Read/Writes to tapes are usually about 20K
+     * and disks are a minimum of 512 bytes unless you want to count
+     * non-read/write commands (such as TEST_UNIT_READY) which we don't
      */
-    actual = aic7xxx_length(cmd, 0);
-    if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
-        && (aic7xxx_error(cmd) == 0))
+    actual = scb->sg_length;
+    if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
     {
       struct aic7xxx_xferstats *sp;
       long *ptr;
@@ -1997,7 +2345,14 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
       sp->xfers++;
 
-      if (cmd->request.cmd == WRITE)
+      /*
+       * For block devices, cmd->request.cmd is always == either READ or
+       * WRITE.  For character devices, this isn't always set properly, so
+       * we check data_cmnd[0].  This catches the conditions for st.c, but
+       * I'm still not sure if request.cmd is valid for sg devices.
+       */
+      if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
+           (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
       {
         sp->w_total++;
         sp->w_total512 += (actual >> 9);
@@ -2024,6 +2379,10 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     }
   }
 #endif /* AIC7XXX_PROC_STATS */
+
+  aic7xxx_free_scb(p, scb);
+  aic7xxx_queue_cmd_complete(p, cmd);
+
 }
 
 /*+F*************************************************************************
@@ -2039,20 +2398,25 @@ static void
 aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
 {
   struct aic7xxx_scb *scb;
-  int i;
+  int i, found = 0;
 
   for (i = 0; i < p->scb_data->numscbs; i++)
   {
     scb = p->scb_data->scb_array[i];
     if (scb->flags & SCB_QUEUED_FOR_DONE)
     {
-#ifdef AIC7XXX_DEBUG_ABORT
-      printk("(scsi%d:%d:%d) Aborting scb %d\n",
-             p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-#endif
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Aborting scb %d\n",
+             p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+      found++;
       aic7xxx_done(p, scb);
     }
   }
+  if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN))
+  {
+    printk(INFO_LEAD "%d commands found and queued for "
+        "completion.\n", p->host_no, -1, -1, -1, found);
+  }
   if (complete)
   {
     aic7xxx_done_cmds_complete(p);
@@ -2076,14 +2440,9 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
   /*
    * Select the SCB we want to abort and pull the next pointer out of it.
    */
-  curscb = inb(p->base + SCBPTR);
-  outb(scbpos, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
-
-  /*
-   * Clear the necessary fields
-   */
-  outb(0, p->base + SCB_CONTROL);
+  curscb = aic_inb(p, SCBPTR);
+  aic_outb(p, scbpos, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
 
   aic7xxx_add_curscb_to_free_list(p);
 
@@ -2095,25 +2454,21 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
     /*
      * First in the list
      */
-    outb(next, p->base + WAITING_SCBH);
+    aic_outb(p, next, WAITING_SCBH);
   }
   else
   {
     /*
      * Select the scb that pointed to us and update its next pointer.
      */
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
   }
   /*
    * Point us back at the original scb position and inform the SCSI
    * system that the command has been aborted.
    */
-  outb(curscb, p->base + SCBPTR);
-  scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-  scb->flags &= ~SCB_ACTIVE;
-  scb->cmd->result = (DID_RESET << 16);
-
+  aic_outb(p, curscb, SCBPTR);
   return (next);
 }
 
@@ -2126,219 +2481,381 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
  *   requeue.  Returns the number of matching SCBs.
  *-F*************************************************************************/
 static int
-aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
-    int lun, unsigned char tag, int flags, int requeue)
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
+    int lun, unsigned char tag, int flags, int requeue,
+    volatile scb_queue_type *queue)
 {
-  unsigned char saved_queue[AIC7XXX_MAXSCB];
-  int      queued = inb(p->base + QINCNT) & p->qcntmask;
-  int      i;
   int      found;
+  unsigned char qinpos, qintail;
   struct aic7xxx_scb *scbp;
-  scb_queue_type removed_scbs;
 
   found = 0;
-  scbq_init (&removed_scbs);
-  for (i = 0; i < (queued - found); i++)
+  qinpos = aic_inb(p, QINPOS);
+  qintail = p->qinfifonext;
+
+  p->qinfifonext = qinpos;
+
+  while (qinpos != qintail)
   {
-    saved_queue[i] = inb(p->base + QINFIFO);
-    scbp = p->scb_data->scb_array[saved_queue[i]];
-    if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]];
+    if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
     {
        /*
         * We found an scb that needs to be removed.
         */
-       if (requeue)
+       if (requeue && (queue != NULL))
+       {
+         if ( !(scbp->flags & SCB_WAITINGQ) )
+         {
+           scbq_insert_tail(queue, scbp);
+           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
+           p->activescbs--;
+           scbp->flags |= SCB_WAITINGQ;
+         }
+         if ( !(scbp->tag_action & TAG_ENB) )
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
+       }
+       else if (requeue)
        {
-         scbq_insert_head(&removed_scbs, scbp);
+         p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
        }
        else
        {
-         scbp->flags = flags;
-         scbp->flags &= ~SCB_ACTIVE;
-         /*
-          * XXX - Don't know what error to use here.
-          */
-         aic7xxx_error(scbp->cmd) = DID_RESET;
+        /*
+         * Preserve any SCB_RECOVERY_SCB flags on this scb then set the
+         * flags we were called with, presumeably so aic7xxx_run_done_queue
+         * can find this scb
+         */
+         scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
+         if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+                                       FALSE) == scbp->hscb->tag)
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
        }
-       i--;
        found++;
     }
-  }
-  /* Now put the saved scbs back. */
-  for (queued = 0; queued < i; queued++)
-    outb(saved_queue[queued], p->base + QINFIFO);
-
-  if (requeue)
-  {
-    scbp = removed_scbs.head;
-    while (scbp != NULL)
+    else
     {
-      scbq_remove_head(&removed_scbs);
-      /*
-       * XXX - Shouldn't we be adding this to the free list?
-       */
-      scbq_insert_head(&p->waiting_scbs, scbp);
-      scbp->flags |= SCB_WAITINGQ;
-      scbp = removed_scbs.head;
+      p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
     }
   }
+  /*
+   * Now that we've done the work, clear out any left over commands in the
+   * qinfifo and update the KERNEL_QINPOS down on the card.
+   *
+   *  NOTE: This routine expect the sequencer to already be paused when
+   *        it is run....make sure it's that way!
+   */
+  qinpos = p->qinfifonext;
+  while(qinpos != qintail)
+  {
+    p->qinfifo[qinpos++] = SCB_LIST_NULL;
+  }
+  aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
 
   return (found);
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_scb_on_qoutfifo
+ *
+ * Description:
+ *   Is the scb that was passed to us currently on the qoutfifo?
+ *-F*************************************************************************/
+static int
+aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int i=0;
+
+  while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL)
+  {
+    if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag)
+      return TRUE;
+    else
+      i++;
+  }
+  return FALSE;
+}
+
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_reset_device
  *
  * Description:
  *   The device at the given target/channel has been reset.  Abort
- *   all active and queued scbs for that target/channel.
+ *   all active and queued scbs for that target/channel.  This function
+ *   need not worry about linked next pointers because if was a MSG_ABORT_TAG
+ *   then we had a tagged command (no linked next), if it was MSG_ABORT or
+ *   MSG_BUS_DEV_RESET then the device won't know about any commands any more
+ *   and no busy commands will exist, and if it was a bus reset, then nothing
+ *   knows about any linked next commands any more.  In all cases, we don't
+ *   need to worry about the linked next or busy scb, we just need to clear
+ *   them.
  *-F*************************************************************************/
-static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+static void
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
                      int lun, unsigned char tag)
 {
   struct aic7xxx_scb *scbp;
-  unsigned char active_scb;
-  int i = 0;
-  int found;
+  unsigned char active_scb, tcl;
+  int i = 0, j, init_lists = FALSE;
 
   /*
    * Restore this when we're done
    */
-  active_scb = inb(p->base + SCBPTR);
-
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
-         p->host_no, target, CHAN_TO_INT(channel), active_scb);
-#endif
+  active_scb = aic_inb(p, SCBPTR);
 
+  if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+    printk(INFO_LEAD "Reset device, active_scb %d\n",
+         p->host_no, channel, target, lun, active_scb);
   /*
    * Deal with the busy target and linked next issues.
    */
   {
     int min_target, max_target;
-    unsigned char busy_scbid;
+    struct aic7xxx_scb *scbp, *prev_scbp;
 
     /* Make all targets 'relative' to bus A. */
     if (target == ALL_TARGETS)
     {
       switch (channel)
       {
-        case 'A':
-         min_target = 0;
-         max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-         break;
-        case 'B':
-         min_target = 8;
-         max_target = 15;
-         break;
+        case 0:
+                 min_target = 0;
+                 max_target = (p->type & AHC_WIDE) ? 15 : 7;
+                 break;
+        case 1:
+                 min_target = 8;
+                 max_target = 15;
+                 break;
         case ALL_CHANNELS:
         default:
-         min_target = 0;
-         max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-         break;
+                 min_target = 0;
+                 max_target = (p->type & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
+                 break;
       }
     }
     else
     { 
-      min_target = target + channel == 'B' ? 8 : 0;
+      min_target = target | (channel << 3);
       max_target = min_target;
     }
 
+
     for (i = min_target; i <= max_target; i++)
     {
-      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
-      if (busy_scbid < p->scb_data->numscbs)
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Cleaning up status information "
+          "and delayed_scbs.\n", p->host_no, channel, i, lun);
+      if ( !(p->dev_flags[i] & DEVICE_TAGGED_SUCCESS) &&
+            (p->dev_active_cmds[i]) &&
+            (p->tagenable & (0x01 << i)) )
       {
-       struct aic7xxx_scb *busy_scb;
-       struct aic7xxx_scb *next_scb;
-       unsigned char next_scbid;
-
-       busy_scb = p->scb_data->scb_array[busy_scbid];
-  
-       next_scbid = le32_to_cpu(busy_scb->hscb->data_count) >> 24;
-
-       if (next_scbid == SCB_LIST_NULL)
+        printk(INFO_LEAD "Device appears to be choking on tagged commands.\n",
+          p->host_no, channel, i, lun);
+        printk(INFO_LEAD "Will use untagged I/O instead.\n", p->host_no,
+          channel, i, lun);
+        p->dev_max_queue_depth[i] = 1;
+        p->dev_temp_queue_depth[i] = 1;
+        p->tagenable &= ~(0x01 << i);
+        p->orderedtag &= ~(0x01 << i);
+      }
+      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+      if ( tag == SCB_LIST_NULL )
+      {
+        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+        p->dev_last_reset[i] = jiffies;
+        p->dev_last_queue_full_count[i] = 0;
+        p->dev_last_queue_full[i] = 0;
+        p->dev_temp_queue_depth[i] =
+          p->dev_max_queue_depth[i];
+  /*
+   * In case this isn't a full bus reset, we want to add a 4 second timer in
+   * here so that we can delay all re-sent commands for this device for the
+   * 4 seconds and then have our timer routine pick them back up.
+   */
+        if( (p->dev_timer[i].prev != NULL) ||
+            (p->dev_timer[i].next != NULL) )
         {
-         busy_scbid = aic7xxx_find_scb(p, busy_scb);
-
-         if (busy_scbid != SCB_LIST_NULL)
-          {
-           outb(busy_scbid, p->base + SCBPTR);
-           next_scbid = inb(p->base + SCB_LINKED_NEXT);
-         }
-       }
-
-       if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
+          del_timer(&p->dev_timer[i]);
+        }
+        p->dev_timer[i].expires = jiffies + (3 * HZ);
+        add_timer(&p->dev_timer[i]);
+      }
+      for(j=0; j<MAX_LUNS; j++)
+      {
+        if (channel == 1)
+          tcl = ((i << 4) & 0x70) | (channel << 3) | j;
+        else
+          tcl = (i << 4) | (channel << 3) | j;
+        if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
+             (tag == SCB_LIST_NULL) )
+          aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
+      }
+      j = 0; 
+      prev_scbp = NULL; 
+      scbp = p->delayed_scbs[i].head;
+      while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+      {
+        prev_scbp = scbp;
+        scbp = scbp->q_next;
+        if ( prev_scbp == scbp )
         {
-         aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
-       }
-
-       if (next_scbid != SCB_LIST_NULL)
+          if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+            printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+              "in the delayed_scbs queue!\n", p->host_no, channel, i, lun);
+          scbp = NULL;
+          prev_scbp->q_next = NULL;
+          p->delayed_scbs[i].tail = prev_scbp;
+        }
+        if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
         {
-         next_scb = p->scb_data->scb_array[next_scbid];
-         if (aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+          scbq_remove(&p->delayed_scbs[i], prev_scbp);
+          if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
           {
-           continue;
+            p->dev_active_cmds[i]++;
+            p->activescbs++;
           }
-         /* Requeue for later processing */
-         scbq_insert_head(&p->waiting_scbs, next_scb);
-         next_scb->flags |= SCB_WAITINGQ;
-       }
+          prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+        }
+      }
+      if ( j > p->scb_data->numscbs )
+      {
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! There's a loop in the "
+            "delayed_scbs queue!\n", p->host_no, channel, i, lun);
+        scbq_init(&p->delayed_scbs[i]);
+      }
+      if ( (p->delayed_scbs[i].head == NULL) &&
+           (p->dev_timer[i].expires) )
+      {
+        del_timer(&p->dev_timer[i]);
+        p->dev_timer[i].expires = 0;
+      }
+    }
+  }
+
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
+  aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+      SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
+
+/*
+ *  Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
+ *  ABORT/RESET commands.
+ */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel,
+      target, lun );
+  {
+    struct aic7xxx_scb *scbp, *prev_scbp;
+
+    j = 0; 
+    prev_scbp = NULL; 
+    scbp = p->waiting_scbs.head;
+    while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+    {
+      prev_scbp = scbp;
+      scbp = scbp->q_next;
+      if ( prev_scbp == scbp )
+      {
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+            "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp));
+        scbp = NULL;
+        prev_scbp->q_next = NULL;
+        p->waiting_scbs.tail = prev_scbp;
+      }
+      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+      {
+        scbq_remove(&p->waiting_scbs, prev_scbp);
+        if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
+        {
+          p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
+          p->activescbs++;
+        }
+        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
+    if ( j > p->scb_data->numscbs )
+    {
+      if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+        printk(WARN_LEAD "Yikes!! There's a loop in the "
+          "waiting_scbs queue!\n", p->host_no, channel, target, lun);
+      scbq_init(&p->waiting_scbs);
+    }
   }
 
-  found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
-      SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
 
   /*
    * Search waiting for selection list.
    */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting for selection "
+      "list.\n", p->host_no, channel, target, lun);
   {
     unsigned char next, prev, scb_index;
 
-    next = inb(p->base + WAITING_SCBH);  /* Start at head of list. */
+    next = aic_inb(p, WAITING_SCBH);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
-
-    while (next != SCB_LIST_NULL)
+    j = 0;
+    while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
       if (scb_index >= p->scb_data->numscbs)
       {
-        panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
-              scb_index, p->scb_data->numscbs);
+       /*
+        * No aic7xxx_verbose check here.....we want to see this since it
+        * means either the kernel driver or the sequencer screwed things up
+        */
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic_inb(p, SCB_NEXT);
+        aic7xxx_add_curscb_to_free_list(p);
       }
-      scbp = p->scb_data->scb_array[scb_index];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      else
       {
-        unsigned char linked_next;
-
-        next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
-        linked_next = inb(p->base + SCB_LINKED_NEXT);
-        if (linked_next != SCB_LIST_NULL)
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
-          struct aic7xxx_scb *next_scb;
-          /*
-           * Requeue the waiting SCB via the waiting list.
-           */
-          next_scb = p->scb_data->scb_array[linked_next];
-          if (! aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+          next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          if (prev == SCB_LIST_NULL)
           {
-            scbq_insert_head(&p->waiting_scbs, next_scb);
-            next_scb->flags |= SCB_WAITINGQ;
+            /*
+             * This is either the first scb on the waiting list, or we
+             * have already yanked the first and haven't left any behind.
+             * Either way, we need to turn off the selection hardware if
+             * it isn't already off.
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
           }
         }
-        found++;
-      }
-      else
-      {
-        prev = next;
-        next = inb(p->base + SCB_NEXT);
+        else
+        {
+          prev = next;
+          next = aic_inb(p, SCB_NEXT);
+        }
       }
     }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the waiting for "
+        "selection list!\n", p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
   }
 
   /*
@@ -2348,47 +2865,114 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
   {
     unsigned char next, prev, scb_index;
 
-    next = inb(p->base + DISCONNECTED_SCBH);
+    next = aic_inb(p, DISCONNECTED_SCBH);
     prev = SCB_LIST_NULL;
-
-    while (next != SCB_LIST_NULL)
+    j = 0;
+    while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
       if (scb_index > p->scb_data->numscbs)
       {
-        panic("aic7xxx: Disconnected List inconsistency, SCB index = %d, "
-              "num scbs = %d.\n", scb_index, p->scb_data->numscbs);
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic7xxx_rem_scb_from_disc_list(p, next);
+      }
+      else
+      {
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          next = aic7xxx_rem_scb_from_disc_list(p, next);
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          scbp->hscb->control = 0;
+        }
+        else
+        {
+          prev = next;
+          next = aic_inb(p, SCB_NEXT);
+        }
       }
-      scbp = p->scb_data->scb_array[scb_index];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the disconnected list!\n",
+        p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
+  }
+
+  /*
+   * Walk the free list making sure no entries on the free list have
+   * a valid SCB_TAG value or SCB_CONTROL byte.
+   */
+  {
+    unsigned char next;
+
+    j = 0;
+    next = aic_inb(p, FREE_SCBH);
+    while ( (next != SCB_LIST_NULL) && (j++ < p->scb_data->maxhscbs) )
+    {
+      aic_outb(p, next, SCBPTR);
+      if ( aic_inb(p, SCB_TAG) < p->scb_data->numscbs )
       {
-        next = aic7xxx_rem_scb_from_disc_list(p, next);
+        printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
+          target, lun);
+        init_lists = TRUE;
+        next = SCB_LIST_NULL;
       }
       else
       {
-        prev = next;
-        next = inb(p->base + SCB_NEXT);
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        next = aic_inb(p, SCB_NEXT);
       }
     }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the free list!\n",
+        p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
   }
 
   /*
    * Go through the hardware SCB array looking for commands that
    * were active but not on any list.
    */
-  for (i = 0; i < p->scb_data->maxhscbs; i++)
+  if (init_lists)
+  {
+    aic_outb(p, SCB_LIST_NULL, FREE_SCBH);
+    aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+    aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
+  }
+  for (i = p->scb_data->maxhscbs; i >= 0; --i)
   {
     unsigned char scbid;
 
-    outb(i, p->base + SCBPTR);
-    scbid = inb(p->base + SCB_TAG);
-    if (scbid < p->scb_data->numscbs)
+    aic_outb(p, i, SCBPTR);
+    if (init_lists)
+    {
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+      aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+      aic_outb(p, SCB_LIST_NULL, SCB_PREV);
+      aic_outb(p, 0, SCB_CONTROL);
+      aic7xxx_add_curscb_to_free_list(p);
+    }
+    else
     {
-      scbp = p->scb_data->scb_array[scbid];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      scbid = aic_inb(p, SCB_TAG);
+      if (scbid < p->scb_data->numscbs)
       {
-        aic7xxx_add_curscb_to_free_list(p);
+        scbp = p->scb_data->scb_array[scbid];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          aic_outb(p, 0, SCB_CONTROL);
+          aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+          aic7xxx_add_curscb_to_free_list(p);
+        }
       }
     }
   }
@@ -2397,31 +2981,28 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
    * Go through the entire SCB array now and look for commands for
    * for this target that are stillactive.  These are other (most likely
    * tagged) commands that were disconnected when the reset occurred.
+   * Any commands we find here we know this about, it wasn't on any queue,
+   * it wasn't in the qinfifo, it wasn't in the disconnected or waiting
+   * lists, so it really must have been a paged out SCB.  In that case,
+   * we shouldn't need to bother with updating any counters, just mark
+   * the correct flags and go on.
    */
   for (i = 0; i < p->scb_data->numscbs; i++)
   {
     scbp = p->scb_data->scb_array[i];
-    if (((scbp->flags & SCB_ACTIVE) != 0) &&
-        aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    if ((scbp->flags & SCB_ACTIVE) &&
+        aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
+        !aic7xxx_scb_on_qoutfifo(p, scbp))
     {
-      scbp->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-      scbp->flags &= ~SCB_ACTIVE;
-      aic7xxx_error(scbp->cmd) = DID_RESET;
+      scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+    }
+  }
 
-      found++;
-
-      if ((scbp->flags & SCB_WAITINGQ) != 0)
-      {
-        scbq_remove(&p->waiting_scbs, scbp);
-        scbp->flags &= ~SCB_WAITINGQ;
-      }
-    }
-  }
-
-  outb(active_scb, p->base + SCBPTR);
-  return (found);
+  aic_outb(p, active_scb, SCBPTR);
 }
 
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_clear_intstat
@@ -2433,10 +3014,10 @@ static void
 aic7xxx_clear_intstat(struct aic7xxx_host *p)
 {
   /* Clear any interrupt conditions this may have caused. */
-  outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
-  outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
-       CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
-  outb(CLRSCSIINT, p->base + CLRINT);
+  aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0);
+  aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+       CLRPHASECHG | CLRREQINIT, CLRSINT1);
+  aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT, CLRINT);
 }
 
 /*+F*************************************************************************
@@ -2449,32 +3030,26 @@ aic7xxx_clear_intstat(struct aic7xxx_host *p)
 static void
 aic7xxx_reset_current_bus(struct aic7xxx_host *p)
 {
-  unsigned long processor_flags;
   unsigned char scsiseq;
 
-  save_flags(processor_flags);
-  cli();
-
   /* Disable reset interrupts. */
-  outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+  aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
 
   /* Turn on the bus reset. */
-  scsiseq = inb(p->base + SCSISEQ);
-  outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+  scsiseq = aic_inb(p, SCSISEQ);
+  aic_outb(p, scsiseq | SCSIRSTO, SCSISEQ);
 
   udelay(1000);
 
   /* Turn off the bus reset. */
-  outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+  aic_outb(p, scsiseq & ~SCSIRSTO, SCSISEQ);
 
   aic7xxx_clear_intstat(p);
 
   /* Re-enable reset interrupts. */
-  outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+  aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1);
 
   udelay(1000);
-
-  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -2484,22 +3059,19 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
  * Description:
  *   Reset the channel.
  *-F*************************************************************************/
-static int
-aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
+static void
+aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
 {
   unsigned long offset, offset_max;
-  int found;
   unsigned char sblkctl;
-  char cur_channel;
+  int cur_channel;
+
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Reset channel called, %s initiate reset.\n",
+      p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" );
 
-  pause_sequencer(p);
-  /*
-   * Clean up all the state information for the pending transactions
-   * on this bus.
-   */
-  found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
-  if (channel == 'B')
+  if (channel == 1)
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
@@ -2508,7 +3080,7 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
   }
   else
   {
-    if (p->bus_type == AIC_WIDE)
+    if (p->type & AHC_WIDE)
     {
       p->needsdtr = p->needsdtr_copy;
       p->needwdtr = p->needwdtr_copy;
@@ -2534,80 +3106,77 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
      */
     u_char targ_scratch;
 
-    targ_scratch = inb(p->base + offset);
+    targ_scratch = aic_inb(p, offset);
     targ_scratch &= SXFR;
-    outb(targ_scratch, p->base + offset);
-    offset++;
+    aic_outb(p, targ_scratch, offset++);
   }
 
   /*
    * Reset the bus and unpause/restart the controller
    */
-  sblkctl = inb(p->base + SBLKCTL);
-  cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
+  sblkctl = aic_inb(p, SBLKCTL);
+  cur_channel = (sblkctl & SELBUSB) >> 3;
   if (cur_channel != channel)
   {
     /*
      * Case 1: Command for another bus is active
      */
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Stealthily resetting channel %c\n",
-           p->host_no, channel);
-#endif
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no,
+        channel, -1, -1);
     /*
      * Stealthily reset the other bus without upsetting the current bus.
      */
-    outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1);
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
-      /*
-       * Cause the mid-level SCSI code to delay any further 
-       * queueing by the bus settle time for us.
-       */
-      p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
     }
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     aic7xxx_clear_intstat(p);
-    outb(sblkctl, p->base + SBLKCTL);
-    unpause_sequencer(p, /* unpause_always */ FALSE);
+    aic_outb(p, sblkctl, SBLKCTL);
   }
   else
   {
     /*
      * Case 2: A command from this bus is active or we're idle.
      */
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Resetting current channel %c\n",
-           p->host_no, channel);
-#endif
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
+        channel, -1, -1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    p->msg_type = MSG_TYPE_NONE;
+    p->msg_len = 0;
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
-      /*
-       * Cause the mid-level SCSI code to delay any further 
-       * queueing by the bus settle time for us.
-       */
-#if 0
-      p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
-#endif
     }
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     aic7xxx_clear_intstat(p);
+  }
+  if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+    printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1);
+  /*
+   * Clean up all the state information for the pending transactions
+   * on this bus.
+   */
+  aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
+
+  if ( !(p->type & AHC_TWIN) )
+  {
     restart_sequencer(p);
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
-#endif
   }
 
   /*
    * Now loop through all the SCBs that have been marked for abortion,
    * and call the scsi_done routines.
    */
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
-  return (found);
+  if(!(p->flags & AHC_IN_ISR))
+    aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+  return;
 }
 
 /*+F*************************************************************************
@@ -2622,47 +3191,98 @@ static inline void
 aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb;
+  int tindex;
+  int sent;
+  unsigned long cpu_flags = 0;
+
 
   if (p->waiting_scbs.head == NULL)
     return;
 
-  pause_sequencer(p);
+  sent = 0;
+
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
-  scb = p->waiting_scbs.head;
-  while (scb != NULL)
+  DRIVER_LOCK
+  while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
   {
-    if (p->curqincnt >= p->qfullcount)
+    tindex = TARGET_INDEX(scb->cmd);
+    if ( (p->dev_active_cmds[tindex] >=
+          p->dev_temp_queue_depth[tindex]) ||
+         (p->dev_last_reset[tindex] >= (jiffies + (3 * HZ))) )
     {
-      p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
-      if (p->curqincnt >= p->qfullcount)
-      {
-        break;
-      }
+        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
     }
+    else
+    {
+        scb->flags &= ~SCB_WAITINGQ;
+        if ( !(scb->flags & SCB_QUEUED_ABORT) )
+        {
+          p->dev_active_cmds[tindex]++;
+          p->activescbs++;
+        }
+        if ( !(scb->tag_action) )
+        {
+          aic7xxx_busy_target(p, scb);
+        }
+        p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+        sent++;
+    }
+  }
+  if (sent)
+  {
+    if(p->type & AHC_AIC78x0)
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    else
+    {
+      pause_sequencer(p);
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      unpause_sequencer(p, FALSE);
+    }
+    if (p->activescbs > p->max_activescbs)
+      p->max_activescbs = p->activescbs;
+  }
+  DRIVER_UNLOCK
+}
 
-    /*
-     * We have some space.
-     */
-    scbq_remove_head(&(p->waiting_scbs));
-    scb->flags &= ~SCB_WAITINGQ;
-
-    outb(scb->hscb->tag, p->base + QINFIFO);
 
-    if ((p->flags & PAGE_ENABLED) != 0)
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_timer
+ *
+ * Description:
+ *   Take expired extries off of delayed queues and place on waiting queue
+ *   then run waiting queue to start commands.
+ ***************************************************************************/
+static void
+aic7xxx_timer(struct aic7xxx_host *p)
+{
+  int i;
+  unsigned long cpu_flags = 0;
+  struct aic7xxx_scb *scb;
+   
+  DRIVER_LOCK
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if ( (p->dev_timer[i].expires) && 
+          (p->dev_timer[i].expires <= jiffies) )
     {
-      /*
-       * We only care about this statistic when paging
-       * since it's impossible to overflow the qinfifo
-       * in the non-paging case.
-       */
-      p->curqincnt++;
+      p->dev_timer[i].expires = 0;
+      if ( (p->dev_timer[i].prev != NULL) ||
+           (p->dev_timer[i].next != NULL) )
+      {
+        del_timer(&p->dev_timer[i]);
+      }
+      p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
+      while ( (scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL )
+      {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+      }
     }
-    scb = p->waiting_scbs.head;
   }
-
-  unpause_sequencer(p, FALSE);
+  aic7xxx_run_waiting_queues(p);
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -2674,15 +3294,15 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
  *   buffer on the sequencer.
  *-F*************************************************************************/
 static void
-aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char period, unsigned char offset)
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period,
+        unsigned char offset)
 {
-  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
-  outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
-  outb(MSG_EXT_SDTR,     p->base + MSG_OUT + 2 + start_byte);
-  outb(period,           p->base + MSG_OUT + 3 + start_byte);
-  outb(offset,           p->base + MSG_OUT + 4 + start_byte);
-  outb(start_byte + 5,   p->base + MSG_LEN);
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR;
+  p->msg_buf[p->msg_index++] = period;
+  p->msg_buf[p->msg_index++] = offset;
+  p->msg_len += 5;
 }
 
 /*+F*************************************************************************
@@ -2694,14 +3314,13 @@ aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
  *   on the sequencer.
  *-F*************************************************************************/
 static void
-aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char bus_width)
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
 {
-  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
-  outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
-  outb(MSG_EXT_WDTR,     p->base + MSG_OUT + 2 + start_byte);
-  outb(bus_width,        p->base + MSG_OUT + 3 + start_byte);
-  outb(start_byte + 4,   p->base + MSG_LEN);
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR;
+  p->msg_buf[p->msg_index++] = bus_width;
+  p->msg_len += 4;
 }
 
 /*+F*************************************************************************
@@ -2716,7 +3335,7 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   struct aic7xxx_hwscb *hscb;
   Scsi_Cmnd *cmd;
-  int actual;
+  int actual, i;
 
   cmd = scb->cmd;
   hscb = scb->hscb;
@@ -2734,18 +3353,22 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
      *  and cmd->underflow seems to be set rather half-
      *  heartedly in the higher-level SCSI code.
      */
-    actual = aic7xxx_length(cmd, hscb->residual_SG_segment_count);
-
+    actual = scb->sg_length;
+    for (i=1; i < hscb->residual_SG_segment_count; i++)
+    {
+      actual -= scb->sg_list[scb->sg_count - i].length;
+    }
     actual -= (hscb->residual_data_count[2] << 16) |
               (hscb->residual_data_count[1] <<  8) |
               hscb->residual_data_count[0];
 
     if (actual < cmd->underflow)
     {
-      printk(KERN_WARNING "(scsi%d:%d:%d) Underflow - "
-             "Wanted at least %u, got %u, residual SG count %d.\n",
-             p->host_no, TC_OF_SCB(scb), cmd->underflow, actual,
-             hscb->residual_SG_segment_count);
+      if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
+          "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
+          (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
+          hscb->residual_SG_segment_count);
       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
       aic7xxx_status(cmd) = hscb->target_status;
     }
@@ -2769,31 +3392,29 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
  *   Interrupt handler for sequencer interrupts (SEQINT).
  *-F*************************************************************************/
 static void
-aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
 {
   unsigned short targ_mask;
   unsigned char  targ_scratch;
   int scratch_offset = target;
-  int found;
 
-  if (channel == 'B')
-  {
-    scratch_offset += 8;
-  }
+  scratch_offset += channel << 3;
+
   targ_mask = (0x01 << scratch_offset);
   /*
    * Go back to async/narrow transfers and renegotiate.
    */
-  p->needsdtr |= p->needsdtr_copy & targ_mask;
-  p->needwdtr |= p->needwdtr_copy & targ_mask;
+  p->needsdtr |= (p->needsdtr_copy & targ_mask);
+  p->needwdtr |= (p->needwdtr_copy & targ_mask);
   p->sdtr_pending &= ~targ_mask;
   p->wdtr_pending &= ~targ_mask;
-  targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+  targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
   targ_scratch &= SXFR;
-  outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-  found = aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
-  printk(KERN_WARNING "(scsi%d:%d:%d) Bus Device Reset delivered, "
-         "%d SCBs aborted.\n", p->host_no, target, CHAN_TO_INT(channel), found);
+  aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+  aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
+      target, -1);
   aic7xxx_run_done_queue(p, /*complete*/ TRUE);
 }
 
@@ -2809,107 +3430,35 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 {
   struct aic7xxx_scb *scb;
   unsigned short target_mask;
-  unsigned char target, scratch_offset;
+  unsigned char target, scratch_offset, lun;
+  unsigned char queue_flag = FALSE;
   char channel;
 
-  if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
-  {
-    target = (inb(p->base + SELID) >> 4) & 0x0F;
-  }
-  else
-  {
-    target = (inb(p->base + SCSIID) >> 4) & 0x0F;
-  }
-  scratch_offset = target;
-  channel = 'A';
-  if (inb(p->base + SBLKCTL) & SELBUSB)
-  {
-    channel = 'B';
-    scratch_offset += 8;
-  }
+  target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
+  channel = (aic_inb(p, SBLKCTL) >> 3) & 0x01;
+  scratch_offset = target + (channel << 3);
+  lun = aic_inb(p, SAVED_TCL) & 0x07;
   target_mask = (0x01 << scratch_offset);
 
   switch (intstat & SEQINT_MASK)
   {
     case NO_MATCH:
       {
-        /*
-         * This could be for a normal abort request.  Figure out
-         * which SCB we were trying to find and only give an error
-         * if we didn't ask for this to happen.
-         */
-        unsigned char scb_index;
-        unsigned char busy_scbid;
-        unsigned char arg1;
-
-        busy_scbid = aic7xxx_index_busy_target(p, target, channel,
-            /*unbusy*/ FALSE);
-        arg1 = inb(p->base + ARG_1);
-
-        if (arg1 == SCB_LIST_NULL)
-        {
-          /* untagged request */
-          scb_index = busy_scbid;
-        }
-        else
-        {
-          scb_index = arg1;
-        }
-
-        if (scb_index < p->scb_data->numscbs)
-        {
-          scb = p->scb_data->scb_array[scb_index];
-          if (scb->hscb->control & ABORT_SCB)
-          {
-            /*
-             * We expected this.  Let the busfree handler take care
-             * of this when we the abort is finially sent.  Set
-             * IDENTIFY_SEEN so that the busfree handler knows that
-             * there is an SCB to cleanup.
-             */
-            outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
-            printk(KERN_INFO "(scsi%d:%d:%d) reconnect SCB abort successful\n",
-                   p->host_no, TC_OF_SCB(scb));
-            break;
-          }
-        }
-        printk(KERN_WARNING "(scsi%d:%d:%d) No active SCB for reconnecting "
-               "target - Issuing BUS DEVICE RESET.\n",
-               p->host_no, target, CHAN_TO_INT(channel));
-
-        printk(KERN_WARNING "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
-               inb(p->base + SAVED_TCL), arg1,
-               (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-        aic7xxx_handle_device_reset(p, target, channel);
-      }
-      break;
-
-    case NO_MATCH_BUSY:
-      {
-        /*
-         * XXX - Leave this as a panic for the time being since it
-         * indicates a bug in the timeout code for this to happen.
-         */
-        unsigned char scb_index;
-
-        scb_index = inb(p->base + CUR_SCBID);
-        scb = p->scb_data->scb_array[scb_index];
-
-        panic("scsi%d:  Target %d, channel %c, Target busy link failure, "
-              "but busy SCB exists!\n",
-              p->host_no, target, channel);
+        printk(WARN_LEAD "No active SCB for reconnecting target - Issuing "
+               "BUS DEVICE RESET.\n", p->host_no, channel, target, lun);
+        printk(WARN_LEAD "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+               p->host_no, channel, target, lun,
+               aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
+               (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
       }
       break;
 
     case SEND_REJECT:
       {
-        unsigned char rej_byte;
-
-        rej_byte = inb(p->base + REJBYTE);
-        printk(KERN_WARNING "(scsi%d:%d:%d) Rejecting unknown message (0x%x) "
-               "received from target, SEQ_FLAGS=0x%x\n",
-               p->host_no, target, CHAN_TO_INT(channel), rej_byte,
-               inb(p->base + SEQ_FLAGS));
+        if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Rejecting unknown message (0x%x) received from "
+            "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun,
+            aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS));
       }
       break;
 
@@ -2917,559 +3466,652 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
       {
         /*
          * The reconnecting target either did not send an identify
-         * message, or did, but we didn't find and SCB to match and
+         * message, or did, but we didn't find an SCB to match and
          * before it could respond to our ATN/abort, it hit a dataphase.
          * The only safe thing to do is to blow it away with a bus
          * reset.
          */
-        int found;
+        if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID))
+          printk(INFO_LEAD "Target did not send an IDENTIFY message; "
+            "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target,
+            lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
 
-        printk(KERN_WARNING "(scsi%d:%d:%d): Target did not send an IDENTIFY "
-               "message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
-               p->host_no, target, CHAN_TO_INT(channel),
-               inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
+        aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
 
-        found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
-
-        printk(KERN_WARNING "scsi%d: Issued channel %c bus reset; "
-              "%d SCBs aborted\n", p->host_no, channel, found);
       }
       break;
 
     case BAD_PHASE:
-      if (inb(p->base + LASTPHASE) == P_BUSFREE)
+      if (aic_inb(p, LASTPHASE) == P_BUSFREE)
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
-               p->host_no, CHAN_TO_INT(channel), target);
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel,
+            target, lun);
         restart_sequencer(p);
       }
       else
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d): Unknown scsi bus phase, attempting "
-               "to continue\n", p->host_no, CHAN_TO_INT(channel), target);
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no,
+            channel, target, lun);
       }
       break;
 
     case EXTENDED_MSG:
       {
-       unsigned char message_length;
-       unsigned char message_code;
-        unsigned char scb_index;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+        p->msg_len = 0;
+        p->msg_index = 0;
 
-       message_length = inb(p->base + MSGIN_EXT_LEN);
-       message_code = inb(p->base + MSGIN_EXT_OPCODE);
-        scb_index = inb(p->base + SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
+       /*
+        * We have to clear the SEQINT *BEFORE* we set the REQINIT handler
+        * active or else VLB and edge triggered EISA cards could loose the
+        * first REQINIT and cause a bus hang/reset cycle.
+        */
+        aic_outb(p, CLRSEQINT, CLRINT);
 
-       switch (message_code)
-       {
-          case MSG_EXT_SDTR:
-          {
-            unsigned char period;
-            unsigned char offset;
-            unsigned char saved_offset;
-            unsigned char targ_scratch;
-            unsigned char max_offset;
-            unsigned char rate;
-
-            if (message_length != MSG_EXT_SDTR_LEN)
-            {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
-            }
+       /*      
+        * To actually receive the message, simply turn on
+        * REQINIT interrupts and let our interrupt handler
+        * do the rest (REQINIT should already be true).
+        */
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
 
-            period = inb(p->base + MSGIN_EXT_BYTES);
-            saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
-            targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+       /*
+        * We don't want the sequencer unpaused yet so we return early
+        */
+        return;
+      }
 
-            if (targ_scratch & WIDEXFER)
-              max_offset = MAX_OFFSET_16BIT;
-            else
-              max_offset = MAX_OFFSET_8BIT;
-            offset = MIN(saved_offset, max_offset);
+    case REJECT_MSG:
+      {
+        /*
+         * What we care about here is if we had an outstanding SDTR
+         * or WDTR message for this target. If we did, this is a
+         * signal that the target is refusing negotiation.
+         */
+        unsigned char targ_scratch;
+        unsigned char scb_index;
+        unsigned char last_msg;
 
-            aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+        targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+        last_msg = aic_inb(p, LAST_MSG);
 
+        if ( (last_msg == MSG_IDENTIFYFLAG) &&
+             (scb->tag_action != 0 ) &&
+             !(p->flags & AHC_HANDLING_REQINITS) )
+        {
+          if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
+              (p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS))
+          {
             /*
-             * Preserve the WideXfer flag.
+             * OK...the device seems able to accept tagged commands, but
+             * not ordered tag commands, only simple tag commands.  So, we
+             * disable ordered tag commands and go on with life just like
+             * normal.
              */
-            targ_scratch = rate | (targ_scratch & WIDEXFER);
-
+            p->orderedtag &= ~target_mask;
+            scb->tag_action = MSG_SIMPLE_Q_TAG;
+            scb->hscb->control &= ~SCB_TAG_TYPE;
+            scb->hscb->control |= MSG_SIMPLE_Q_TAG;
+            aic_outb(p, scb->hscb->control, SCB_CONTROL);
             /*
-             * Update both the target scratch area and current SCSIRATE.
+             * OK..we set the tag type to simple tag command, now we re-assert
+             * ATNO and hope this will take us into the identify phase again
+             * so we can resend the tag type and info to the device.
              */
-            outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(targ_scratch, p->base + SCSIRATE);
-
+          }
+          else
+          {
+            unsigned char i, reset = 0;
+            struct aic7xxx_scb *scbp;
+            int old_verbose;
             /*
-             * See if we initiated Sync Negotiation and didn't have
-             * have to fall down to async transfers.
+             * Hmmmm....the device is flaking out on tagged commands.  The
+             * bad thing is that we already have tagged commands enabled in
+             * the device struct in the mid level code.  We also have a queue
+             * set according to the tagged queue depth.  Gonna have to live
+             * with it by controlling our queue depth internally and making
+             * sure we don't set the tagged command flag any more.
              */
-            if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
-            {
-              /* We started it. */
-              if (saved_offset == offset)
-              {
-               /*
-                * Don't send an SDTR back to the target.
-                */
-               outb(0, p->base + RETURN_1);
-              }
-              else
-              {
-               /* We went too low - force async. */
-               outb(SEND_REJ, p->base + RETURN_1);
-              }
-            }
-            else
-            {
-              /*
-               * Send our own SDTR in reply.
-               *
-               * We want to see this message as we don't expect a target
-               * to send us a SDTR request first.
-               */
-              printk(KERN_WARNING "scsi%d: Sending SDTR!!\n", p->host_no);
-              aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
-              outb(SEND_MSG, p->base + RETURN_1);
-            }
+            p->tagenable &= ~target_mask;
+            p->orderedtag &= ~target_mask;
+            p->dev_max_queue_depth[scratch_offset] =
+               p->dev_temp_queue_depth[scratch_offset] = 1;
             /*
-             * Clear the flags.
+             * We set this command up as a bus device reset.  However, we have
+             * to clear the tag type as it's causing us problems.  We shouldnt
+             * have to worry about any other commands being active, since if
+             * the device is refusing tagged commands, this should be the
+             * first tagged command sent to the device, however, we do have
+             * to worry about any other tagged commands that may already be
+             * in the qinfifo.  The easiest way to do this, is to issue a BDR,
+             * send all the commands back to the mid level code, then let them
+             * come back and get rebuilt as untagged commands.
              */
-            p->needsdtr &= ~target_mask;
-            break;
-          }
-
-          case MSG_EXT_WDTR:
-          {
-            unsigned char scratch, bus_width;
-
-            if (message_length != MSG_EXT_WDTR_LEN)
-            {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
-            }
-
-            bus_width = inb(p->base + MSGIN_EXT_BYTES);
-            scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
-            if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
-            {
-              /*
-               * Don't send an WDTR back to the target, since we asked first.
-               */
-              outb(0, p->base + RETURN_1);
-              switch (bus_width)
-              {
-               case BUS_8_BIT:
-                 scratch &= 0x7F;
-                 break;
-
-               case BUS_16_BIT:
-                  if (aic7xxx_verbose)
-                  {
-                   printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
-                        "bit transfers.\n", p->host_no, target, channel);
-                  }
-                 scratch |= WIDEXFER;
-                 break;
-
-               case BUS_32_BIT:
-                 outb(SEND_REJ, p->base + RETURN_1);
-                  /* No verbose here!  We want to see this condition. */
-                 printk(KERN_WARNING "scsi%d: Target %d, channel %c, "
-                       "requesting 32 bit transfers, rejecting...\n",
-                        p->host_no, target, channel);
-                 break;
-
-               default:
-                 break;
-              }
-            }
-            else
+            scb->tag_action = 0;
+            scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
+            scb->hscb->control |= MK_MESSAGE;
+            aic_outb(p,  scb->hscb->control, SCB_CONTROL);
+
+            old_verbose = aic7xxx_verbose;
+            aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
+            for (i=0; i!=p->scb_data->numscbs; i++)
             {
-              int send_reject = FALSE;
-
-              /*
-               * Send our own WDTR in reply.
-               */
-              switch (bus_width)
-              {
-               case BUS_8_BIT:
-                 scratch &= 0x7F;
-                 break;
-
-               case BUS_32_BIT:
-               case BUS_16_BIT:
-                 if (p->bus_type == AIC_WIDE)
-                 {
-                    printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
-                          "bit transfers.\n", p->host_no, target, channel);
-                    bus_width = BUS_16_BIT;
-                    scratch |= WIDEXFER;
-                 }
-                 else
-                 {
-                    bus_width = BUS_8_BIT;
-                    scratch &= 0x7F;  /* XXX - FreeBSD doesn't do this. */
-                    send_reject = TRUE;
-                 }
-                 break;
-
-               default:
-                 break;
-              }
-              if (send_reject)
+              scbp = p->scb_data->scb_array[i];
+              if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
               {
-                outb(SEND_REJ, p->base + RETURN_1);
-                printk(KERN_WARNING "scsi%d: Target %d, channel %c, initiating "
-                       "wide negotiation on a narrow bus - rejecting!",
-                       p->host_no, target, channel);
-              }
-              else
-              {
-                aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
-                outb(SEND_MSG, p->base + RETURN_1);
+                if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
+                {
+                  aic7xxx_reset_device(p, target, channel, lun, i);
+                  reset++;
+                }
               }
             }
-            p->needwdtr &= ~target_mask;
-            outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(scratch, p->base + SCSIRATE);
-            break;
-         }  /* case MSG_EXT_WDTR */
-
-          default:
+            aic7xxx_verbose = old_verbose;
             /*
-             * Unknown extended message - reject it.
+             * Wait until after the for loop to set the busy index since
+             * aic7xxx_reset_device will clear the busy index during its
+             * operation.
              */
-            outb(SEND_REJ, p->base + RETURN_1);
-            break;
-       }  /* switch (message_code) */
-      }  /* case EXTENDED_MSG */
-      break;
-
-    case REJECT_MSG:
-      {
-       /*
-        * What we care about here is if we had an outstanding SDTR
-        * or WDTR message for this target. If we did, this is a
-        * signal that the target is refusing negotiation.
-        */
-       unsigned char targ_scratch;
-        unsigned char scb_index;
-
-        scb_index = inb(p->base + SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
-       targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
-       if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
-       {
+            aic7xxx_busy_target(p, scb);
+            printk(INFO_LEAD "Device is refusing tagged commands, using "
+              "untagged I/O.\n", p->host_no, channel, target, lun);
+          }
+          aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+        }
+        else if ( (last_msg == MSG_IDENTIFYFLAG) && 
+                  (scb->flags & SCB_MSGOUT_WDTR) )
+        {
           /*
            * note 8bit xfers and clear flag
            */
           targ_scratch &= 0x7F;
           p->needwdtr &= ~target_mask;
-          printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
-                "negotiation; using 8 bit transfers.\n",
-                p->host_no, target, channel);
-       }
-       else
-       {
-          if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
+          p->needwdtr_copy &= ~target_mask;
+          p->wdtr_pending &= ~target_mask;
+          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+               (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
           {
-            /*
-             * note asynch xfers and clear flag
-             */
-            targ_scratch &= 0xF0;
-            p->needsdtr &= ~target_mask;
-            printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
-                  "synchronous negotiation; using asynchronous transfers.\n",
-                  p->host_no, target, channel);
+            printk(INFO_LEAD "Refusing WIDE negotiation; using 8 bit "
+              "transfers.\n", p->host_no, CTL_OF_SCB(scb));
+            p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
           }
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          p->syncinfo[scratch_offset].offset = MAX_OFFSET_8BIT;
+          if (p->needsdtr & target_mask)
+          {
+            p->sdtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_SDTR;
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          }
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+         /*
+          * note asynch xfers and clear flag
+          */
+          targ_scratch &= 0xF0;
+          p->needsdtr &= ~target_mask;
+          p->needsdtr_copy &= ~target_mask;
+          p->sdtr_pending &= ~target_mask;
+          p->syncinfo[scratch_offset].period = 0;
+          p->syncinfo[scratch_offset].offset = 0;
+          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+               (p->dev_flags[scratch_offset] & DEVICE_PRINT_SDTR) )
+          {
+            printk(INFO_LEAD "Refusing synchronous negotiation; using "
+              "asynchronous transfers.\n", p->host_no, CTL_OF_SCB(scb));
+            p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_SDTR;
+          }
+        }
+        else if (aic7xxx_verbose & VERBOSE_SEQINT)
+        {
           /*
            * Otherwise, we ignore it.
            */
-       }
-        outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-        outb(targ_scratch, p->base + SCSIRATE);
+          printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause.  "
+            "Ignoring.\n", p->host_no, channel, target, lun);
+        }
+        aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+        aic_outb(p, targ_scratch, SCSIRATE);
       }
       break;
 
     case BAD_STATUS:
       {
-       unsigned char scb_index;
-       struct aic7xxx_hwscb *hscb;
-       Scsi_Cmnd *cmd;
-
-       /* The sequencer will notify us when a command has an error that
-        * would be of interest to the kernel.  This allows us to leave
-        * the sequencer running in the common case of command completes
-        * without error.  The sequencer will have DMA'd the SCB back
-        * up to us, so we can reference the drivers SCB array.
-        */
-       scb_index = inb(p->base + SCB_TAG);
-       scb = p->scb_data->scb_array[scb_index];
-       hscb = scb->hscb;
-
-       /*
-        * Set the default return value to 0 indicating not to send
-        * sense.  The sense code will change this if needed and this
-        * reduces code duplication.
-        */
-       outb(0, p->base + RETURN_1);
-       if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-       {
-          printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-                "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%lx.\n", p->host_no,
-                intstat, scb_index, scb->flags, (unsigned long) scb->cmd);
-       }
-       else
-       {
+        unsigned char scb_index;
+        struct aic7xxx_hwscb *hscb;
+        Scsi_Cmnd *cmd;
+
+        /* The sequencer will notify us when a command has an error that
+         * would be of interest to the kernel.  This allows us to leave
+         * the sequencer running in the common case of command completes
+         * without error.  The sequencer will have DMA'd the SCB back
+         * up to us, so we can reference the drivers SCB array.
+         */
+        scb_index = aic_inb(p, SCB_TAG);
+        if (scb_index > p->scb_data->numscbs)
+        {
+          aic_outb(p, 0, RETURN_1);
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n",
+            p->host_no, channel, target, lun, intstat, scb_index);
+          break;
+        }
+        scb = p->scb_data->scb_array[scb_index];
+        hscb = scb->hscb;
+
+        /*
+         * Set the default return value to 0 indicating not to send
+         * sense.  The sense code will change this if needed and this
+         * reduces code duplication.
+         */
+        aic_outb(p, 0, RETURN_1);
+        if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x,"
+            " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat,
+            scb_index, scb->flags, (unsigned long) scb->cmd);
+        }
+        else
+        {
           cmd = scb->cmd;
-         hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+          hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
           aic7xxx_status(cmd) = hscb->target_status;
 
-          cmd->result |= hscb->target_status;
+          cmd->result = hscb->target_status;
 
           switch (status_byte(hscb->target_status))
           {
             case GOOD:
-             printk(KERN_WARNING "(scsi%d:%d:%d) Interrupted for status of "
-                     "GOOD???\n", p->host_no, TC_OF_SCB(scb));
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Interrupted for status of GOOD???\n",
+                  p->host_no, CTL_OF_SCB(scb));
               break;
 
+            case COMMAND_TERMINATED:
             case CHECK_CONDITION:
-              if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+              if ( !(scb->flags & SCB_SENSE) )
               {
-               unsigned int addr;    /* must be 32 bits */
-               /*
-                * XXX - How do we save the residual (if there is one).
-                */
-                aic7xxx_calculate_residual(p, scb);
-
-               /*
-                * Send a sense command to the requesting target.
-                * XXX - revisit this and get rid of the memcopys.
-                */
-               memcpy((void *) scb->sense_cmd, (void *) generic_sense,
-                      sizeof(generic_sense));
-
-               scb->sense_cmd[1] = (cmd->lun << 5);
-               scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
-               scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer));
-               scb->sg_list[0].length = cpu_to_le32(sizeof(cmd->sense_buffer));
-               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+                /*
+                 * XXX - How do we save the residual (if there is one).
+                 */
+                if ( hscb->residual_SG_segment_count != 0 )
+                  aic7xxx_calculate_residual(p, scb);
+
+                /*
+                   * Send a sense command to the requesting target.
+                 * XXX - revisit this and get rid of the memcopys.
+                   */
+                memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+                       sizeof(generic_sense));
+
+                scb->sense_cmd[1] = (cmd->lun << 5);
+                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+                scb->sg_list[0].address = 
+                  cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer[0]));
+                scb->sg_list[0].length = 
+                  cpu_to_le32(sizeof(cmd->sense_buffer));
 
                 /*
                  * XXX - We should allow disconnection, but can't as it
                  * might allow overlapped tagged commands.
                  */
-               /* hscb->control &= DISCENB; */
+                  /* hscb->control &= DISCENB; */
                 hscb->control = 0;
-               hscb->target_status = 0;
-               hscb->SG_segment_count = 1;
-
-               addr = VIRT_TO_BUS(&scb->sg_list[0]);
-                hscb->SG_list_pointer = cpu_to_le32(addr);
+                hscb->target_status = 0;
+                hscb->SG_list_pointer = 
+                  cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
                 hscb->data_pointer = scb->sg_list[0].address;
+                hscb->data_count = scb->sg_list[0].length;
+                hscb->SCSI_cmd_pointer = 
+                  cpu_to_le32(VIRT_TO_BUS(&scb->sense_cmd[0]));
+                hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+                hscb->residual_SG_segment_count = 0;
+                hscb->residual_data_count[0] = 0;
+                hscb->residual_data_count[1] = 0;
+                hscb->residual_data_count[2] = 0;
+
+                scb->sg_count = hscb->SG_segment_count = 1;
+                scb->sg_length = sizeof(cmd->sense_buffer);
+                scb->flags &= ~SCB_MSGOUT_BITS;
+                scb->tag_action = 0;
+                /*
+                 * This problem could be caused if the target has lost power
+                 * or found some other way to loose the negotiation settings,
+                 * so if needed, we'll re-negotiate while doing the sense cmd.
+                 * However, if this SCB already was attempting to negotiate,
+                 * then we assume this isn't the problem and skip this part.
+                 */
+                if ( !(scb->flags & SCB_MSGOUT_BITS) )
+                {
+                  if ( p->needwdtr_copy & target_mask )
+                  {
+                    p->needwdtr |= target_mask;
+                    p->wdtr_pending |= target_mask;
+                    hscb->control |= MK_MESSAGE;
+                    scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+                  }
+                  if ( p->needsdtr_copy & target_mask )
+                  {
+                    p->needsdtr |= target_mask;
+                    if ((hscb->control & MK_MESSAGE) == 0)
+                    {
+                      p->sdtr_pending |= target_mask;
+                      hscb->control |= MK_MESSAGE;
+                      scb->flags |= SCB_MSGOUT_SDTR;
+                    }
+                  }
+                }
 
-               /* Maintain SCB_LINKED_NEXT */
-               hscb->data_count &= cpu_to_le32(0xFF000000);
-               hscb->data_count |= scb->sg_list[0].length;
-
-               addr = VIRT_TO_BUS(scb->sense_cmd);
-                hscb->SCSI_cmd_pointer = cpu_to_le32(addr);
-               hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
-
-                scb->sg_count = hscb->SG_segment_count;
-               scb->flags |= SCB_SENSE;
+                scb->flags |= SCB_SENSE;
                 /*
                  * Ensure the target is busy since this will be an
                  * an untagged request.
                  */
-                aic7xxx_busy_target(p, target, channel, hscb->tag);
-               outb(SEND_SENSE, p->base + RETURN_1);
+                aic7xxx_busy_target(p, scb);
+                aic_outb(p, SEND_SENSE, RETURN_1);
+                aic7xxx_error(cmd) = DID_OK;
+                break;
               }  /* first time sense, no errors */
-             else
-             {
-               if (aic7xxx_error(cmd) == 0)
-               {
-                 aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-               }
-             }
+              aic7xxx_error(cmd) = DID_OK;
+              scb->flags &= ~SCB_SENSE;
               break;
 
             case QUEUE_FULL:
-#ifdef NOT_YET
-              if (scb->hscb->control & TAG_ENB)
+              queue_flag = TRUE;    /* Mark that this is a QUEUE_FULL and */
+            case BUSY:              /* drop through to here */
+            {
+              struct aic7xxx_scb *next_scbp, *prev_scbp;
+              unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
+              /*
+               * We have to look three places for queued commands:
+               *  1: QINFIFO
+               *  2: p->waiting_scbs queue
+               *  3: WAITING_SCBS list on card (for commands that are started
+               *     but haven't yet made it to the device)
+               */
+              aic7xxx_search_qinfifo(p, target, channel, lun,
+                SCB_LIST_NULL, 0, TRUE,
+                &p->delayed_scbs[scratch_offset]);
+              next_scbp = p->waiting_scbs.head;
+              while ( next_scbp != NULL )
               {
-               if (cmd->device->queue_depth > 2)
-               {
-                  cmd->device->queue_depth--;  /* Not correct */
-                  printk(KERN_WARNING "(scsi%d:%d:%d) Tagged queue depth "
-                        "reduced to %d\n", p->host_no,
-                        TC_OF_SCB(scb), cmd->device->queue_depth);
-               }
-               /*
-                * XXX - Requeue this unconditionally?
-                */
-
-               /*
-                * We'd like to be able to give the SCB some more time
-                * (untimeout, then timeout).
-                */
-               break;
+                prev_scbp = next_scbp;
+                next_scbp = next_scbp->q_next;
+                if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun,
+                     SCB_LIST_NULL) )
+                {
+                  scbq_remove(&p->waiting_scbs, prev_scbp);
+                  scbq_insert_tail(&p->delayed_scbs[scratch_offset],
+                    prev_scbp);
+                }
               }
-#endif
-              printk(KERN_WARNING "(scsi%d:%d:%d) Queue full received; "
-                     "queue depth %d, active %d\n", p->host_no,
-                     TC_OF_SCB(scb), cmd->device->queue_depth,
-                     p->device_status[TARGET_INDEX(cmd)].active_cmds);
-
-              /* Else treat this as if it was a BUSY condition. */
-              scb->hscb->target_status = (BUSY << 1) |
-                  (scb->hscb->target_status & 0x01);
-              /* Fall through to the BUSY case. */
-
-            case BUSY:
-              printk(KERN_WARNING "(scsi%d:%d:%d) Target busy\n",
-                     p->host_no, TC_OF_SCB(scb));
-              if (!aic7xxx_error(cmd))
+              next_scbp = NULL;
+              active_hscb = aic_inb(p, SCBPTR);
+              prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
+              next_hscb = aic_inb(p, WAITING_SCBH);
+              while (next_hscb != SCB_LIST_NULL)
               {
-               /*
-                * The mid-level SCSI code should be fixed to
-                * retry the command at a later time instead of
-                * trying right away.
-                */
-               aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
-              }
-              udelay(1000);  /*  A small pause (1ms) to help the drive */
-              break;
+                aic_outb(p, next_hscb, SCBPTR);
+                scb_index = aic_inb(p, SCB_TAG);
+                next_scbp = p->scb_data->scb_array[scb_index];
+                if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
+                    SCB_LIST_NULL) )
+                {
+                  scbq_insert_head(&p->delayed_scbs[scratch_offset],
+                    next_scbp);
+                  next_scbp->flags |= SCB_WAITINGQ;
+                  p->dev_active_cmds[scratch_offset]--;
+                  p->activescbs--;
+                  next_hscb = aic_inb(p, SCB_NEXT);
+                  aic_outb(p, 0, SCB_CONTROL);
+                  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+                  aic7xxx_add_curscb_to_free_list(p);
+                  if (prev_hscb == SCB_LIST_NULL)
+                  {
+                    aic_outb(p, 0, SCSISEQ);    /* We were first on the list,
+                                                 * so we kill the selection
+                                                 * hardware.  Let the sequencer
+                                                 * re-init the hardware itself
+                                                 */
+                    aic_outb(p, next_hscb, WAITING_SCBH);
+                  }
+                  else
+                  {
+                    aic_outb(p, prev_hscb, SCBPTR);
+                    aic_outb(p, next_hscb, SCB_NEXT);
+                  }
+                }
+                else
+                {
+                  prev_hscb = next_hscb;
+                  next_hscb = aic_inb(p, SCB_NEXT);
+                }
+              }
+              aic_outb(p, active_hscb, SCBPTR);
+              scbq_insert_head(&p->delayed_scbs[scratch_offset], scb);
+              p->dev_active_cmds[scratch_offset]--;
+              p->activescbs--;
+              scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
+                  
+              if (p->dev_timer[scratch_offset].expires == 0) 
+              {
+                if ( p->dev_active_cmds[scratch_offset] )
+                {
+                  p->dev_timer[scratch_offset].expires = jiffies + (HZ * 2);
+                  add_timer(&p->dev_timer[scratch_offset]);
+                }
+                else
+                {
+                  p->dev_timer[scratch_offset].expires = jiffies + (HZ / 2);
+                  add_timer(&p->dev_timer[scratch_offset]);
+                }
+              }
+              if (aic7xxx_verbose & VERBOSE_QUEUE_FULL)
+              {
+                if (queue_flag)
+                  printk(INFO_LEAD "Queue full received; queue depth %d, "
+                    "active %d\n", p->host_no, CTL_OF_SCB(scb),
+                    p->dev_max_queue_depth[scratch_offset],
+                    p->dev_active_cmds[scratch_offset]);
+                else
+                  printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
 
+              }
+              if (queue_flag)
+              {
+                p->dev_temp_queue_depth[scratch_offset] = 
+                  p->dev_active_cmds[scratch_offset];
+                if ( p->dev_last_queue_full[scratch_offset] !=
+                     p->dev_active_cmds[scratch_offset] )
+                {
+                  p->dev_last_queue_full[scratch_offset] = 
+                      p->dev_active_cmds[scratch_offset];
+                  p->dev_last_queue_full_count[scratch_offset] = 0;
+                }
+                else
+                {
+                  p->dev_last_queue_full_count[scratch_offset]++;
+                }
+                if ( (p->dev_last_queue_full_count[scratch_offset] > 14) &&
+                     (p->dev_active_cmds[scratch_offset] > 4) )
+                {
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+                    printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
+                      CTL_OF_SCB(scb), p->dev_active_cmds[scratch_offset]);
+                  p->dev_max_queue_depth[scratch_offset] = 
+                      p->dev_active_cmds[scratch_offset];
+                  p->dev_last_queue_full[scratch_offset] = 0;
+                  p->dev_last_queue_full_count[scratch_offset] = 0;
+                }
+              }
+              break;
+            }
+            
             default:
-              printk(KERN_WARNING "(scsi%d:%d:%d) Unexpected target "
-                     "status 0x%x.\n", p->host_no,
-                    TC_OF_SCB(scb), scb->hscb->target_status);
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no,
+                     CTL_OF_SCB(scb), scb->hscb->target_status);
               if (!aic7xxx_error(cmd))
               {
-               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+                aic7xxx_error(cmd) = DID_RETRY_COMMAND;
               }
               break;
           }  /* end switch */
-       }  /* end else of */
+        }  /* end else of */
       }
       break;
 
     case AWAITING_MSG:
       {
-       unsigned char scb_index;
-        unsigned char message_offset;
-
-       scb_index = inb(p->base + SCB_TAG);
-       scb = p->scb_data->scb_array[scb_index];
-
-       /*
-        * This SCB had a MK_MESSAGE set in its control byte informing
-        * the sequencer that we wanted to send a special message to
-        * this target.
-        */
-        message_offset = inb(p->base + MSG_LEN);
-       if (scb->flags & SCB_DEVICE_RESET)
-       {
-          outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
-          outb(1, p->base + MSG_LEN);
-          printk(KERN_INFO "(scsi%d:%d:%d) Bus device reset sent\n",
-                p->host_no, TC_OF_SCB(scb));
-       }
+        unsigned char scb_index;
+
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+        p->msg_index = p->msg_len = 0;
+        /*
+         * This SCB had a MK_MESSAGE set in its control byte informing
+         * the sequencer that we wanted to send a special message to
+         * this target.
+         */
+
+        if (scb->flags & SCB_DEVICE_RESET)
+        {
+          p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+            printk(INFO_LEAD "Bus device reset mailed.\n",
+                 p->host_no, CTL_OF_SCB(scb));
+        }
         else if (scb->flags & SCB_ABORT)
         {
-          if ((scb->hscb->control & TAG_ENB) != 0)
+          if (scb->hscb->control & TAG_ENB)
           {
-            outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+            if (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG)
+            {
+              p->msg_buf[p->msg_index++] = scb->tag_action;
+              p->msg_buf[p->msg_index++] = scb->hscb->tag;
+              p->msg_len += 2;
+            }
+            p->msg_buf[p->msg_index++] = MSG_ABORT_TAG;
           }
           else
           {
-            outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+            p->msg_buf[p->msg_index++] = MSG_ABORT;
           }
-          outb(message_offset + 1, p->base + MSG_LEN);
-          printk(KERN_WARNING "(scsi%d:%d:%d): Abort message sent.\n",
-                 p->host_no, TC_OF_SCB(scb));
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+            printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
+              CTL_OF_SCB(scb));
         }
-       else if (scb->flags & SCB_MSGOUT_WDTR)
-       {
-          aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          aic7xxx_construct_wdtr(p, (scb->flags & SCB_WDTR_16BIT));
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
-          unsigned char target_scratch;
-          unsigned short ultra_enable;
-          int i, sxfr;
+          unsigned char period, offset;
 
           /*
            * Pull the user defined setting from scratch RAM.
            */
-          target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-          sxfr = target_scratch & SXFR;
-          ultra_enable = inb(p->base + ULTRA_ENB) |
-              (inb(p->base + ULTRA_ENB + 1) << 8);
-          if (ultra_enable & target_mask)
-          {
-            sxfr |= 0x100;
-          }
-          for (i = 0; i < num_aic7xxx_syncrates; i++)
+          period = p->syncinfo[scratch_offset].period;
+          offset = p->syncinfo[scratch_offset].offset;
+          if ( (p->needsdtr_copy & target_mask) == 0)
           {
-            if (sxfr == aic7xxx_syncrates[i].rate)
-            break;
+            period = 0;
+            offset = 0;
           }
-          aic7xxx_construct_sdtr(p, message_offset,
-                                 aic7xxx_syncrates[i].period,
-                                 target_scratch & WIDEXFER ?
-                                 MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
+          aic7xxx_construct_sdtr(p, period, offset);
         }
         else 
         {
           panic("aic7xxx: AWAITING_MSG for an SCB that does "
-                "not have a waiting message.");
-       }
+                "not have a waiting message.\n");
+        }
+        /*
+         * We've set everything up to send our message, now to actually do
+         * so we need to enable reqinit interrupts and let the interrupt
+         * handler do the rest.  We don't want to unpause the sequencer yet
+         * though so we'll return early.  We also have to make sure that
+         * we clear the SEQINT *BEFORE* we set the REQINIT handler active
+         * or else it's possible on VLB cards to loose the first REQINIT
+         * interrupt.  Edge triggered EISA cards could also loose this
+         * interrupt, although PCI and level triggered cards should not
+         * have this problem since they continually interrupt the kernel
+         * until we take care of the situation.
+         */
+        aic_outb(p, CLRSEQINT, CLRINT);
+        p->msg_index = 0;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+        return;
       }
       break;
 
     case DATA_OVERRUN:
       {
-       unsigned char scb_index = inb(p->base + SCB_TAG);
-        unsigned char lastphase = inb(p->base + LASTPHASE);
-       unsigned int i, overrun;
-
-       scb = (p->scb_data->scb_array[scb_index]);
-       overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
-                 (inb(p->base + STCNT + 2) << 16);
-       overrun = 0x00FFFFFF - overrun;
-       printk(KERN_WARNING "(scsi%d:%d:%d) Data overrun of %d bytes detected "
-               "in %s phase, tag %d; forcing a retry.\n",
-               p->host_no, TC_OF_SCB(scb), overrun,
-               lastphase == P_DATAIN ? "Data-In" : "Data-Out",
-               scb->hscb->tag);
-        printk(KERN_WARNING "%s seen Data Phase.  Length = %d, NumSGs = %d.\n",
-               inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
-               aic7xxx_length(scb->cmd, 0), scb->sg_count);
-        for (i = 0; i < scb->sg_count; i++)
+        unsigned char scb_index = aic_inb(p, SCB_TAG);
+        unsigned char lastphase = aic_inb(p, LASTPHASE);
+        unsigned int i;
+
+        scb = (p->scb_data->scb_array[scb_index]);
+        /*
+         * XXX - What do we really want to do on an overrun?  The
+         *       mid-level SCSI code should handle this, but for now,
+         *       we'll just indicate that the command should retried.
+         *    If we retrieved sense info on this target, then the 
+         *    base SENSE info should have been saved prior to the
+         *    overrun error.  In that case, we return DID_OK and let
+         *    the mid level code pick up on the sense info.  Otherwise
+         *    we return DID_ERROR so the command will get retried.
+         */
+        if ( !(scb->flags & SCB_SENSE) )
         {
-          printk(KERN_INFO "     sg[%d] - Addr 0x%x : Length %d\n",
-                 i,
+          printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n",
+            p->host_no, CTL_OF_SCB(scb), 
+            (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag);
+          printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
+            (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
+            scb->sg_length, scb->sg_count);
+          for (i = 0; i < scb->sg_count; i++)
+          {
+            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+                 i, 
                  le32_to_cpu(scb->sg_list[i].address),
-                 le32_to_cpu(scb->sg_list[i].length));
+                 le32_to_cpu(scb->sg_list[i].length) );
+          }
+          aic7xxx_error(scb->cmd) = DID_ERROR;
         }
-       /*
-        * XXX - What do we really want to do on an overrun?  The
-        *       mid-level SCSI code should handle this, but for now,
-        *       we'll just indicate that the command should retried.
-        */
-       aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
+        else
+          printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n",
+            p->host_no, CTL_OF_SCB(scb));
+      }
+      break;
+
+    case TRACEPOINT:
+      {
+        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
+          target, lun);
+      }
+      break;
+
+    case TRACEPOINT2:
+      {
+        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
+          target, lun);
       }
       break;
 
-/* #if AIC7XXX_NOT_YET */
+#if AIC7XXX_NOT_YET 
     /* XXX Fill these in later */
     case MSG_BUFFER_BUSY:
       printk("aic7xxx: Message buffer busy.\n");
@@ -3477,31 +4119,374 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
     case MSGIN_PHASEMIS:
       printk("aic7xxx: Message-in phasemis.\n");
       break;
-/*#endif */
-
-    case ABORT_CMDCMPLT:
-      /* This interrupt serves to pause the sequencer until we can clean
-       * up the QOUTFIFO allowing us to handle any abort SCBs that may
-       * completed yet still have an SCB in the QINFIFO or waiting for
-       * selection queue.  By the time we get here, we should have
-       * already cleaned up the queues, so all we need to do is unpause
-       * the sequencer.
-       */
-      break;
+#endif
 
-    default:              /* unknown */
-      printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
-             p->host_no, intstat, inb(p->base + SCSISIGI));
+    default:                   /* unknown */
+      printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+             p->host_no, channel, target, lun, intstat,
+             aic_inb(p, SCSISIGI));
       break;
   }
 
   /*
    * Clear the sequencer interrupt and unpause the sequencer.
    */
-  outb(CLRSEQINT, p->base + CLRINT);
+  aic_outb(p, CLRSEQINT, CLRINT);
   unpause_sequencer(p, /* unpause always */ TRUE);
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_parse_msg
+ *
+ * Description:
+ *   Parses incoming messages into actions on behalf of
+ *   aic7xxx_handle_reqinit
+ *_F*************************************************************************/
+static int
+aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int reject, done;
+  unsigned char target_scratch, scratch_offset;
+  unsigned short target_mask;
+
+  reject = done = FALSE;
+  scratch_offset = TARGET_INDEX(scb->cmd);
+  target_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+  target_mask = (0x01 << scratch_offset);
+
+  /*
+   * Parse as much of the message as is availible,
+   * rejecting it if we don't support it.  When
+   * the entire message is availible and has been
+   * handled, return TRUE indicating that we have
+   * parsed an entire message.
+   */
+
+  if (p->msg_buf[0] != MSG_EXTENDED)
+  {
+    reject = TRUE;
+  }
+
+  /*
+   * Just accept the length byte outright and perform
+   * more checking once we know the message type.
+   */
+
+  if ( !reject && (p->msg_len > 2) )
+  {
+    switch(p->msg_buf[2])
+    {
+      case MSG_EXT_SDTR:
+      {
+        unsigned char period, response_period, offset;
+        unsigned char max_offset, saved_offset, rate;
+
+        if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_SDTR_LEN + 2))
+        {
+          break;
+        }
+
+        period = p->msg_buf[3];
+        saved_offset = p->msg_buf[4];
+
+        if (target_scratch & WIDEXFER)
+        {
+          max_offset = MAX_OFFSET_16BIT;
+        }
+        else
+        {
+          max_offset = MAX_OFFSET_8BIT;
+        }
+        offset = MIN(saved_offset, max_offset);
+        response_period = aic7xxx_scsirate(p, &rate, &period,
+          &offset, scb->cmd->target, scb->cmd->channel, /* set */ TRUE);
+        /* Preserve the WideXfer flag */
+        target_scratch = rate | (target_scratch & WIDEXFER);
+
+        /*
+         * Update the TARGET_SCRATCH, the SCSIRATE, and our syncinfo
+         * areas.
+         */
+        aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+        aic_outb(p, target_scratch, SCSIRATE);
+        p->syncinfo[scratch_offset].period = response_period;
+        p->syncinfo[scratch_offset].offset = offset;
+
+        /*
+         * Did we start this, if not, or if we went to low and had to
+         * go async, then send an SDTR back to the target
+         */
+        p->needsdtr &= ~target_mask;
+        if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+          if (saved_offset != offset)
+          {
+            p->needsdtr_copy &= ~target_mask;
+            reject = TRUE; 
+          }
+          scb->flags &= ~SCB_MSGOUT_SDTR;
+          p->sdtr_pending &= ~target_mask;
+        }
+        else
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_SDTR;
+          p->sdtr_pending |= target_mask;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_WDTR:
+      {
+        unsigned char bus_width;
+          
+        if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_WDTR_LEN + 2))
+        {
+          break;
+        }
+
+        bus_width = p->msg_buf[3];
+        p->needwdtr &= ~target_mask;
+        if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reject = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              target_scratch &= 0x7f;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              target_scratch |= WIDEXFER;
+              break;
+            }
+          }
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          p->wdtr_pending &= ~target_mask;
+        }
+        else
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          switch(bus_width)
+          {
+            default:
+            {
+              if (p->type & AHC_WIDE)
+              {
+                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                p->needwdtr_copy |= target_mask;
+                scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+                target_scratch |= WIDEXFER;
+                if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                     (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+                {
+                  printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+                    p->host_no, CTL_OF_SCB(scb));
+                  p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+                }
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              scb->flags |= SCB_MSGOUT_WDTR_8BIT;
+              target_scratch &= 0x7f;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              break;
+            }
+          }
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          p->wdtr_pending |= target_mask;
+        }
+        aic_outb(p, target_scratch, SCSIRATE);
+        aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+        p->syncinfo[scratch_offset].offset =
+          (bus_width == MSG_EXT_WDTR_BUS_8_BIT) ? 
+          MAX_OFFSET_8BIT : MAX_OFFSET_16BIT;
+        if ( !(p->wdtr_pending & target_mask) && !reject)
+        {
+          /*
+           * We've successfully completed the wide negotiation, so let's start
+           * up the sync negotiation now.
+           */
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          if ((p->needsdtr & target_mask) && !(p->sdtr_pending & target_mask))
+          {
+            p->sdtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_SDTR;
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          }
+        }
+        done = TRUE;
+        break;
+      }
+      default:
+      {
+        reject = TRUE;
+        break;
+      }
+    } /* end of switch(p->msg_type) */
+  } /* end of if (!reject && (p->msg_len > 2)) */
+
+  if (reject)
+  {
+    aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
+    aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+  }
+  return(done);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_reqinit
+ *
+ * Description:
+ *   Interrupt handler for REQINIT interrupts (used to transfer messages to
+ *    and from devices).
+ *_F*************************************************************************/
+static void
+aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  unsigned char lastbyte;
+  unsigned char phasemis;
+  int done;
+
+  switch(p->msg_type)
+  {
+    case MSG_TYPE_INITIATOR_MSGOUT:
+      {
+        if (p->msg_len == 0)
+          panic("aic7xxx: REQINIT with no active message!\n");
+
+        lastbyte = (p->msg_index == (p->msg_len - 1));
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
+
+        if (lastbyte || phasemis)
+        {
+          /* Time to end the message */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          /*
+           * NOTE-TO-MYSELF: If you clear the REQINIT after you
+           * disable REQINITs, then cases of REJECT_MSG stop working
+           * and hang the bus
+           */
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          p->flags &= ~AHC_HANDLING_REQINITS;
+
+          if (phasemis == 0)
+          {
+            aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
+            aic_outb(p, 0, RETURN_1);
+          }
+          else
+          {
+            aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
+          }
+          unpause_sequencer(p, TRUE);
+        }
+        else
+        {
+          /*
+           * Present the byte on the bus (clearing REQINIT) but don't
+           * unpause the sequencer.
+           */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_outb(p,  p->msg_buf[p->msg_index++], SCSIDATL);
+        }
+        break;
+      }
+    case MSG_TYPE_INITIATOR_MSGIN:
+      {
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
+
+        if (phasemis == 0)
+        {
+          p->msg_len++;
+          /* Pull the byte in without acking it */
+          p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
+          done = aic7xxx_parse_msg(p, scb);
+          /* Ack the byte */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_inb(p, SCSIDATL);
+          p->msg_index++;
+        }
+        if (phasemis || done)
+        {
+          /* Time to end our message session */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          p->flags &= ~AHC_HANDLING_REQINITS;
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          unpause_sequencer(p, TRUE);
+        }
+        break;
+      }
+    default:
+      {
+        panic("aic7xxx: Unknown REQINIT message type.\n");
+        break;
+      }
+  } /* End of switch(p->msg_type) */
+}
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_handle_scsiint
@@ -3516,8 +4501,8 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
   unsigned char status;
   struct aic7xxx_scb *scb;
 
-  scb_index = inb(p->base + SCB_TAG);
-  status = inb(p->base + SSTAT1);
+  scb_index = aic_inb(p, SCB_TAG);
+  status = aic_inb(p, SSTAT1);
 
   if (scb_index < p->scb_data->numscbs)
   {
@@ -3532,14 +4517,35 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     scb = NULL;
   }
 
+
+  if ( (p->flags & AHC_HANDLING_REQINITS) && (status & REQINIT) )
+  {
+    if (scb)
+    {
+      aic7xxx_handle_reqinit(p, scb);
+    }
+    else
+    {
+      p->flags &= ~AHC_HANDLING_REQINITS;
+      aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+      aic_outb(p, CLRREQINIT, CLRSINT1);
+      aic_outb(p, CLRSCSIINT, CLRINT);
+      p->msg_type = MSG_TYPE_NONE;
+      p->msg_index = 0;
+      p->msg_len = 0;
+    }
+    return;
+  }
+
   if ((status & SCSIRSTI) != 0)
   {
-    char channel;
+    int channel;
 
-    channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+    channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
 
-    printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
-           p->host_no, channel);
+    if (aic7xxx_verbose & VERBOSE_RESET)
+      printk(WARN_LEAD "Someone else reset the channel!!\n",
+           p->host_no, channel, -1, -1);
     /*
      * Go through and abort all commands for the channel, but do not
      * reset the channel again.
@@ -3554,35 +4560,27 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      * chances are pretty good that the bus free was in response to
      * one of our abort requests.
      */
-    unsigned char lastphase = inb(p->base + LASTPHASE);
-    unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
-    char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
+    unsigned char target = (saved_tcl >> 4) & 0x0F;
+    int channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
     int printerror = TRUE;
 
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     if (lastphase == P_MESGOUT)
     {
-      unsigned char sindex;
       unsigned char message;
 
-      sindex = inb(p->base + SINDEX);
-      message = inb(p->base + sindex - 1);
+      message = aic_inb(p, SINDEX);
 
-      if (message == MSG_ABORT)
-      {
-        printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort completed.\n",
-                   p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), SCB_LIST_NULL);
-        aic7xxx_run_done_queue(p, /* complete */ TRUE);
-        scb = NULL;
-        printerror = 0;
-      }
-      else if (message == MSG_ABORT_TAG)
+      if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort Tag completed.\n",
-                   p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), scb->hscb->tag);
-        aic7xxx_run_done_queue(p, /* complete */ TRUE);
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no,
+            CTL_OF_SCB(scb), scb->hscb->tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS,
+                (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
+        aic7xxx_run_done_queue(p, FALSE);
         scb = NULL;
         printerror = 0;
       }
@@ -3607,20 +4605,26 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
         {
           tag = SCB_LIST_NULL;
         }
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
+        aic7xxx_run_done_queue(p, FALSE);
       }
       else
-      {
-        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+      {  /* Since we don't really know what happened here, we'll wait */
+         /* for the commands to timeout and get aborted if need be    */
+        aic7xxx_add_curscb_to_free_list(p);
       }
-      printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
-             "SEQADDR = 0x%x\n", p->host_no, lastphase,
-             (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+      printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
+             "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
+             (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+      scb = NULL;
     }
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
-    outb(CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
   }
   else if ((status & SELTO) != 0)
   {
@@ -3628,9 +4632,18 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     unsigned char nextscb;
     Scsi_Cmnd *cmd;
 
-    scbptr = inb(p->base + WAITING_SCBH);
-    outb(scbptr, p->base + SCBPTR);
-    scb_index = inb(p->base + SCB_TAG);
+    scbptr = aic_inb(p, WAITING_SCBH);
+    if (scbptr >= p->scb_data->maxhscbs)
+    {
+      scb_index = SCB_LIST_NULL;
+      printk(WARN_LEAD "Bad scbptr %d during SELTO.\n", 
+        p->host_no, -1, -1, -1, scbptr);
+    }
+    else
+    {
+      aic_outb(p, scbptr, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
+    }
 
     scb = NULL;
     if (scb_index < p->scb_data->numscbs)
@@ -3643,63 +4656,80 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     }
     if (scb == NULL)
     {
-      printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
-             p->host_no, scb_index);
+      printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n",
+             p->host_no, -1, -1, -1, scb_index);
       printk(KERN_WARNING "        SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
-             "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
-             inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
-             inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+             "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ),
+             aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+             aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
     }
     else
     {
-      /*
-       * XXX - If we queued an abort tag, go clean up the disconnected list.
-       */
       cmd = scb->cmd;
       cmd->result = (DID_TIME_OUT << 16);
 
       /*
-       * Clear an pending messages for the timed out
-       * target and mark the target as free.
+       * Clear out this hardware SCB
+       */
+      aic_outb(p, 0, SCB_CONTROL);
+
+      /*
+       * Clear out a few values in the card that are in an undetermined
+       * state.
        */
-      outb(0, p->base + MSG_LEN);
-      aic7xxx_index_busy_target(p, cmd->target,
-          cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
-      outb(0, p->base + SCB_CONTROL);
+      aic_outb(p, MSG_NOOP, MSG_OUT);
 
       /*
        * Shift the waiting for selection queue forward
        */
-      nextscb = inb(p->base + SCB_NEXT);
-      outb(nextscb, p->base + WAITING_SCBH);
+      nextscb = aic_inb(p, SCB_NEXT);
+      aic_outb(p, nextscb, WAITING_SCBH);
 
       /*
        * Put this SCB back on the free list.
        */
       aic7xxx_add_curscb_to_free_list(p);
+      /*
+       * XXX - If we queued an abort tag, go clean up the disconnected list.
+       * We know that this particular SCB had to be the queued abort since
+       * the disconnected SCB would have gotten a reconnect instead.
+       * However, if this is an abort command, then DID_TIMEOUT isn't
+       * appropriate, neither is returning the command for that matter.
+       * What we need to do then is to let the command timeout again so
+       * we get a reset since this abort just failed.
+       */
+      if (p->flags & SCB_QUEUED_ABORT)
+      {
+        cmd->result = 0;
+        scb->flags &= ~SCB_QUEUED_ABORT;
+        scb = NULL;
+      }
     }
     /*
      * Stop the selection.
      */
-    outb(0, p->base + SCSISEQ);
-    outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, 0, SCSISEQ);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
   }
   else if (scb == NULL)
   {
-    printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+    printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid "
            "during scsiint 0x%x scb(%d)\n"
            "      SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
-           p->host_no, status, scb_index, inb(p->base + SIMODE0),
-           inb(p->base + SIMODE1), inb(p->base + SSTAT0),
-           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+           p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
+           aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+           (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
     /*
      * Turn off the interrupt and set status to zero, so that it
      * falls through the rest of the SCSIINT code.
      */
-    outb(status, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
@@ -3711,7 +4741,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     char  *phase;
     Scsi_Cmnd *cmd;
     unsigned char mesg_out = MSG_NOOP;
-    unsigned char lastphase = inb(p->base + LASTPHASE);
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
 
     cmd = scb->cmd;
     switch (lastphase)
@@ -3746,8 +4776,8 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      * A parity error has occurred during a data
      * transfer phase. Flag it and continue.
      */
-    printk(KERN_WARNING "(scsi%d:%d:%d) Parity error during phase %s.\n",
-           p->host_no, TC_OF_SCB(scb), phase);
+    printk(WARN_LEAD "Parity error during phase %s.\n",
+           p->host_no, CTL_OF_SCB(scb), phase);
 
     /*
      * We've set the hardware to assert ATN if we get a parity
@@ -3757,19 +4787,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      */
     if (mesg_out != MSG_NOOP)
     {
-      outb(mesg_out, p->base + MSG_OUT);
-      outb(1, p->base + MSG_LEN);
+      aic_outb(p, mesg_out, MSG_OUT);
       scb = NULL;
     }
-    else
-    {
-      /*
-       * Should we allow the target to make this decision for us?
-       */
-      cmd->result = DID_RETRY_COMMAND << 16;
-    }
-    outb(CLRSCSIPERR, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, CLRSCSIPERR, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause_always */ TRUE);
   }
   else
@@ -3778,47 +4800,150 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      * We don't know what's going on. Turn off the
      * interrupt source and try to continue.
      */
-    printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
-    outb(status, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    if (aic7xxx_verbose & VERBOSE_SCSIINT)
+      printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n",
+        p->host_no, -1, -1, -1, status);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
   if (scb != NULL)
   {
     aic7xxx_done(p, scb);
-    aic7xxx_done_cmds_complete(p);
   }
 }
 
+#ifdef CONFIG_PCI
+
+#define  DPE 0x80
+#define  SSE 0x40
+#define  RMA 0x20
+#define  RTA 0x10
+#define  STA 0x08
+#define  DPR 0x01
+
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_isr
+ *   aic7xxx_pci_intr
  *
  * Description:
- *   SCSI controller interrupt handler.
+ *   Check the scsi card for PCI errors and clear the interrupt
+ *
+ *   NOTE: If you don't have this function and a 2940 card encounters
+ *         a PCI error condition, the machine will end up locked as the
+ *         interrupt handler gets slammed with non-stop PCI error interrupts
  *-F*************************************************************************/
 static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+aic7xxx_pci_intr(struct aic7xxx_host *p)
 {
-  struct aic7xxx_host *p = (struct aic7xxx_host *) dev_id;
-  unsigned char intstat;
-  unsigned long flags;
-
-  /*
-   * Handle all the interrupt sources - especially for SCSI
-   * interrupts, we won't get a second chance at them.
-   */
-  intstat = inb(p->base + INTSTAT);
-  if (! (intstat & INT_PEND))  /* Interrupt for another device */
+  unsigned char status1;
+  int error;
+
+  error = 0;
+  error = pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+                                            PCI_STATUS, &status1);
+
+  if (error == 0)
+  {
+    if (status1 & DPE)
+      printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
+        "phase.\n", p->host_no, -1, -1, -1);
+    if (status1 & SSE)
+      printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & RMA)
+      printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & RTA)
+      printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & STA)
+      printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & DPR)
+      printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
+        "PERR#\n", p->host_no, -1, -1, -1);
+  }
+  else
+  {
+    printk(WARN_LEAD "Error reading PCI config register during PCI ERROR"
+      "interrupt.\n", p->host_no, -1, -1, -1);
+    aic_outb(p,  CLRPARERR, CLRINT);
+    return;
+  }
+  
+  pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
+                                            PCI_STATUS, status1);
+  if (status1 & (DPR|RMA|RTA))
+    aic_outb(p,  CLRPARERR, CLRINT);
+
+}
+#endif
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_isr
+ *
+ * Description:
+ *   SCSI controller interrupt handler.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct aic7xxx_host *p;
+  unsigned char intstat;
+  unsigned long cpu_flags = 0;
+
+  p = (struct aic7xxx_host *)dev_id;
+
+  /*
+   * Just a few sanity checks.  Make sure p != NULL, that we have an
+   * interrupt pending, and that we aren't already in our int handler.
+   * Also, if PCI, then we are going to check for a PCI bus error status
+   * should we get too many spurious interrupts.
+   */
+  if (p == NULL)
+  {
+    printk(KERN_WARNING "aic7xxx: ISR routine called with NULL dev_id\n");
+    return;
+  }
+  else if (!(aic_inb(p, INTSTAT) & INT_PEND))
+  {
+#ifdef CONFIG_PCI
+    if ((p->type & AHC_AIC78x0) && (p->spurious_int > 500))
+    {
+      if ( aic_inb(p, ERROR) & PCIERRSTAT )
+      {
+        aic7xxx_pci_intr(p);
+      }
+      p->spurious_int = 0;
+    }
+    else
+    {
+      p->spurious_int++;
+    }
+#endif
+  }
+  else if (p->flags & AHC_IN_ISR)
+  {
     return;
+  }
+
+  /*
+   * Handle all the interrupt sources - especially for SCSI
+   * interrupts, we won't get a second chance at them.
+   */
+  DRIVER_LOCK
+  intstat = aic_inb(p, INTSTAT);
+  p->spurious_int = 0;
 
   /*
    * Keep track of interrupts for /proc/scsi
    */
   p->isr_count++;
-
-  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+  p->flags |= AHC_IN_ISR;
+  if (!(p->flags & AHC_A_SCANNED) && (p->isr_count == 1))
   {
     /*
      * We must only have one card at this IRQ and it must have been
@@ -3826,144 +4951,97 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
      * It is sufficient that we check isr_count and not the spurious
      * interrupt count.
      */
-    printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
     if (intstat)
     {
       /* Try clearing all interrupts. */
-      outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
+      aic_outb(p, CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, CLRINT);
+      unpause_sequencer(p, TRUE);
     }
-    return;
-  }
-
-  if (p->flags & IN_ISR)
-  {
-    printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
-           p->host_no);
+    DRIVER_UNLOCK
+    printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
     return;
   }
 
   /*
    * Indicate that we're in the interrupt handler.
    */
-  save_flags(flags);
-  cli();
-  p->flags |= IN_ISR;
-
   if (intstat & CMDCMPLT)
   {
     struct aic7xxx_scb *scb = NULL;
     Scsi_Cmnd *cmd;
-    unsigned char qoutcnt;
     unsigned char scb_index;
-    int i, interrupts_cleared = 0;
 
+    /*
+     * Clear interrupt status before running the completion loop.
+     * This eliminates a race condition whereby a command could
+     * complete between the last check of qoutfifo and the
+     * CLRCMDINT statement.  This would result in us thinking the
+     * qoutfifo was empty when it wasn't, and in actuality be a lost
+     * completion interrupt.  With multiple devices or tagged queueing
+     * this could be very bad if we caught all but the last completion
+     * and no more are imediately sent.
+     */
+    aic_outb(p, CLRCMDINT, CLRINT);
     /*
      * The sequencer will continue running when it
      * issues this interrupt. There may be >1 commands
      * finished, so loop until we've processed them all.
      */
-    qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
 
-#if 1
-  if (qoutcnt >= p->qfullcount - 1)
-    printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
-           "qoutcnt = %d.\n", qoutcnt);
-#endif
-    while (qoutcnt > 0)
+    while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
     {
-      if ((p->flags & PAGE_ENABLED) != 0)
+      scb_index = p->qoutfifo[p->qoutfifonext];
+      p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+      if ( scb_index >= p->scb_data->numscbs )
+        scb = NULL;
+      else
+        scb = p->scb_data->scb_array[scb_index];
+      if (scb == NULL)
       {
-        p->cmdoutcnt += qoutcnt;
-        if (p->cmdoutcnt >= p->qfullcount)
-        {
-          /*
-           * Since paging only occurs on aic78x0 chips, we can use
-           * Auto Access Pause to clear the command count.
-           */
-          outb(0, p->base + CMDOUTCNT);
-          p->cmdoutcnt = 0;
-        }
+        printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+          -1, -1, -1, scb_index);
+        continue;
       }
-      for (i = 0; i < qoutcnt; i++)
+      else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
       {
-        scb_index = inb(p->base + QOUTFIFO);
-        scb = p->scb_data->scb_array[scb_index];
-        if (scb == NULL)
-        {
-         printk(KERN_WARNING "scsi%d: CMDCMPLT with invalid SCB index %d, "
-                "QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
-                 inb(p->base + QOUTCNT), inb(p->base + QINCNT));
-          continue;
-        }
-        else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-        {
-         printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d, "
-                "QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
-                 p->host_no, scb_index, inb(p->base + QOUTCNT),
-                 inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
-         continue;
-        }
-        cmd = scb->cmd;
-        if (scb->hscb->residual_SG_segment_count != 0)
-        {
-          aic7xxx_calculate_residual(p, scb);
-        }
-        if ((scb->flags & SCB_QUEUED_ABORT) != 0)
-        {
-          /*
-           * Have to clean up any possible entries in the
-           * waiting queue and the QINFIFO.
-           */
-          int target;
-          char channel;
-          int lun;
-          unsigned char tag;
-
-          tag = SCB_LIST_NULL;
-          target = cmd->target;
-          lun = cmd->lun;
-          channel = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
-          if (scb->hscb->control & TAG_ENB)
+        printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+          "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+          (unsigned long) scb->cmd);
+        continue;
+      }
+      switch (status_byte(scb->hscb->target_status))
+      {
+        case QUEUE_FULL:
+        case BUSY:
+          scb->hscb->target_status = 0;
+          scb->cmd->result = 0;
+          aic7xxx_error(scb->cmd) = DID_OK;
+          break;
+        default:
+          cmd = scb->cmd;
+          if (scb->hscb->residual_SG_segment_count != 0)
           {
-            tag = scb->hscb->tag;
+            aic7xxx_calculate_residual(p, scb);
           }
-          aic7xxx_reset_device(p, target, channel, lun, tag);
-          /*
-           * Run the done queue, but don't complete the commands; we
-           * do this once at the end of the loop.
-           */
-          aic7xxx_run_done_queue(p, /*complete*/ FALSE);
-        }
-        cmd->result |= (aic7xxx_error(cmd) << 16);
-        p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-        aic7xxx_done(p, scb);
-      }
-      /*
-       * Clear interrupt status before checking the output queue again.
-       * This eliminates a race condition whereby a command could
-       * complete between the queue poll and the interrupt clearing,
-       * so notification of the command being complete never made it
-       * back up to the kernel.
-       */
-      outb(CLRCMDINT, p->base + CLRINT);
-      interrupts_cleared++;
-      qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
-    }
-
-    if (interrupts_cleared == 0)
-    {
-      outb(CLRCMDINT, p->base + CLRINT);
+          cmd->result |= (aic7xxx_error(cmd) << 16);
+          if (scb->tag_action)
+            p->dev_flags[TARGET_INDEX(cmd)] |= 
+               DEVICE_TAGGED_SUCCESS | DEVICE_SUCCESS | DEVICE_PRESENT;
+          else
+            p->dev_flags[TARGET_INDEX(cmd)] |= 
+               DEVICE_SUCCESS | DEVICE_PRESENT;
+          aic7xxx_done(p, scb);
+          break;
+      }      
     }
-
-    aic7xxx_done_cmds_complete(p);
   }
 
   if (intstat & BRKADRINT)
   {
     int i;
-    unsigned char errno = inb(p->base + ERROR);
+    unsigned char errno = aic_inb(p, ERROR);
 
-    printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+    printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno);
     for (i = 0; i < NUMBER(hard_error); i++)
     {
       if (errno & hard_error[i].errno)
@@ -3971,11 +5049,15 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
         printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
       }
     }
-    printk("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
-           inb(p->base + ERROR),
-           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-    aic7xxx_reset_device(p, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL);
-    aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+    printk(KERN_ERR "(scsi%d)   LINE=%d\n", p->host_no,
+      (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
+    aic7xxx_reset_channel(p, 0, TRUE);
+    if ( p->type & AHC_TWIN )
+    {
+      aic7xxx_reset_channel(p, 1, TRUE);
+      restart_sequencer(p);
+    }
+    aic_outb(p, CLRBRKADRINT, CLRINT);
   }
 
   if (intstat & SEQINT)
@@ -3987,14 +5069,36 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
   {
     aic7xxx_handle_scsiint(p, intstat);
   }
-
-  if (p->waiting_scbs.head != NULL)
+  DRIVER_UNLOCK
+  if(!(p->flags & (AHC_IN_ABORT | AHC_IN_RESET)))
   {
+    aic7xxx_done_cmds_complete(p);
     aic7xxx_run_waiting_queues(p);
   }
+  p->flags &= ~AHC_IN_ISR;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_isr
+ *
+ * Description:
+ *   This is a gross hack to solve a problem in linux kernels 2.1.85 and
+ *   above.  Please, children, do not try this at home, and if you ever see
+ *   anything like it, please inform the Gross Hack Police immediately
+ *-F*************************************************************************/
+static void
+do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,93)
+  unsigned long flags;
 
-  p->flags &= ~IN_ISR;
-  restore_flags(flags);
+  spin_lock_irqsave(&io_request_lock, flags);
+  aic7xxx_isr(irq, dev_id, regs);
+  spin_unlock_irqrestore(&io_request_lock, flags);
+#else
+  aic7xxx_isr(irq, dev_id, regs);
+#endif
 }
 
 /*+F*************************************************************************
@@ -4017,54 +5121,58 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
 static void
 aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
 {
-  int default_depth = 2;
+  int default_depth = 3;
+  unsigned char tindex;
+  unsigned short target_mask;
+
+  tindex = device->id | (device->channel << 3);
+  target_mask = (1 << tindex);
 
   device->queue_depth = default_depth;
-#ifdef AIC7XXX_TAGGED_QUEUEING
+  p->dev_mid_level_queue_depth[tindex] = 3;
+  p->dev_temp_queue_depth[tindex] = 1;
+  p->dev_max_queue_depth[tindex] = 1;
+  p->tagenable &= ~target_mask;
+
   if (device->tagged_supported)
   {
-    unsigned short target_mask;
     int tag_enabled = TRUE;
 
-    target_mask = (1 << (device->id | (device->channel << 3)));
-
 #ifdef AIC7XXX_CMDS_PER_LUN
     default_depth = AIC7XXX_CMDS_PER_LUN;
 #else
-    if (p->scb_data->maxhscbs <= 4)
-    {
-      default_depth = 4;  /* Not many SCBs to work with. */
-    }
-    else
-    {
-      default_depth = 8;
-    }
+    default_depth = 8;  /* Not many SCBs to work with. */
 #endif
  
     if (!(p->discenable & target_mask))
     {
-      printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+      if (aic7xxx_verbose & VERBOSE_QUEUE)
+        printk(INFO_LEAD "Disconnection disabled, unable to "
              "enable tagged queueing.\n",
-             p->host_no, device->id, device->channel);
+             p->host_no, device->channel, device->id, device->lun);
     }
     else
     {
-#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
-      device->queue_depth = default_depth;
-#else
       if (p->instance >= NUMBER(aic7xxx_tag_info))
       {
+        static int print_warning = TRUE;
+        if(print_warning)
+        {
+          printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
+                           " installed controllers.\n");
+          printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
+                           " the aic7xxx.c source file.\n");
+          print_warning = FALSE;
+        }
         device->queue_depth = default_depth;
       }
       else
       {
-        unsigned char  tindex;
 
-        tindex = device->id | (device->channel << 3);
-        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
+        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
         {
           tag_enabled = FALSE;
-          device->queue_depth = 2;  /* Tagged queueing is disabled. */
+          device->queue_depth = 3;  /* Tagged queueing is disabled. */
         }
         else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
         {
@@ -4076,21 +5184,24 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
             aic7xxx_tag_info[p->instance].tag_commands[tindex];
         }
       }
-#endif
       if ((device->tagged_queue == 0) && tag_enabled)
       {
-        if (aic7xxx_verbose)
+        if (aic7xxx_verbose & VERBOSE_QUEUE)
         {
-         printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
-                "queue depth %d.\n", p->host_no,
-                device->id, device->channel, device->queue_depth);
+              printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
+                p->host_no, device->channel, device->id,
+                device->lun, device->queue_depth);
         }
+        p->dev_max_queue_depth[tindex] = device->queue_depth;
+        p->dev_temp_queue_depth[tindex] = device->queue_depth;
+        p->dev_mid_level_queue_depth[tindex] = device->queue_depth;
+        p->tagenable |= target_mask;
+        p->orderedtag |= target_mask;
         device->tagged_queue = 1;
         device->current_tag = SCB_LIST_NULL;
       }
     }
   }
-#endif
 }
 
 /*+F*************************************************************************
@@ -4111,17 +5222,29 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
 {
   Scsi_Device *device;
   struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+  int scbnum;
 
+  scbnum = 0;
   for (device = scsi_devs; device != NULL; device = device->next)
   {
     if (device->host == host)
     {
       aic7xxx_device_queue_depth(p, device);
+      scbnum += device->queue_depth;
     }
   }
+  while (scbnum > p->scb_data->numscbs)
+  {
+    /*
+     * Pre-allocate the needed SCBs to get around the possibility of having
+     * to allocate some when memory is more or less exhausted and we need
+     * the SCB in order to perform a swap operation (possible deadlock)
+     */
+    if ( aic7xxx_allocate_scb(p, TRUE) == NULL )
+      return;
+  }
 }
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_probe
@@ -4144,8 +5267,8 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
  *   The fourth byte's lowest bit seems to be an enabled/disabled
  *   flag (rest of the bits are reserved?).
  *-F*************************************************************************/
-static aha_chip_type
-aic7xxx_probe(int slot, int base, aha_status_type *bios)
+static ahc_type
+aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
 {
   int i;
   unsigned char buf[4];
@@ -4153,13 +5276,13 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
   static struct {
     int n;
     unsigned char signature[sizeof(buf)];
-    aha_chip_type type;
+    ahc_type type;
     int bios_disabled;
   } AIC7xxx[] = {
-    { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
-    { 4, { 0x04, 0x90, 0x77, 0x70 }, AIC_7770, FALSE }, /* motherboard 7770  */
-    { 4, { 0x04, 0x90, 0x77, 0x56 }, AIC_284x, FALSE }, /* 284x BIOS enabled */
-    { 4, { 0x04, 0x90, 0x77, 0x57 }, AIC_284x, TRUE }   /* 284x BIOS disabled */
+    { 4, { 0x04, 0x90, 0x77, 0x71 }, AHC_274, FALSE }, /* host adapter 274x */
+    { 4, { 0x04, 0x90, 0x77, 0x70 }, AHC_AIC7770, FALSE },  /* mb 7770  */
+    { 4, { 0x04, 0x90, 0x77, 0x56 }, AHC_284, FALSE }, /* 284x BIOS enabled */
+    { 4, { 0x04, 0x90, 0x77, 0x57 }, AHC_284, TRUE }   /* 284x BIOS disabled */
   };
 
   /*
@@ -4183,13 +5306,13 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
       {
         if (AIC7xxx[i].bios_disabled)
         {
-          *bios = AIC_DISABLED;
+          *flags |= AHC_USEDEFAULTS;
         }
         else
         {
-          *bios = AIC_ENABLED;
+          *flags |= AHC_BIOS_ENABLED;
         }
-       return (AIC7xxx[i].type);
+        return (AIC7xxx[i].type);
       }
 
       printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
@@ -4197,9 +5320,8 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
     }
   }
 
-  return (AIC_NONE);
+  return (AHC_NONE);
 }
-#endif /* __sparc_v9__ or __powerpc__ */
 
 /*+F*************************************************************************
  * Function:
@@ -4236,11 +5358,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0)        \
-  {                                            \
-    ;  /* Do nothing */                                \
-  }                                            \
-  (void) inb(p->base + SEECTL_2840);
+  while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
+  }                                                \
+  (void) aic_inb(p, SEECTL_2840);
 
   /*
    * Read the first 32 registers of the seeprom.  For the 2840,
@@ -4253,7 +5375,7 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     /*
      * Send chip select for one clock cycle.
      */
-    outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+    aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
     CLOCK_PULSE(p);
 
     /*
@@ -4263,10 +5385,10 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = CS_2840 | seeprom_read.bits[i];
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
     /*
@@ -4277,10 +5399,10 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
       temp = k;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = CS_2840 | temp;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
 
@@ -4293,11 +5415,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     for (i = 0; i <= 16; i++)
     {
       temp = CS_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
-      outb(temp, p->base + SEECTL_2840);
+      seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
     /*
@@ -4314,11 +5436,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(0, p->base + SEECTL_2840);
+    aic_outb(p, 0, SEECTL_2840);
     CLOCK_PULSE(p);
-    outb(CK_2840, p->base + SEECTL_2840);
+    aic_outb(p, CK_2840, SEECTL_2840);
     CLOCK_PULSE(p);
-    outb(0, p->base + SEECTL_2840);
+    aic_outb(p, 0, SEECTL_2840);
     CLOCK_PULSE(p);
   }
 
@@ -4365,16 +5487,16 @@ acquire_seeprom(struct aic7xxx_host *p)
    * is needed.  Reason: after the 7870 chip reset, there
    * should be no contention.
    */
-  outb(SEEMS, p->base + SEECTL);
+  aic_outb(p, SEEMS, SEECTL);
   wait = 1000;  /* 1000 msec = 1 second */
-  while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+  while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
   {
     wait--;
     udelay(1000);  /* 1 msec */
   }
-  if ((inb(p->base + SEECTL) & SEERDY) == 0)
+  if ((aic_inb(p, SEECTL) & SEERDY) == 0)
   {
-    outb(0, p->base + SEECTL);
+    aic_outb(p, 0, SEECTL);
     return (0);
   }
   return (1);
@@ -4390,7 +5512,7 @@ acquire_seeprom(struct aic7xxx_host *p)
 static inline void
 release_seeprom(struct aic7xxx_host *p)
 {
-  outb(0, p->base + SEECTL);
+  aic_outb(p, 0, SEECTL);
 }
 
 /*+F*************************************************************************
@@ -4444,8 +5566,8 @@ release_seeprom(struct aic7xxx_host *p)
  *   this case, has no implied timing.
  *-F*************************************************************************/
 static int
-read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
-    unsigned int len, seeprom_chip_type chip)
+read_seeprom(struct aic7xxx_host *p, int offset, 
+    unsigned short *scarray, unsigned int len, seeprom_chip_type chip)
 {
   int i = 0, k;
   unsigned char temp;
@@ -4457,9 +5579,9 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + SEECTL) & SEERDY) == 0)        \
-  {                                            \
-    ;  /* Do nothing */                                \
+  while ((aic_inb(p, SEECTL) & SEERDY) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
   }
 
   /*
@@ -4482,7 +5604,7 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     /*
      * Send chip select for one clock cycle.
      */
-    outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+    aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
     CLOCK_PULSE(p);
 
     /*
@@ -4492,10 +5614,10 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
     /*
@@ -4506,10 +5628,10 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
       temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
 
@@ -4522,11 +5644,11 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     for (i = 0; i <= 16; i++)
     {
       temp = SEEMS | SEECS;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
-      outb(temp, p->base + SEECTL);
+      scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
 
@@ -4544,11 +5666,11 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(SEEMS, p->base + SEECTL);
+    aic_outb(p, SEEMS, SEECTL);
     CLOCK_PULSE(p);
-    outb(SEEMS | SEECK, p->base + SEECTL);
+    aic_outb(p, SEEMS | SEECK, SEECTL);
     CLOCK_PULSE(p);
-    outb(SEEMS, p->base + SEECTL);
+    aic_outb(p, SEEMS, SEECTL);
     CLOCK_PULSE(p);
   }
 
@@ -4571,7 +5693,6 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
   }
   printk("\n");
 #endif
-
   if (checksum != scarray[len - 1])
   {
     return (0);
@@ -4594,13 +5715,13 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
   unsigned char brdctl;
 
   brdctl = BRDCS | BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl |= value;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl &= ~BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl &= ~BRDCS;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
 }
 
 /*+F*************************************************************************
@@ -4613,8 +5734,77 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
 static inline unsigned char
 read_brdctl(struct aic7xxx_host *p)
 {
-  outb(BRDRW | BRDCS, p->base + BRDCTL);
-  return (inb(p->base + BRDCTL));
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  return (aic_inb(p, BRDCTL));
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic785x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic785x class controller chips
+ *-F*************************************************************************/
+static void
+aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  aic_outb(p, 0, BRDCTL);
+  brdctl = aic_inb(p, BRDCTL);
+  *int_50 = !(brdctl & BRDDAT5);
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = ( aic_inb(p, SPIOCAP) & EEPROM ) != 0;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic787x class controller chips
+ *
+ * NOTE: This functions assumes the SEEPROM will have already been aquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  /*
+   * First read the status of our cables.  Set the rom bank to
+   * 0 since the bank setting serves as a multiplexor for the
+   * cable detection logic.  BRDDAT5 controls the bank switch.
+   */
+  write_brdctl(p, 0);
+
+  /*
+   * Now we read the state of the two internal connectors.  BRDDAT6
+   * is internal 50, BRDDAT7 is internal 68.  For each, the cable is
+   * present if the bit is 0
+   */
+  brdctl = read_brdctl(p);
+  *int_50 = !(brdctl & BRDDAT6);
+  *int_68 = !(brdctl & BRDDAT7);
+
+  /*
+   * Set the bank bit in brdctl and then read the external cable state
+   * and the EEPROM status
+   */
+  write_brdctl(p, BRDDAT5);
+  brdctl = read_brdctl(p);
+
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = (brdctl & BRDDAT7);
+
+  /*
+   * We're done, the calling function will release the SEEPROM for us
+   */
+  
 }
 
 /*+F*************************************************************************
@@ -4629,82 +5819,72 @@ static void
 configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
     unsigned short adapter_control, unsigned char max_targ)
 {
-  unsigned char brdctl_int, brdctl_ext;
   int internal50_present;
   int internal68_present = 0;
   int external_present = 0;
   int eprom_present;
   int high_on;
   int low_on;
-  int old_verbose;
 
   if (acquire_seeprom(p))
   {
     if (adapter_control & CFAUTOTERM)
     {
-      old_verbose = aic7xxx_verbose;
-      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination.  Please "
-                       "verify driver\n");
-      printk(KERN_INFO "         detected settings and use manual termination "
-                       "if necessary.\n"); 
-
+      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination on "
+                       "controller:\n");
+      printk(KERN_INFO "aic7xxx: <%s> at ", board_names[p->board_name_index]);
+      switch(p->type & 0x1ff1)
+      {
+        case AHC_AIC7770:
+        case AHC_274:
+          printk("EISA slot %d\n", p->pci_device_fn);
+          break;
+        case AHC_284:
+          printk("VLB slot %d\n", p->pci_device_fn);
+          break;
+        default:
+          printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+            PCI_FUNC(p->pci_device_fn));
+          break;
+      }
+      printk(KERN_INFO "aic7xxx: Please verify driver detected settings are "
+        "correct.\n");
+      printk(KERN_INFO "aic7xxx: If not, then please properly set the device "
+        "termination\n");
+      printk(KERN_INFO "aic7xxx: in the Adaptec SCSI BIOS by hitting CTRL-A "
+        "when prompted\n");
+      printk(KERN_INFO "aic7xxx: during machine bootup.\n");
       /* Configure auto termination. */
-      outb(SEECS | SEEMS, p->base + SEECTL);
+      aic_outb(p, SEECS | SEEMS, SEECTL);
 
-      /*
-       * First read the status of our cables.  Set the rom bank to
-       * 0 since the bank setting serves as a multiplexor for the
-       * cable detection logic.  BRDDAT5 controls the bank switch.
-       */
-      write_brdctl(p, 0);
-
-      /*
-       * Now read the state of the internal connectors.  The
-       * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
-       * set when cables are not present (BRDDAT6 is INT50 and
-       * BRDDAT7 is INT68).
-       */
-      brdctl_int = read_brdctl(p);
-      internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
+      if ( (p->type & AHC_AIC7860) == AHC_AIC7860 )
+      {
+        aic785x_cable_detect(p, &internal50_present, &external_present,
+          &eprom_present);
+      }
+      else
+      {
+        aic787x_cable_detect(p, &internal50_present, &internal68_present,
+          &external_present, &eprom_present);
+      }
       if (max_targ > 8)
       {
-        internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
+        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
+               "Ext-68 %s)\n",
+               internal50_present ? "YES" : "NO",
+               internal68_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
       }
-
-      /*
-       * Set the rom bank to 1 and determine
-       * the other signals.
-       */
-      write_brdctl(p, BRDDAT5);
-
-      /*
-       * Now read the state of the external connectors.  BRDDAT6 is
-       * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
-       * set when the eprom is present.
-       */
-      brdctl_ext = read_brdctl(p);
-      external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
-      eprom_present = brdctl_ext & BRDDAT7;
-      if (aic7xxx_verbose)
+      else
       {
-        if (max_targ > 8)
-        {
-          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
-                 "Ext-68 %s)\n",
-                 internal50_present ? "YES" : "NO",
-                 internal68_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
-        }
-        else
-        {
-          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
-                 internal50_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
-        }
-        printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
-               "brdctl_ext=0x%x\n",
-               eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
+        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+               internal50_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
+        internal68_present = 0;
       }
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "aic7xxx: EEPROM %s present.\n",
+             eprom_present ? "is" : "is not");
 
       /*
        * Now set the termination based on what we found.  BRDDAT6
@@ -4718,16 +5898,18 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
         high_on = TRUE;
       }
 
-      if ((internal50_present + internal68_present + external_present) <= 1)
+      if ( ( (internal50_present ? 1 : 0) +
+             (internal68_present ? 1 : 0) +
+             (external_present   ? 1 : 0) ) <= 1)
       {
         low_on = TRUE;
       }
           
       if (internal50_present && internal68_present && external_present)
       {
-        printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
-               "         Only two connectors on the adapter may be "
-               "used at a time!\n");
+        printk(KERN_INFO "aic7xxx: Illegal cable configuration!!  Only two\n");
+        printk(KERN_INFO "aic7xxx: connectors on the SCSI controller may be "
+               "in use at a time!\n");
       }
 
       if (high_on == TRUE)
@@ -4738,28 +5920,23 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
       if (low_on == TRUE)
         *sxfrctl1 |= STPWEN;
 
-      if (aic7xxx_verbose)
+      if (max_targ > 8)
       {
-        if (max_targ > 8)
-        {
-          printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
-                 low_on ? "ON" : "OFF",
-                 high_on ? "ON" : "OFF");
-        }
-        else
-        {
-          printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
-        }
+        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+              low_on ? "ON" : "OFF", high_on ? "ON" : "OFF");
+      }
+      else
+      {
+        printk(KERN_INFO "aic7xxx: Termination %s\n",
+          low_on ? "Enabled" : "Disabled");
       }
-      aic7xxx_verbose = old_verbose;
     }
     else
     {
       if (adapter_control & CFSTERM)
-      {
         *sxfrctl1 |= STPWEN;
-      }
-      outb(SEEMS | SEECS, p->base + SEECTL);
+
+      aic_outb(p, SEEMS | SEECS, SEECTL);
       /*
        * Configure high byte termination.
        */
@@ -4771,7 +5948,7 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
       {
         write_brdctl(p, 0);
       }
-      if (aic7xxx_verbose)
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
       {
         printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
                (adapter_control & CFSTERM) ? "ON" : "OFF",
@@ -4794,7 +5971,6 @@ static void
 detect_maxscb(struct aic7xxx_host *p)
 {
   int i;
-  unsigned char max_scbid = 255;
 
   /*
    * It's possible that we've already done this for multichannel
@@ -4806,90 +5982,35 @@ detect_maxscb(struct aic7xxx_host *p)
      * We haven't initialized the SCB settings yet.  Walk the SCBs to
      * determince how many there are.
      */
-    outb(0, p->base + FREE_SCBH);
+    aic_outb(p, 0, FREE_SCBH);
 
     for (i = 0; i < AIC7XXX_MAXSCB; i++)
     {
-      outb(i, p->base + SCBPTR);
-      outb(i, p->base + SCB_CONTROL);
-      if (inb(p->base + SCB_CONTROL) != i)
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, i, SCB_CONTROL);
+      if (aic_inb(p, SCB_CONTROL) != i)
         break;
-      outb(0, p->base + SCBPTR);
-      if (inb(p->base + SCB_CONTROL) != 0)
+      aic_outb(p, 0, SCBPTR);
+      if (aic_inb(p, SCB_CONTROL) != 0)
         break;
 
-      outb(i, p->base + SCBPTR);
-      outb(0, p->base + SCB_CONTROL);   /* Clear the control byte. */
-      outb(i + 1, p->base + SCB_NEXT);  /* Set the next pointer. */
-      outb(SCB_LIST_NULL, p->base + SCB_TAG);  /* Make the tag invalid. */
-
-      /* Make the non-tagged targets not busy. */
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
+      aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
     }
 
     /* Make sure the last SCB terminates the free list. */
-    outb(i - 1, p->base + SCBPTR);
-    outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+    aic_outb(p, i - 1, SCBPTR);
+    aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
 
     /* Ensure we clear the first (0) SCBs control byte. */
-    outb(0, p->base + SCBPTR);
-    outb(0, p->base + SCB_CONTROL);
+    aic_outb(p, 0, SCBPTR);
+    aic_outb(p, 0, SCB_CONTROL);
 
     p->scb_data->maxhscbs = i;
   }
 
-  if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
-  {
-    /* Determine the number of valid bits in the FIFOs. */
-    outb(max_scbid, p->base + QINFIFO);
-    max_scbid = inb(p->base + QINFIFO);
-    p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
-  }
-  else
-  {
-    p->scb_data->maxscbs = p->scb_data->maxhscbs;
-  }
-  if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
-  {
-    /*
-     * Disable paging if the QINFIFO doesn't allow more SCBs than
-     * we have in hardware.
-     */
-    p->flags &= ~PAGE_ENABLED;
-  }
-
-  /*
-   * Set the Queue Full Count.  Some cards have more queue space than
-   * SCBs.
-   */
-  switch (p->chip_class)
-  {
-    case AIC_777x:
-      p->qfullcount = 4;
-      p->qcntmask = 0x07;
-      break;
-    case AIC_785x:
-    case AIC_786x:
-      p->qfullcount = 8;
-      p->qcntmask = 0x0f;
-      break;
-    case AIC_787x:
-    case AIC_788x:
-      if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
-      {
-        p->qfullcount = AIC7XXX_MAXSCB;
-        p->qcntmask = 0xFF;
-      }
-      else
-      {
-        p->qfullcount = 16;
-        p->qcntmask = 0x1F;
-      }
-      break;
-  }
 }
 
 /*+F*************************************************************************
@@ -4900,15 +6021,14 @@ detect_maxscb(struct aic7xxx_host *p)
  *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
  *-F*************************************************************************/
 static int
-aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
+  int reset_delay)
 {
-  int i;
-  unsigned char sblkctl, flags = 0;
-  int max_targets, irq_flags = 0;
+  int i, result;
+  int max_targets;
   int found = 1;
-  char channel_ids[] = {'A', 'B', 'C'};
   unsigned char target_settings;
-  unsigned char scsi_conf, sxfrctl1;
+  unsigned char term, scsi_conf, sxfrctl1;
   unsigned short ultraenable = 0;
   struct Scsi_Host *host;
 
@@ -4917,78 +6037,12 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
    */
   request_region(p->base, MAXREG - MINREG, "aic7xxx");
 
-  /*
-   * Read the bus type from the SBLKCTL register. Set the FLAGS
-   * register in the sequencer for twin and wide bus cards.
-   */
-  sblkctl = inb(p->base + SBLKCTL);
-  if (p->flags & PAGE_ENABLED)
-    flags = PAGESCBS;
-
-  switch (sblkctl & SELBUS_MASK)
-  {
-    case SELNARROW:     /* narrow/normal bus */
-      p->scsi_id = inb(p->base + SCSICONF) & 0x07;
-      p->bus_type = AIC_SINGLE;
-      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
-      if (p->flags & MULTI_CHANNEL)
-      {
-        printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
-               channel_ids[p->chan_num], p->scsi_id);
-      }
-      else
-      {
-        printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
-                p->scsi_id);
-      }
-      outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
-      break;
 
-    case SELWIDE:     /* Wide bus */
-      p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
-      p->bus_type = AIC_WIDE;
-      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
-      if (p->flags & MULTI_CHANNEL)
-      {
-        printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
-               channel_ids[p->chan_num], p->scsi_id);
-      }
-      else
-      {
-        printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
-                p->scsi_id);
-      }
-      outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
-      break;
+  host = p->host;
 
-    case SELBUSB:     /* Twin bus */
-      p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
-      p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
-      p->bus_type = AIC_TWIN;
-      printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
-             p->scsi_id, p->scsi_id_b);
-      outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
-      break;
-
-    default:
-      printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
-            "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
-      outb(0, p->base + SEQ_FLAGS);
-      return (0);
-  }
-
-  /*
-   * Detect SCB parameters and initialize the SCB array.
-   */
-  detect_maxscb(p);
-  printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
-         p->scb_data->maxhscbs, p->scb_data->maxscbs,
-         p->qfullcount, p->qcntmask);
-
-  host = p->host;
-
-  host->can_queue = p->scb_data->maxscbs;
-  host->cmd_per_lun = 2;
+  p->scb_data->maxscbs = AIC7XXX_MAXSCB;
+  host->can_queue = AIC7XXX_MAXSCB;
+  host->cmd_per_lun = 3;
   host->sg_tablesize = AIC7XXX_MAX_SG;
   host->select_queue_depths = aic7xxx_select_queue_depth;
   host->this_id = p->scsi_id;
@@ -4996,110 +6050,231 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   host->n_io_port = 0xFF;
   host->base = (unsigned char *) p->mbase;
   host->irq = p->irq;
-  if (p->bus_type == AIC_WIDE)
+  if (p->type & AHC_WIDE)
   {
     host->max_id = 16;
   }
-  if (p->bus_type == AIC_TWIN)
+  if (p->type & AHC_TWIN)
   {
     host->max_channel = 1;
   }
 
   p->host = host;
+  p->last_reset = 0;
   p->host_no = host->host_no;
   p->isr_count = 0;
+  p->next = NULL;
   p->completeq.head = NULL;
   p->completeq.tail = NULL;
   scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
 
-  for (i = 0; i < NUMBER(p->device_status); i++)
+  for (i = 0; i < NUMBER(p->untagged_scbs); i++)
+  {
+    p->untagged_scbs[i] = SCB_LIST_NULL;
+    p->qinfifo[i] = SCB_LIST_NULL;
+    p->qoutfifo[i] = SCB_LIST_NULL;
+  }
+  /*
+   * We currently have no commands of any type
+   */
+  p->qinfifonext = 0;
+  p->qoutfifonext = 0;
+
+  for (i = 0; i < MAX_TARGETS; i++)
+  {
+    p->dev_commands_sent[i] = 0;
+    p->dev_flags[i] = DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+    p->dev_active_cmds[i] = 0;
+    p->dev_last_reset[i] = 0;
+    p->dev_last_queue_full[i] = 0;
+    p->dev_last_queue_full_count[i] = 0;
+    p->dev_max_queue_depth[i] = 1;
+    p->dev_temp_queue_depth[i] = 1;
+    p->dev_mid_level_queue_depth[i] = 3;
+    scbq_init(&p->delayed_scbs[i]);
+    init_timer(&p->dev_timer[i]);
+    p->dev_timer[i].expires = 0;
+    p->dev_timer[i].data = (unsigned long)p;
+    p->dev_timer[i].function = (void *)aic7xxx_timer;
+    p->syncinfo[i].period = 0;
+    p->syncinfo[i].offset = 0;
+  }
+
+  printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
+    board_names[p->board_name_index]);
+  switch(p->type & 0x1ff1)
+  {
+    case AHC_AIC7770:
+    case AHC_274:
+      printk("EISA slot %d\n", p->pci_device_fn);
+      break;
+    case AHC_284:
+      printk("VLB slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+        PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+  if (p->type & AHC_TWIN)
+  {
+    printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+           p->host_no, p->scsi_id, p->scsi_id_b);
+  }
+  else
   {
-    p->device_status[i].commands_sent = 0;
-    p->device_status[i].flags = 0;
-    p->device_status[i].active_cmds = 0;
-    p->device_status[i].last_reset = 0;
+    char *channel;
+
+    channel = "";
+
+    if ((p->type & AHC_39x) != 0)
+    {
+      channel = " A";
+
+      if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
+      {
+        channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+    }
+    if (p->type & AHC_WIDE)
+    {
+      printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
+    }
+    else
+    {
+      printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
+    }
+    printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
   }
+  aic_outb(p, 0, SEQ_FLAGS);
 
   /*
-   * Request an IRQ for the board. Only allow sharing IRQs with PCI devices.
+   * Detect SCB parameters and initialize the SCB array.
    */
-#ifdef AIC7XXX_OLD_ISR_TYPE
-  irq_flags = SA_INTERRUPT;
-#endif
-  if (p->chip_class != AIC_777x)
-    irq_flags |= SA_SHIRQ;
-  if (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", p) < 0)
+  detect_maxscb(p);
+  printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
+  printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
+    p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
+    p->base, p->irq);
+  printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n",
+    p->host_no, p->mbase, (unsigned long)p->maddr);
+
+
+
+  /*
+   * Register IRQ with the kernel.  Only allow sharing IRQs with
+   * PCI devices.
+   */
+  if ((p->type & AHC_AIC7770) == AHC_AIC7770)
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
+  }
+  else
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+              "aic7xxx", p));
+    if (result < 0)
+    {
+      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+              "aic7xxx", p));
+    }
+  }
+  if (result < 0)
   {
-    printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
-           p->irq);
+    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring.\n",
+           p->host_no, p->irq);
     return (0);
   }
 
   /*
    * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
    */
-  if (p->bus_type == AIC_TWIN)
+  if (p->type & AHC_TWIN)
   {
     /*
      * The controller is gated to channel B after a chip reset; set
      * bus B values first.
      */
-    outb(p->scsi_id_b, p->base + SCSIID);
-    scsi_conf = inb(p->base + SCSICONF + 1);
-    sxfrctl1 = inb(p->base + SXFRCTL1);
-    outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
-         ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
-    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
-    if (p->flags & ULTRA_ENABLED)
+    term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0;
+    aic_outb(p, p->scsi_id_b, SCSIID);
+    scsi_conf = aic_inb(p, SCSICONF + 1);
+    sxfrctl1 = aic_inb(p, SXFRCTL1);
+    aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term | 
+         ENSTIMER | ACTNEGEN, SXFRCTL1);
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+    if (p->type & AHC_ULTRA)
     {
-      outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+      aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
     }
     else
     {
-      outb(DFON | SPIOEN, p->base + SXFRCTL0);
+      aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+    }
+    if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+    {
+      scsi_conf &= ~0x07;
+      scsi_conf |= p->scsi_id_b;
+      aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF + 1);
     }
-
     if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
     {
       /* Reset SCSI bus B. */
-      if (aic7xxx_verbose)
-        printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+      if (aic7xxx_verbose & VERBOSE_PROBE)
+        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
 
       aic7xxx_reset_current_bus(p);
     }
 
     /* Select channel A */
-    outb(SELNARROW, p->base + SBLKCTL);
+    aic_outb(p, SELNARROW, SBLKCTL);
   }
 
-  outb(p->scsi_id, p->base + SCSIID);
-  scsi_conf = inb(p->base + SCSICONF);
-  sxfrctl1 = inb(p->base + SXFRCTL1);
-  outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
-       ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
-  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
-  if (p->flags & ULTRA_ENABLED)
+  term = ((p->flags & AHC_TERM_ENB_A) != 0) ? STPWEN : 0;
+  aic_outb(p, p->scsi_id, SCSIID);
+  scsi_conf = aic_inb(p, SCSICONF);
+  sxfrctl1 = aic_inb(p, SXFRCTL1);
+  aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term | 
+       ENSTIMER | ACTNEGEN, SXFRCTL1);
+  aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+  if (p->type & AHC_ULTRA)
   {
-    outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+    aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
   }
   else
   {
-    outb(DFON | SPIOEN, p->base + SXFRCTL0);
+    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+  }
+  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+  {
+    scsi_conf &= ~0x07;
+    scsi_conf |= p->scsi_id;
+    aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF);
   }
 
+
   if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
   {
     /* Reset SCSI bus A. */
-    if (aic7xxx_verbose)
-      printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+    if (aic7xxx_verbose & VERBOSE_PROBE)
+    {  /* In case we are a 3940, 3985, or 7895, print the right channel */
+      char *channel = "";
+      if (p->flags & AHC_MULTI_CHANNEL)
+      {
+        channel = " A";
+        if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+          channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+      printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
+    }
 
     aic7xxx_reset_current_bus(p);
 
     /*
      * Delay for the reset delay.
      */
-    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+    if (!reset_delay)
+      aic7xxx_delay(AIC7XXX_RESET_DELAY);
   }
 
   /*
@@ -5114,7 +6289,10 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   p->sdtr_pending = 0x0;
   p->needwdtr_copy = 0x0;
   p->wdtr_pending = 0x0;
-  if (p->bus_type == AIC_SINGLE)
+  p->tagenable = 0x0;
+  p->ultraenb = 0x0;
+  p->discenable = 0xffff;
+  if ((p->type & (AHC_TWIN|AHC_WIDE)) == 0)
   {
     max_targets = 8;
   }
@@ -5126,31 +6304,36 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   /*
    * Grab the disconnection disable table and invert it for our needs
    */
-  if (p->flags & USE_DEFAULTS)
+  if (p->flags & AHC_USEDEFAULTS)
   {
-    printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
-           "device parameters.\n");
-    p->discenable = 0xFFFF;
+    printk(KERN_INFO "(scsi%d) Host adapter BIOS disabled. Using default SCSI "
+           "device parameters.\n", p->host_no);
+    if (p->type & AHC_ULTRA)
+      p->ultraenb = 0xffff;
+    p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
   }
   else
   {
-    p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
-        inb(p->base + DISC_DSB));
+    p->discenable = ~((aic_inb(p, DISC_DSB + 1) << 8) |
+        aic_inb(p, DISC_DSB));
+    if (p->type & AHC_ULTRA)
+      p->ultraenb = (aic_inb(p, ULTRA_ENB + 1) << 8) | 
+          aic_inb(p, ULTRA_ENB);
   }
 
   for (i = 0; i < max_targets; i++)
   {
-    if (p->flags & USE_DEFAULTS)
+    if (p->flags & AHC_USEDEFAULTS)
     {
       target_settings = 0;  /* 10 or 20 MHz depending on Ultra enable */
       p->needsdtr_copy |= (0x01 << i);
       p->needwdtr_copy |= (0x01 << i);
-      if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+      if (p->type & AHC_ULTRA)
         ultraenable |= (0x01 << i);
     }
     else
     {
-      target_settings = inb(p->base + TARG_SCRATCH + i);
+      target_settings = aic_inb(p, TARG_SCRATCH + i);
       if (target_settings & 0x0F)
       {
         p->needsdtr_copy |= (0x01 << i);
@@ -5168,24 +6351,33 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
          */
         target_settings &= 0x7F;
       }
-      if (p->flags & ULTRA_ENABLED)
+    }
+
+    aic_outb(p, target_settings, TARG_SCRATCH + i);
+    if (p->needsdtr_copy & (0x01 << i))
+    {
+      short sxfr, j;
+
+      sxfr = target_settings & SXFR;
+      if ((p->ultraenb & (1 << i)) != 0)
+      {
+        /* Want an ultra speed in the table */
+        sxfr |= 0x100;
+      }
+      for (j = 0; j < NUMBER(aic7xxx_syncrates); j++)
       {
-        switch (target_settings & 0x70)
-        {
-          case 0x00:
-          case 0x10:
-          case 0x20:
-            ultraenable |= (0x01 << i);
-            break;
-          case 0x40:  /* treat 10MHz as 10MHz without Ultra enabled */
-            target_settings &= ~(0x70);
-            break;
-          default:
-            break;
-        }
+        if (sxfr == aic7xxx_syncrates[j].rate)
+          break;
       }
+      p->syncinfo[i].period = aic7xxx_syncrates[j].period;
+      p->syncinfo[i].offset =
+       (p->type & AHC_WIDE) ? MAX_OFFSET_16BIT : MAX_OFFSET_8BIT;
+    }
+    else
+    {
+      p->syncinfo[i].period = 0;
+      p->syncinfo[i].offset = 0;
     }
-    outb(target_settings, p->base + TARG_SCRATCH + i);
   }
 
   /*
@@ -5193,26 +6385,14 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
    * work on some cards that don't leave these fields cleared
    * when BIOS is not installed.
    */
-  if (p->bus_type != AIC_WIDE)
+  if ( !(p->type & AHC_WIDE))
   {
     p->needwdtr_copy = 0;
   }
   p->needsdtr = p->needsdtr_copy;
   p->needwdtr = p->needwdtr_copy;
-  p->orderedtag = 0;
-  outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
-  outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
-
-  /*
-   * Set the number of available hardware SCBs.
-   */
-  outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
-
-  /*
-   * 2s compliment of maximum tag value.
-   */
-  i = p->scb_data->maxscbs;
-  outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
+  aic_outb(p, 0, ULTRA_ENB);
+  aic_outb(p, 0, ULTRA_ENB + 1);
 
   /*
    * Allocate enough hardware scbs to handle the maximum number of
@@ -5230,8 +6410,8 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
     p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
     if (p->scb_data->hscbs == NULL)
     {
-      printk("aic7xxx: Unable to allocate hardware SCB array; "
-             "failing detection.\n");
+      printk("(scsi%d) Unable to allocate hardware SCB array; "
+             "failing detection.\n", p->host_no);
       release_region(p->base, MAXREG - MINREG);
       free_irq(p->irq, p);
       return(0);
@@ -5241,40 +6421,35 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
 
     /* Tell the sequencer where it can find the hardware SCB array. */
     hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
-    outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
-    outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
-    outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
-    outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
-  }
+    aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
 
-  /*
-   * QCount mask to deal with broken aic7850s that sporadically get
-   * garbage in the upper bits of their QCNT registers.
-    */
-  outb(p->qcntmask, p->base + QCNTMASK);
+    /* Set up the fifo areas at the same time */
+    hscb_physaddr = VIRT_TO_BUS(&p->untagged_scbs[0]);
+    aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
+
+    /* The Q-FIFOs we just set up are all empty */
+    aic_outb(p, 0, QINPOS);
+    aic_outb(p, 0, KERNEL_QINPOS);
+    aic_outb(p, 0, QOUTPOS);
 
-  /*
-   * Set FIFO depth and command out count.  These are only used when
-   * paging is enabled and should not be touched for AIC-7770 based
-   * adapters; FIFODEPTH and CMDOUTCNT overlay SCSICONF and SCSICONF+1
-   * which are used to control termination.
-   */
-  if (p->flags & PAGE_ENABLED)
-  {
-    outb(p->qfullcount, p->base + FIFODEPTH);
-    outb(0, p->base + CMDOUTCNT);
   }
 
   /*
    * We don't have any waiting selections or disconnected SCBs.
    */
-  outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
-  outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+  aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+  aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
 
   /*
    * Message out buffer starts empty
    */
-  outb(0, p->base + MSG_LEN);
+  aic_outb(p, MSG_NOOP, MSG_OUT);
 
   /*
    * Load the sequencer program, then re-enable the board -
@@ -5285,11 +6460,17 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
    */
   aic7xxx_loadseq(p);
 
-  if (p->chip_class == AIC_777x)
+  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
   {
-    outb(ENABLE, p->base + BCTL);  /* Enable the boards BUS drivers. */
+    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
   }
 
+  /*
+   * Link us into the list of valid hosts
+   */
+  p->next = first_aic7xxx;
+  first_aic7xxx = p;
+
   /*
    * Unpause the sequencer before returning and enable
    * interrupts - we shouldn't get any until the first
@@ -5297,12 +6478,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
    */
   unpause_sequencer(p, /* unpause_always */ TRUE);
 
-  /*
-   * Add it to our list of adapters.
-   */
-  p->next = first_aic7xxx;
-  first_aic7xxx = p;
-
   return (found);
 }
 
@@ -5314,38 +6489,56 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
  *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
  *   is paused upon return.
  *-F*************************************************************************/
-static void
+int
 aic7xxx_chip_reset(struct aic7xxx_host *p)
 {
   unsigned char hcntrl;
   int wait;
 
   /* Retain the IRQ type across the chip reset. */
-  hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+  hcntrl = (aic_inb(p, HCNTRL) & IRQMS) | INTEN;
 
   /*
    * For some 274x boards, we must clear the CHIPRST bit and pause
    * the sequencer. For some reason, this makes the driver work.
    */
-  outb(PAUSE | CHIPRST, p->base + HCNTRL);
+  aic_outb(p, PAUSE | CHIPRST, HCNTRL);
 
   /*
    * In the future, we may call this function as a last resort for
    * error handling.  Let's be nice and not do any unecessary delays.
    */
   wait = 1000;  /* 1 second (1000 * 1000 usec) */
-  while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
+  while ((wait > 0) && ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0))
   {
     udelay(1000);  /* 1 msec = 1000 usec */
     wait = wait - 1;
   }
 
-  if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+  if ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0)
   {
     printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
   }
 
-  outb(hcntrl | PAUSE, p->base + HCNTRL);
+  aic_outb(p, hcntrl | PAUSE, HCNTRL);
+
+  switch( aic_inb(p, SBLKCTL) & 0x0a )
+  {
+    case 0:  /* normal narrow card */
+      break;
+    case 2:  /* Wide card */
+      p->type |= AHC_WIDE;
+      break;
+    case 8:  /* Twin card */
+      p->type |= AHC_TWIN;
+      p->flags |= AHC_MULTI_CHANNEL;
+      break;
+    default: /* hmmm...we don't know what this is */
+      printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n",
+        aic_inb(p, SBLKCTL) & 0x0a);
+      return(-1);
+  }
+  return(0);
 }
 
 /*+F*************************************************************************
@@ -5357,8 +6550,7 @@ aic7xxx_chip_reset(struct aic7xxx_host *p)
  *   and a pointer to a aic7xxx_host struct upon success.
  *-F*************************************************************************/
 static struct aic7xxx_host *
-aic7xxx_alloc(Scsi_Host_Template *sht, unsigned long base, unsigned long mbase,
-    aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
 {
   struct aic7xxx_host *p = NULL;
   struct Scsi_Host *host;
@@ -5375,46 +6567,45 @@ aic7xxx_alloc(Scsi_Host_Template *sht, unsigned long base, unsigned long mbase,
     memset(p, 0, sizeof(struct aic7xxx_host));
     p->host = host;
 
-    if (scb_data != NULL)
+    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+    if (p->scb_data != NULL)
     {
-      /*
-       * We are sharing SCB data areas; use the SCB data pointer
-       * provided.
-       */
-      p->scb_data = scb_data;
-      p->flags |= SHARED_SCBDATA;
+      memset(p->scb_data, 0, sizeof(scb_data_type));
+      scbq_init (&p->scb_data->free_scbs);
     }
     else
     {
       /*
-       * We are not sharing SCB data; allocate one.
+       * For some reason we don't have enough memory.  Free the
+       * allocated memory for the aic7xxx_host struct, and return NULL.
        */
-      p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
-      if (p->scb_data != NULL)
-      {
-        memset(p->scb_data, 0, sizeof(scb_data_type));
-        scbq_init (&p->scb_data->free_scbs);
-      }
-      else
-      {
-        /*
-         * For some reason we don't have enough memory.  Free the
-         * allocated memory for the aic7xxx_host struct, and return NULL.
-         */
-        scsi_unregister(host);
-        p = NULL;
-      }
+      scsi_unregister(host);
+      p = NULL;
     }
     if (p != NULL)
     {
       p->host_no = host->host_no;
-      p->base = base;
-      p->mbase = mbase;
-      p->maddr = NULL;
-      p->flags = flags;
-      p->chip_type = chip_type;
-      p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
-      p->pause = p->unpause | PAUSE;
+      p->base = temp->base;
+      p->mbase = temp->mbase;
+      p->maddr = temp->maddr;
+      p->flags = temp->flags;
+      p->type = temp->type;
+      p->unpause = temp->unpause;
+      p->pause = temp->pause;
+      p->pci_bus = temp->pci_bus;
+      p->pci_device_fn = temp->pci_device_fn;
+      p->bios_address = temp->bios_address;
+      p->irq = temp->irq;
+      p->scsi_id = temp->scsi_id;
+      p->scsi_id_b = temp->scsi_id_b;
+      p->discenable = temp->discenable;
+      p->ultraenb = temp->ultraenb;
+      p->tagenable = 0;
+      p->orderedtag = 0;
+      p->board_name_index = temp->board_name_index;
+      p->adapter_control = temp->adapter_control;
+      p->bios_control = temp->bios_control;
+      DRIVER_LOCK_INIT
     }
   }
   return (p);
@@ -5429,49 +6620,48 @@ aic7xxx_alloc(Scsi_Host_Template *sht, unsigned long base, unsigned long mbase,
  *   the driver (struct aic7xxx_host *).
  *-F*************************************************************************/
 static void
-aic7xxx_free (struct aic7xxx_host *p)
+aic7xxx_free(struct aic7xxx_host *p)
 {
-  int i;
+  int i, jump;
 
   /*
-   * We should be careful in freeing the scb_data area.  For those
-   * adapters sharing external SCB RAM(398x), there will be only one
-   * scb_data area allocated.  The flag SHARED_SCBDATA indicates if
-   * one adapter is sharing anothers SCB RAM.
+   * Free the allocated hardware SCB space.
    */
-  if (!(p->flags & SHARED_SCBDATA))
+  if (p->scb_data->hscbs != NULL)
   {
-    /*
-     * Free the allocated hardware SCB space.
-     */
-    if (p->scb_data->hscbs != NULL)
-    {
-      kfree(p->scb_data->hscbs);
-    }
-    /*
-     * Free the driver SCBs.  These were allocated on an as-need
-     * basis.
-     */
-    for (i = 0; i < p->scb_data->numscbs; i++)
-    {
-      kfree(p->scb_data->scb_array[i]);
-    }
-    /*
-     * Free the hardware SCBs.
-     */
-    if (p->scb_data->hscbs != NULL)
-    {
-      kfree(p->scb_data->hscbs);
-    }
-
-    /*
-     * Free the SCB data area.
-     */
-    kfree(p->scb_data);
+    kfree(p->scb_data->hscbs);
+  }
+  /*
+   * Free the driver SCBs.  These were allocated on an as-need
+   * basis. However, we allocated them 30 at a time up until the
+   * very last allocation (if there was one).  So, we need to free
+   * every 30th pointer to free the array (this also frees the
+   * SG_array structs as well).
+   *
+   * Note, on 64 bit machines we allocate 29 at a time instead.
+   */
+  jump = (sizeof(int) == sizeof(void *)) ? 30 : 29;
+  for (i = 0; i < p->scb_data->numscbs; i += jump)
+  {
+    kfree(p->scb_data->scb_array[i]);
   }
+  /*
+   * Free the SCB data area.
+   */
+  kfree(p->scb_data);
+
   /*
    * Free the instance of the device structure.
    */
+
+  /*
+   * XXXXXXXX  FIXXXXXMEEEEEE.  How do we unmap the I/O range we have mapped
+   * if we are doing MMAPed I/O ??????????  Our biggest concern is the issue
+   * of possibly calling unmap on an area that *might* be used on another
+   * controller as well (aka, the 4096 byte MMAPed area is back to back
+   * with another controller, and the PAGE_SIZE is greater then 4096, allowing
+   * us to remap in a shared page).
+   */
   scsi_unregister(p->host);
 }
 
@@ -5492,46 +6682,42 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
   unsigned short scarray[128];
   struct seeprom_config *sc = (struct seeprom_config *) scarray;
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
   {
     printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
   }
-  switch (p->chip_type)
+  switch (p->type & 0x00001ff1)
   {
-    case AIC_7770:  /* None of these adapters have seeproms. */
-    case AIC_7771:
-    case AIC_7855:
+    case AHC_AIC7770:  /* None of these adapters have seeproms. */
+    case AHC_274:
       break;
 
-    case AIC_284x:
+    case AHC_284:
       have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
       break;
 
-    case AIC_7850:  /* The 2910B is a 7850 with a seeprom. */
-    case AIC_7861:
-    case AIC_7870:
-    case AIC_7871:
-    case AIC_7872:
-    case AIC_7874:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7884:
-      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+    case AHC_AIC7850:  /* The 2910B is a 7850 with a seeprom. */
+    case AHC_294AU:
+    case AHC_AIC7870:  /* For these controllers we try the three possible */
+    case AHC_AIC7895:  /* SEEPROM read types.  If none works, then we are */
+    case AHC_294:      /* SOL.  This should catch any SEEPROM variety     */
+    case AHC_394:      /* Adaptec or some motherboard manufacturer might  */
+    case AHC_294U:     /* throw at us, and since we perform a checksum    */
+    case AHC_394U:     /* during the read, we should get bogus seeprom    */
+    case AHC_AIC7860:  /* reads. */
+    case AHC_AIC7880:
+    case AHC_398:
+    case AHC_398U:
+      have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                   scarray, sizeof(*sc)/2, C46);
-      break;
-
-    case AIC_7860:  /* Motherboard Ultra controllers might have RAID port. */
-    case AIC_7880:
-      have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
       if (!have_seeprom)
-      {
-        have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
-      }
-      break;
-
-    case AIC_7873:  /* The 3985 adapters use the 93c56 serial EEPROM. */
-    case AIC_7883:
-      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, sizeof(scarray)/2, C46);
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, sizeof(*sc)/2, C56_66);
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                   scarray, sizeof(scarray)/2, C56_66);
       break;
 
@@ -5541,19 +6727,19 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
 
   if (!have_seeprom)
   {
-    if (aic7xxx_verbose)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
       printk("\naic7xxx: No SEEPROM available; using defaults.\n");
     }
-    p->flags |= USE_DEFAULTS;
+    p->flags |= AHC_USEDEFAULTS;
+    p->flags &= ~AHC_BIOS_ENABLED;
   }
   else
   {
-    if (aic7xxx_verbose)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
       printk("done\n");
     }
-    p->flags |= HAVE_SEEPROM;
 
     /*
      * Update the settings in sxfrctl1 to match the termination settings.
@@ -5564,14 +6750,17 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
      * First process the settings that are different between the VLB
      * and PCI adapter seeproms.
      */
-    if (p->chip_class == AIC_777x)
+    if (p->type & AHC_284)
     {
       /* VLB adapter seeproms */
       if (sc->bios_control & CF284XEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+        p->flags |= AHC_EXTEND_TRANS_A;
 
       if (sc->adapter_control & CF284XSTERM)
+      {
         *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_A;
+      }
       /*
        * The 284x SEEPROM doesn't have a max targets field.  We
        * set it to 16 to make sure we take care of the 284x-wide
@@ -5589,30 +6778,90 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
     {
       /* PCI adapter seeproms */
       if (sc->bios_control & CFEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+        p->flags |= AHC_EXTEND_TRANS_A;
 
       if (sc->adapter_control & CFSTERM)
+      {
         *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_A;
+      }
 
       /* Limit to 16 targets just in case. */
       max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
     }
 
+    p->discenable = 0;
+
+    for (i = 0; i < max_targets; i++)
+    {
+      if( (p->type & AHC_ULTRA) &&
+         !(sc->adapter_control & CFULTRAEN) &&
+          (sc->device_flags[i] & CFSYNCHISULTRA) )
+      {
+        p->flags |= AHC_NEWEEPROM_FMT;
+        break;
+      }
+    }
+
     for (i = 0; i < max_targets; i++)
     {
       target_settings = (sc->device_flags[i] & CFXFER) << 4;
       if (sc->device_flags[i] & CFSYNCH)
+      {
         target_settings |= SOFS;
+      }
       if (sc->device_flags[i] & CFWIDEB)
+      {
         target_settings |= WIDEXFER;
+      }
       if (sc->device_flags[i] & CFDISC)
+      {
         p->discenable |= (0x01 << i);
-      outb(target_settings, p->base + TARG_SCRATCH + i);
+      }
+      if (p->flags & AHC_NEWEEPROM_FMT)
+      {
+        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        {
+          p->ultraenb |= (0x01 << i);
+        }
+      }
+      else if (sc->adapter_control & CFULTRAEN)
+      {
+        p->ultraenb |= (0x01 << i);
+      }
+      if ( ((target_settings & 0x70) == 0x40) &&
+           (p->ultraenb & (0x01 << i)) )
+      {
+        target_settings &= ~0x70;
+        p->ultraenb &= ~(0x01 << i);
+      }
+      aic_outb(p, target_settings, TARG_SCRATCH + i);
     }
-    outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
-    outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
+    aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+    aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+    aic_outb(p,  (p->ultraenb & 0xFF), ULTRA_ENB);
+    aic_outb(p,  ((p->ultraenb >> 8) & 0xFF), ULTRA_ENB + 1);
 
     p->scsi_id = sc->brtime_id & CFSCSIID;
+    p->adapter_control = sc->adapter_control;
+    p->bios_control = sc->bios_control;
+
+    if (p->bios_control & CFBIOSEN)
+    {
+      p->flags &= ~AHC_USEDEFAULTS;
+      p->flags |= AHC_BIOS_ENABLED;
+    }
+    else
+    {
+      p->flags &= ~AHC_BIOS_ENABLED;
+      p->flags |= AHC_USEDEFAULTS;
+    }
+
+    if ((p->type & 0x1ff1) == AHC_AIC7895)
+    {
+      if (p->adapter_control & CFBPRIMARY)
+        p->flags |= AHC_CHANNEL_B_PRIMARY;
+    }
 
     scsi_conf = (p->scsi_id & 0x7);
     if (sc->adapter_control & CFSPARITY)
@@ -5621,37 +6870,39 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
      * The 7850 controllers with a seeprom, do not honor the CFRESETB
      * flag in the seeprom.  Assume that we want to reset the SCSI bus.
      */
-    if ((sc->adapter_control & CFRESETB) || (p->chip_class == AIC_7850))
+    if (sc->adapter_control & CFRESETB)
       scsi_conf |= RESET_SCSI;
-
-    if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
-    {
-      /*
-       * We allow the operator to override ultra enable through
-       * the boot prompt.
-       */
-      if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
-      {
-        /* Treat us as a non-ultra card */
-        p->flags &= ~ULTRA_ENABLED;
-      }
-    }
+    /*
+     * We may be a 2842, if so, preserve the TERM_ENB bit in scsi conf
+     */
+    if ( (p->flags & AHC_TERM_ENB_A) && 
+        ((p->type & AHC_AIC7770) == AHC_AIC7770) )
+      scsi_conf |= TERM_ENB;
+    /*
+     * If this is an Ultra card, is Ultra mode enabled?  If not, disable
+     * it in the host struct as well
+     */
+    if ( (p->type & AHC_ULTRA) && 
+        !(sc->adapter_control & CFULTRAEN) &&
+        !(p->flags & AHC_NEWEEPROM_FMT) )
+      p->type &= ~AHC_ULTRA;
 
     /* Set the host ID */
-    outb(scsi_conf, p->base + SCSICONF);
+    aic_outb(p, scsi_conf, SCSICONF);
     /* In case we are a wide card */
-    outb(p->scsi_id, p->base + SCSICONF + 1);
+    aic_outb(p, p->scsi_id, SCSICONF + 1);
 
-    if (p->chip_class != AIC_777x)
+    if ((p->type & AHC_AIC7860) == AHC_AIC7860)
     {
+      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
       /*
        * Update the settings in sxfrctl1 to match the termination
        * settings.
        */
-      *sxfrctl1 = 0;
-      configure_termination(p, sxfrctl1, sc->adapter_control,
-        (unsigned char) sc->max_targets & CFMAXTARG);
+        configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
     }
+    else if (have_seeprom && ((p->type & AHC_AIC7770) != AHC_AIC7770))
+      configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
   }
   return (have_seeprom);
 }
@@ -5671,28 +6922,40 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
 int
 aic7xxx_detect(Scsi_Host_Template *template)
 {
+  struct aic7xxx_host *temp_p = NULL;
+  struct aic7xxx_host *current_p = NULL;
+  struct aic7xxx_host *list_p = NULL;
   int found = 0;
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
-  aha_status_type adapter_bios;
-  unsigned char hcntrl, hostconf, irq = 0;
-  int slot, base;
+  ahc_flag_type flags = 0;
+  ahc_type type;
+  unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+  unsigned char hcntrl, hostconf;
+  unsigned int slot, base;
+#endif
+
+#ifdef MODULE
+  /*
+   * If we are called as a module, the aic7xxx pointer may not be null
+   * and it would point to our bootup string, just like on the lilo
+   * command line.  IF not NULL, then process this config string with
+   * aic7xxx_setup
+   */
+  if(aic7xxx)
+    aic7xxx_setup(aic7xxx, NULL);
+
 #endif
-  aha_chip_class_type chip_class;
-  aha_chip_type chip_type;
-  int chan_num = 0;
-  unsigned char sxfrctl1, sblkctl;
-  int i;
-  struct aic7xxx_host *p;
 
   template->proc_dir = &proc_scsi_aic7xxx;
-  template->name = aic7xxx_info(NULL);
   template->sg_tablesize = AIC7XXX_MAX_SG;
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+
+#if defined(__i386__) || defined(__alpha__)
   /*
    * EISA/VL-bus card signature probe.
    */
-  for (slot = MINSLOT; slot <= MAXSLOT; slot++)
+  slot = MINSLOT;
+  while (slot <= MAXSLOT)
   {
     base = SLOTBASE(slot) + MINREG;
 
@@ -5702,354 +6965,571 @@ aic7xxx_detect(Scsi_Host_Template *template)
        * Some other driver has staked a
        * claim to this i/o region already.
        */
-      continue;
+      slot++;
+      continue; /* back to the beginning of the for loop */
     }
-
-    chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
-    if (chip_type != AIC_NONE)
+    flags = 0;
+    type = aic7xxx_probe(slot, base + HID0, &flags);
+    switch (type)
     {
-
-      switch (chip_type)
-      {
-        case AIC_7770:
-        case AIC_7771:
+      case AHC_AIC7770:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
           printk("aic7xxx: <%s> at EISA %d\n",
-                 board_names[chip_type], slot);
-          break;
-        case AIC_284x:
+               board_names[2], slot);
+        break;
+      case AHC_274:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at EISA %d\n",
+               board_names[3], slot);
+        break;
+      case AHC_284:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
           printk("aic7xxx: <%s> at VLB %d\n",
-                 board_names[chip_type], slot);
-          break;
-        default:
-          break;
-      }
+               board_names[4], slot);
+        break;
+      default:
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
+    temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+    if (temp_p == NULL)
+    {
+      printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+      slot++;
+      continue; /* back to the beginning of the while loop */
+    }
+    /*
+     * Pause the card preserving the IRQ type.  Allow the operator
+     * to override the IRQ trigger.
+     */
+    if (aic7xxx_irq_trigger == 1)
+      hcntrl = IRQMS;  /* Level */
+    else if (aic7xxx_irq_trigger == 0)
+      hcntrl = 0;  /* Edge */
+    else
+      hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
+    memset(temp_p, 0, sizeof(struct aic7xxx_host));
+    temp_p->unpause = hcntrl | INTEN;
+    temp_p->pause = hcntrl | PAUSE | INTEN;
+    temp_p->base = base;
+    temp_p->type = type;
+    temp_p->flags = flags | AHC_PAGESCBS;
+    temp_p->mbase = 0;
+    temp_p->maddr = 0;
+    temp_p->pci_bus = 0;
+    temp_p->pci_device_fn = slot;
+    aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+    while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+    if (aic7xxx_chip_reset(temp_p) == -1)
+      temp_p->irq = 0;
+    else
+      temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+    switch (temp_p->irq)
+    {
+      case 9:
+      case 10:
+      case 11:
+      case 12:
+      case 14:
+      case 15:
+        break;
 
-      /*
-       * Pause the card preserving the IRQ type.  Allow the operator
-       * to override the IRQ trigger.
-       */
-      if (aic7xxx_irq_trigger == 1)
-        hcntrl = IRQMS;  /* Level */
-      else if (aic7xxx_irq_trigger == 0)
-        hcntrl = 0;  /* Edge */
-      else
-        hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
-      outb(hcntrl | PAUSE, base + HCNTRL);
+      default:
+        printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+          "level %d, ignoring.\n", temp_p->irq);
+        kfree(temp_p);
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
 
-      p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
-      if (p == NULL)
-      {
-        printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-        continue;
-      }
-      aic7xxx_chip_reset(p);
+    /*
+     * We are commited now, everything has been checked and this card
+     * has been found, now we just set it up
+     */
+    /*
+     * Insert our new struct into the list at the end
+     */
+    if (list_p == NULL)
+    {
+      list_p = current_p = temp_p;
+    }
+    else
+    {
+      current_p = list_p;
+      while (current_p->next != NULL)
+        current_p = current_p->next;
+      current_p->next = temp_p;
+    }
+    if (aic7xxx_extended)
+    {
+      temp_p->flags |= AHC_EXTEND_TRANS_A;
+      if (temp_p->flags & AHC_MULTI_CHANNEL)
+        temp_p->flags |= AHC_EXTEND_TRANS_B;
+    }
 
-      irq = inb(INTDEF + base) & 0x0F;
-      switch (irq)
+    switch (temp_p->type & 0x1ff1)
+    {
+      case AHC_AIC7770:
+        temp_p->board_name_index = 2;
+      case AHC_274:
       {
-        case 9:
-        case 10:
-        case 11:
-        case 12:
-        case 14:
-        case 15:
-          break;
+        temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
 
-        default:
-          printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
-          "level %d, ignoring.\n", irq);
-          irq = 0;
-          aic7xxx_free(p);
-          break;
-      }
-
-      if (irq != 0)
-      {
-        p->irq = irq & 0x0F;
-        p->chip_class = AIC_777x;
-#ifdef AIC7XXX_PAGE_ENABLE
-        p->flags |= PAGE_ENABLED;
-#endif
-        p->instance = found;
-        if (aic7xxx_extended)
+        /*
+         * Get the primary channel information.  Right now we don't
+         * do anything with this, but someday we will be able to inform
+         * the mid-level SCSI code which channel is primary.
+         */
+        if (temp_p->board_name_index == 0)
+          temp_p->board_name_index = 3;
+        if (temp_p->bios_control & CHANNEL_B_PRIMARY)
         {
-          p->flags |= EXTENDED_TRANSLATION;
+          temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
         }
 
-        switch (p->chip_type)
+        if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+        {
+          temp_p->flags |= AHC_USEDEFAULTS;
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        }
+        else
         {
-          case AIC_7770:
-          case AIC_7771:
+          temp_p->flags &= ~AHC_USEDEFAULTS;
+          temp_p->flags |= AHC_BIOS_ENABLED;
+          if ( (temp_p->bios_control & 0x20) == 0 )
           {
-            unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
-
-            /*
-             * Get the primary channel information.  Right now we don't
-             * do anything with this, but someday we will be able to inform
-             * the mid-level SCSI code which channel is primary.
-             */
-            if (biosctrl & CHANNEL_B_PRIMARY)
-            {
-              p->flags |= FLAGS_CHANNEL_B_PRIMARY;
-            }
-
-            if ((biosctrl & BIOSMODE) == BIOSDISABLED)
+            switch(temp_p->bios_control & 0x07)
             {
-              p->flags |= USE_DEFAULTS;
+              case 0x0:
+                temp_p->bios_address = 0xcc000;
+                break;
+              case 0x1:
+                temp_p->bios_address = 0xd0000;
+                break;
+              case 0x2:
+                temp_p->bios_address = 0xd4000;
+                break;
+              case 0x3:
+                temp_p->bios_address = 0xd8000;
+                break;
+              case 0x4:
+                temp_p->bios_address = 0xdc000;
+                break;
+              case 0x5:
+                temp_p->bios_address = 0xe0000;
+                break;
+              case 0x6:
+                temp_p->bios_address = 0xe4000;
+                break;
+              case 0x7:
+                temp_p->bios_address = 0xe8000;
+                break;
+              default:
+                break; /* can't get here */
             }
-            break;
           }
-
-          case AIC_284x:
-            if (!load_seeprom(p, &sxfrctl1))
+          else
+          {
+            switch(temp_p->bios_control & 0x06)
             {
-              if (aic7xxx_verbose)
-                printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+              case 0x0:
+                temp_p->bios_address = 0xd0000;
+                break;
+              case 0x2:
+                temp_p->bios_address = 0xd8000;
+                break;
+              case 0x4:
+                temp_p->bios_address = 0xe0000;
+                break;
+              case 0x6:
+                temp_p->bios_address = 0xe8000;
+                break;
+              default:
+                break; /* can't get here */
             }
-            break;
-
-          default:  /* Won't get here. */
-            break;
+          }
         }
-        printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s), ",
-               (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
-               (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
-        /*
-         * Check for Rev C or E boards. Rev E boards can supposedly have
-         * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
-         * It's still not clear extactly what is different about the Rev E
-         * boards, but we think it allows 8 bit entries in the QOUTFIFO to
-         * support "paging" SCBs (more than 4 commands can be active at once).
-         *
-         * The Rev E boards have a read/write autoflush bit in the
-         * SBLKCTL register, while in the Rev C boards it is read only.
-         */
-        sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
-        outb(sblkctl, p->base + SBLKCTL);
-        if (inb(p->base + SBLKCTL) == sblkctl)
+        temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+        temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+        if (temp_p->flags & AHC_USEDEFAULTS)
         {
-          /*
-           * We detected a Rev E board, we allow paging on this board.
-           */
-          printk("Revision >= E\n");
-          outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+          temp_p->scsi_id = temp_p->scsi_id_b = 7;
+          temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
         }
         else
         {
-          /* Do not allow paging. */
-          p->flags &= ~PAGE_ENABLED;
-          printk("Revision <= C\n");
+          if ( ((temp_p->adapter_control >> 8) & TERM_ENB) != 0 )
+            temp_p->flags |= AHC_TERM_ENB_A;
+          if ( (temp_p->adapter_control & TERM_ENB) != 0 )
+            temp_p->flags |= AHC_TERM_ENB_B;
+          temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+          temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
         }
+        break;
+      }
 
-        if (aic7xxx_verbose)
-          printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-                 (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-
-        /*
-         * Set the FIFO threshold and the bus off time.
-         */
-        hostconf = inb(p->base + HOSTCONF);
-        outb(hostconf & DFTHRSH, p->base + BUSSPD);
-        outb((hostconf << 2) & BOFF, p->base + BUSTIME);
-
-        /*
-         * Try to initialize the card and register it with the kernel.
-         */
-        if (aic7xxx_register(template, p))
-        {
-          /*
-           * We successfully found a board and registered it.
-           */
-          found = found + 1;
-        }
-        else
+      case AHC_284:
+        load_seeprom(temp_p, &sxfrctl1);
+        temp_p->board_name_index = 4;
+        switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
         {
-          /*
-           * Something went wrong; release and free all resources.
-           */
-          aic7xxx_free(p);
+          case 0x00:
+            temp_p->bios_address = 0xe0000;
+            break;
+          case 0x20:
+            temp_p->bios_address = 0xc8000;
+            break;
+          case 0x40:
+            temp_p->bios_address = 0xd0000;
+            break;
+          case 0x60:
+            temp_p->bios_address = 0xd8000;
+            break;
+          default:
+            break; /* can't get here */
         }
-      }
+        break;
+
+      default:  /* Won't get here. */
+        break;
+    }
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+        (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+        temp_p->irq,
+        (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+             (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
     }
+
+    /*
+     * Set the FIFO threshold and the bus off time.
+     */
+    hostconf = aic_inb(temp_p, HOSTCONF);
+    aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+    aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+    slot++;
+    found++;
   }
-#endif /* __sparc_v9__ or __powerpc__ */
+
+#endif /* defined(__i386__) || defined(__alpha__) */
 
 #ifdef CONFIG_PCI
   /*
    * PCI-bus probe.
    */
-  if (pci_present())
+  if (pcibios_present())
   {
     struct
     {
       unsigned short      vendor_id;
       unsigned short      device_id;
-      aha_chip_type       chip_type;
-      aha_chip_class_type chip_class;
+      ahc_type            type;
+      ahc_flag_type       flags;
+      int                 board_name_index;
     } const aic7xxx_pci_devices[] = {
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AIC_7873, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AIC_7874, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AIC_7880, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AIC_7881, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AIC_7882, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AIC_7883, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
+       AHC_FNONE,                                            1 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
+       AHC_PAGESCBS | AHC_USEDEFAULTS,                       5 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
+       AHC_PAGESCBS | AHC_USEDEFAULTS,                       6 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  7 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_294AU,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  8 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                      9 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_294,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     10 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_394,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     11 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_398,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     12 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_294,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     13 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     14 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_294U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     15 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_394U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     16 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_398U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     17 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_294U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     18 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 19 }
     };
 
-    int error, flags;
-    unsigned short index = 0;
-    unsigned char ultra_enb = 0;
-    unsigned int  devconfig, class_revid;
-    scb_data_type *shared_scb_data = NULL;
-    char rev_id[] = {'B', 'C', 'D'};
+    unsigned short command;
+    unsigned int  devconfig, i;
+#ifdef MMAPIO
+    unsigned long page_offset;
+#endif
+    struct aic7xxx_host *first_7895 = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
     struct pci_dev *pdev = NULL;
-    unsigned long iobase, mbase;
-    unsigned int irq;
+#else
+    int index;
+    unsigned int piobase, mmapbase;
+    unsigned char pci_bus, pci_devfn;
+#endif
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
+    {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+      pdev = NULL;
       while ((pdev = pci_find_device(aic7xxx_pci_devices[i].vendor_id,
                                      aic7xxx_pci_devices[i].device_id,
-                                   pdev)))
+                                     pdev)))
+#else
+      index = 0;
+      while (!(pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
+                                   aic7xxx_pci_devices[i].device_id,
+                                   index++, &pci_bus, &pci_devfn)) )
+#endif
       {
-        chip_class = aic7xxx_pci_devices[i].chip_class;
-        chip_type = aic7xxx_pci_devices[i].chip_type;
-        chan_num = 0;
-        flags = 0;
-        switch (aic7xxx_pci_devices[i].chip_type)
+        if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
         {
-          case AIC_7855:
-            flags |= USE_DEFAULTS;
-            break;
-
-          case AIC_7872:  /* 3940 */
-          case AIC_7882:  /* 3940-Ultra */
-            flags |= MULTI_CHANNEL;
-            chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
-            number_of_3940s++;
-            break;
-
-          case AIC_7873:  /* 3985 */
-          case AIC_7883:  /* 3985-Ultra */
-            chan_num = number_of_3985s;  /* Has 3 controllers */
-            flags |= MULTI_CHANNEL;
-            number_of_3985s++;
-            if (number_of_3985s == 3)
-            {
-              number_of_3985s = 0;
-              shared_scb_data = NULL;
-            }
-            break;
-
-          default:
-            break;
+          if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
+          {
+            printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
+              "supported by\n");
+            printk(KERN_INFO "         this driver, we are ignoring it.\n");
+          }
         }
+        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+                                    GFP_ATOMIC)) != NULL )
+        {
+          memset(temp_p, 0, sizeof(struct aic7xxx_host));
+          temp_p->type = aic7xxx_pci_devices[i].type;
+          temp_p->flags = aic7xxx_pci_devices[i].flags;
+          temp_p->board_name_index = aic7xxx_pci_devices[i].board_name_index;
 
-        /*
-         * Read sundry information from PCI BIOS.
-         */
-       iobase = pdev->base_address[0];
-       mbase = pdev->base_address[1];
-       irq = pdev->irq;
-        error = pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-        error += pci_read_config_dword(pdev, CLASS_PROGIF_REVID, &class_revid);
-        printk("aic7xxx: <%s> at PCI %d\n",
-               board_names[chip_type], PCI_SLOT(pdev->devfn));
-
-        /*
-         * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
-         * we mask it off.
-         */
-       iobase &= PCI_BASE_ADDRESS_IO_MASK;
-        p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags, shared_scb_data);
-        if(p) {
-          unsigned short pci_command;
-
-          /* Enable bus mastering since this thing must do DMA. */
-          pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-          pci_command |= PCI_COMMAND_MASTER;
-#ifdef __powerpc__
-          /* Enable I/O and memory-space access */
-          pci_command |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+          /*
+           * Read sundry information from PCI BIOS.
+           */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+          temp_p->irq = pdev->irq;
+          temp_p->pci_bus = pdev->bus->number;
+          temp_p->pci_device_fn = pdev->devfn;
+          temp_p->base = pdev->base_address[0];
+          temp_p->mbase = pdev->base_address[1];
+          pci_read_config_word(pdev, PCI_COMMAND, &command);
+          pci_write_config_word(pdev, PCI_COMMAND,
+             command | PCI_COMMAND_MASTER |
+             PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+#else
+          temp_p->pci_bus = pci_bus;
+          temp_p->pci_device_fn = pci_devfn;
+          pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
+            &temp_p->irq);
+          pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
+            &piobase);
+          temp_p->base = piobase;
+          pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1,
+            &mmapbase);
+          temp_p->mbase = mmapbase;
+          pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
+          pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
+            command | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
+            PCI_COMMAND_IO);
 #endif
-          pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-        } else {
-          printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-          continue;
-        }
 
-        /* Remember to set the channel number, irq, and chip class. */
-        p->chan_num = chan_num;
-        p->irq = irq;
-        p->chip_class = chip_class;
-#ifdef AIC7XXX_PAGE_ENABLE
-        p->flags |= PAGE_ENABLED;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic7xxx_pci_devices[i].board_name_index],
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
+
+          /*
+           * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
+           * we mask it off.
+           */
+          temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
+          temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+          temp_p->unpause = (aic_inb(temp_p, HCNTRL) & IRQMS) | INTEN;
+          temp_p->pause = temp_p->unpause | PAUSE;
+
+#ifdef MMAPIO
+          base = temp_p->mbase & PAGE_MASK;
+          page_offset = temp_p->mbase - base;
+          /*
+           * replace the next line with this one if you are using 2.1.x:
+           * temp_p->maddr = ioremap(base, page_offset + 256);
+           */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+          temp_p->maddr = ioremap(base, page_offset + 256);
+#else
+          temp_p->maddr = vremap(base, page_offset + 256);
+#endif
+          if(temp_p->maddr)
+          {
+            temp_p->maddr += page_offset;
+          }
 #endif
-        p->instance = found;
+
+          aic_outb(temp_p, temp_p->pause, HCNTRL);
+          while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+
+          temp_p->bios_address = 0;
 
           /*
            * Remember how the card was setup in case there is no seeprom.
            */
-          p->scsi_id = inb(p->base + SCSIID) & OID;
-          if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+          temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
+          /*
+           * Get current termination setting
+           */
+          sxfrctl1 = aic_inb(temp_p, SXFRCTL1) & STPWEN;
+
+          if (aic7xxx_chip_reset(temp_p) == -1)
           {
-            p->flags |= ULTRA_ENABLED;
-            ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
           }
-         sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
 
-          aic7xxx_chip_reset(p);
-
-#ifdef AIC7XXX_USE_EXT_SCBRAM
-          if (devconfig & RAMPSM)
+          switch (temp_p->type & 0x1ff1)
           {
-            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
-                   "access.\n");
-            /*
-             * XXX - Assume 9 bit SRAM and enable parity checking.
-             */
-            devconfig |= EXTSCBPEN;
+            case AHC_394:   /* 3940 */
+            case AHC_394U:  /* 3940-Ultra */
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              switch(PCI_SLOT(temp_p->pci_device_fn))
+              {
+                case 5:
+                  temp_p->flags |= AHC_CHNLB;
+                  break;
+                default:
+                  break;
+              }
+              break;
 
-            /*
-             * XXX - Assume fast SRAM and only enable 2 cycle access if we
-             *       are sharing the SRAM across multiple adapters (398x).
-             */
-            if ((devconfig & MPORTMODE) == 0)
-            {
-              devconfig |= EXTSCBTIME;
-            }
-            devconfig &= ~SCBRAMSEL;
-            pcibios_write_config_dword(pci_bus, pci_device_fn,
-                                       DEVCONFIG, devconfig);
-          }
+            case AHC_398:   /* 3985 */
+            case AHC_398U:  /* 3985-Ultra */
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              switch(PCI_SLOT(temp_p->pci_device_fn))
+              {
+                case 8:
+                  temp_p->flags |= AHC_CHNLB;
+                  break;
+                case 12:
+                  temp_p->flags |= AHC_CHNLC;
+                  break;
+                default:
+                  break;
+              }
+              break;
+
+            case AHC_AIC7895:
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              if (PCI_FUNC(temp_p->pci_device_fn) != 0)
+              {
+                temp_p->flags |= AHC_CHNLB;
+              }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+              devconfig |= SCBSIZE32;
+              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#else
+              pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                &devconfig);
+              devconfig |= SCBSIZE32;
+              pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                devconfig);
 #endif
+              if (aic7xxx_7895_irq_hack != -1)
+              {
+                if (first_7895 == NULL)
+                {
+                  printk(KERN_INFO "aic7xxx: Using 7895_irq_hack.  Please "
+                    "upgrade your motherboard BIOS\n");
+                  first_7895 = temp_p;
+                }
+                else if (aic7xxx_7895_irq_hack == 0)
+                {
+                  if (temp_p->flags & AHC_CHNLB)
+                    temp_p->irq = first_7895->irq;
+                  else
+                    first_7895->irq = temp_p->irq;
+                  first_7895 = NULL;
+                }
+                else
+                {
+                  if ( !(temp_p->flags & AHC_CHNLB) )
+                    temp_p->irq = first_7895->irq;
+                  else
+                    first_7895->irq = temp_p->irq;
+                  first_7895 = NULL;
+                }
+              }
+              break;
+            default:
+              break;
+          }
+
+          /*
+           * Loading of the SEEPROM needs to come after we've set the flags
+           * to indicate possible CHNLB and CHNLC assigments.  Otherwise,
+           * on 394x and 398x cards we'll end up reading the wrong settings
+           * for channels B and C
+           */
+          if ( !(load_seeprom(temp_p, &sxfrctl1)) )
+          {
+            temp_p->flags |= AHC_USEDEFAULTS;
+            if (sxfrctl1 & STPWEN)
+              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
+            temp_p->scsi_id = temp_p->scsi_id_b = 7;
+          }
 
-          if ((p->flags & USE_DEFAULTS) == 0)
+          /*
+           * and then we need another switch based on the type in order to
+           * make sure the channel B primary flag is set properly on 7895
+           * controllers....Arrrgggghhh!!!
+           */
+          switch(temp_p->type & 0x1ff1)
           {
-            load_seeprom(p, &sxfrctl1);
+            case AHC_AIC7895:
+              current_p = list_p;
+              while(current_p != NULL)
+              {
+                if ( (current_p->pci_bus == temp_p->pci_bus) &&
+                     (PCI_SLOT(current_p->pci_device_fn) ==
+                      PCI_SLOT(temp_p->pci_device_fn)) )
+                {
+                  if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
+                    temp_p->flags |= 
+                      (current_p->flags & AHC_CHANNEL_B_PRIMARY);
+                  else
+                    current_p->flags |=
+                      (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
+                }
+                current_p = current_p->next;
+              }
+              break;
+            default:
+              break;
           }
 
           /*
            * Take the LED out of diagnostic mode
            */
-          sblkctl = inb(p->base + SBLKCTL);
-          outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+          aic_outb(temp_p, 
+            (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
+            SBLKCTL);
 
           /*
            * We don't know where this is set in the SEEPROM or by the
            * BIOS, so we default to 100%.
            */
-          outb(DFTHRSH_100, p->base + DSPCISTATUS);
+          aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
 
-          if (p->flags & USE_DEFAULTS)
+          if (temp_p->flags & AHC_USEDEFAULTS)
           {
             int j;
+            unsigned char k;
             /*
              * Default setup; should only be used if the adapter does
              * not have a SEEPROM.
@@ -6061,207 +7541,409 @@ aic7xxx_detect(Scsi_Host_Template *template)
              */
             for (j = TARG_SCRATCH; j < 0x60; j++)
             {
-              if (inb(p->base + j) != 0x00)      /* Check for all zeroes. */
+              k = aic_inb(temp_p, j);
+              /* Check for all zeros and ones.  Break out if we pass */
+              if( (k != 0x00) && (k != 0xff) )
                 break;
             }
-            if (j == TARG_SCRATCH)
-            {
-              for (j = TARG_SCRATCH; j < 0x60; j++)
-              {
-                if (inb(p->base + 1) != 0xFF)    /* Check for all ones. */
-                  break;
-              }
-            }
-            if ((j != 0x60) && (p->scsi_id != 0))
+            /* If j makes it to 0x60, then all entries are either 0x00 or
+             * 0xff.  We would then assume we have *not* been initialized
+             * and drop through here.  OTOH, if even one entry is inited,
+             * then as long as we appear to have a valid SCSI ID, we'll use
+             * the leftover BIOS values.
+             */
+            if ((j != 0x60) && (temp_p->scsi_id != 0))
             {
-              p->flags &= ~USE_DEFAULTS;
-              if (aic7xxx_verbose)
+              temp_p->flags &= ~AHC_USEDEFAULTS;
+              if (aic7xxx_verbose & VERBOSE_PROBE2)
               {
                 printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
               }
             }
             else
             {
-              if (aic7xxx_verbose)
-              {
-                printk(KERN_INFO "aic7xxx: No BIOS found; using default "
-                       "settings.\n");
-              }
               /*
                * Assume only one connector and always turn on
                * termination.
                */
+              temp_p->flags &= ~AHC_BIOS_ENABLED;
+              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
               sxfrctl1 = STPWEN;
-              p->scsi_id = 7;
+              temp_p->scsi_id = 7;
             }
-            outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
-                 p->base + SCSICONF);
+            aic_outb(temp_p, (temp_p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+                 SCSICONF);
             /* In case we are a wide card. */
-            outb(p->scsi_id, p->base + SCSICONF + 1);
-            if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
-            {
-              /*
-               * If there wasn't a BIOS or the board wasn't in this mode
-               * to begin with, turn off Ultra.
-               */
-              p->flags &= ~ULTRA_ENABLED;
-            }
+            aic_outb(temp_p, temp_p->scsi_id, SCSICONF + 1);
           }
-
-          /*
-           * Print some additional information about the adapter.
-           */
-          printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, "
-                 "IO Mem 0x%lx, IRQ %x",
-                 (p->flags & USE_DEFAULTS) ? "dis" : "en",
-                 p->base, p->mbase, p->irq);
-          if ((class_revid & DEVREVID) < 3)
+          else /* not using defaults */
           {
-            printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+            if (sxfrctl1 & STPWEN)
+              temp_p->flags |= AHC_TERM_ENB_A;
           }
-          printk("\n");
 
           if (aic7xxx_extended)
-            p->flags |= EXTENDED_TRANSLATION;
-
-          if (aic7xxx_verbose)
-            printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-                   (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+            temp_p->flags |= AHC_EXTEND_TRANS_A;
 
           /*
            * Put our termination setting into sxfrctl1 now that the
            * generic initialization is complete.
            */
-          sxfrctl1 |= inb(p->base + SXFRCTL1);
-          outb(sxfrctl1, p->base + SXFRCTL1);
-
-          if (aic7xxx_register(template, p) == 0)
+          sxfrctl1 |= aic_inb(temp_p, SXFRCTL1);
+          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+          if ( list_p == NULL )
           {
-            aic7xxx_free(p);
+            list_p = current_p = temp_p;
           }
           else
           {
-            found = found + 1;
-
-#ifdef AIC7XXX_USE_EXT_SCBRAM
-            /*
-             * Set the shared SCB data once we've successfully probed a
-             * 398x adapter.
-             *
-             * Note that we can only do this if the use of external
-             * SCB RAM is enabled.
-             */
-            if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
-            {
-              if (shared_scb_data == NULL)
-              {
-                shared_scb_data = p->scb_data;
-              }
-            }
-#endif
+            current_p = list_p;
+            while(current_p->next != NULL)
+              current_p = current_p->next;
+            current_p->next = temp_p;
           }
-
-          index++;
-      }  /* Found an Adaptec PCI device. */
-  }
+          temp_p->next = NULL;
+          found++;
+        }  /* Found an Adaptec PCI device. */
+        else /* Well, we found one, but we couldn't get any memory */
+        {
+          printk("aic7xxx: Found <%s>\n", 
+            board_names[aic7xxx_pci_devices[i].board_name_index]);
+          printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
+            "skipping.\n");
+        }
+      } /* while(pdev=....) */
+    } /* for PCI_DEVICES */
+  } /* PCI BIOS present */
 #endif CONFIG_PCI
-
-  return (found);
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_buildscb
- *
- * Description:
- *   Build a SCB.
- *-F*************************************************************************/
-static void
-aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
-    struct aic7xxx_scb *scb)
-{
-  unsigned short mask;
-  struct aic7xxx_hwscb *hscb;
-
-  mask = (0x01 << TARGET_INDEX(cmd));
-  hscb = scb->hscb;
-
   /*
-   * Setup the control byte if we need negotiation and have not
-   * already requested it.
+   * Now, we re-order the probed devices by BIOS address and BUS class.
+   * In general, we follow this algorithm to make the adapters show up
+   * in the same order under linux that the computer finds them.
+   *  1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
+   *     address, going from lowest to highest.
+   *  2: All PCI controllers with BIOS_ENABLED next, according to BIOS
+   *     address, going from lowest to highest.
+   *  3: Remaining VLB/EISA controllers going in slot order.
+   *  4: Remaining PCI controllers, going in PCI device order (reversable)
    */
-  if (p->discenable & mask)
-  {
-    hscb->control |= DISCENB;
-#ifdef AIC7XXX_TAGGED_QUEUEING
-    if (cmd->device->tagged_queue)
-    {
-      cmd->tag = hscb->tag;
-      p->device_status[TARGET_INDEX(cmd)].commands_sent++;
-      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
-      {
-        hscb->control |= MSG_SIMPLE_Q_TAG;
-      }
-      else
-      {
-        hscb->control |= MSG_ORDERED_Q_TAG;
-        p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
-      }
-    }
-#endif  /* Tagged queueing */
-  }
 
-  if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
-  {
-    p->wdtr_pending |= mask;
-    hscb->control |= MK_MESSAGE;
-    scb->flags |= SCB_MSGOUT_WDTR;
-#if 0
-    printk("scsi%d: Sending WDTR request to target %d.\n",
-           p->host_no, cmd->target);
-#endif
-  }
-  else
   {
-    if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
-    {
-      p->sdtr_pending |= mask;
-      hscb->control |= MK_MESSAGE;
-      scb->flags |= SCB_MSGOUT_SDTR;
-#if 0
-      printk("scsi%d: Sending SDTR request to target %d.\n",
-             p->host_no, cmd->target);
-#endif
-    }
-  }
-#if 0
-  printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
-         "mask(0x%x).\n",
-        cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
-#endif
-  hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
-       ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
-
-  /*
-   * The interpretation of request_buffer and request_bufflen
-   * changes depending on whether or not use_sg is zero; a
-   * non-zero use_sg indicates the number of elements in the
-   * scatter-gather array.
-   */
+    struct aic7xxx_host *vlb_enab, *vlb_disab, *pci;
+    struct aic7xxx_host *prev_p;
+    struct aic7xxx_host *p;
+    unsigned char left;
 
-  /*
-   * XXX - this relies on the host data being stored in a
-   *       little-endian format.
-   *
-   * No longer is that an issue, I've "big-endian'ified" this driver. -DaveM
-   */
-  hscb->SCSI_cmd_length = cmd->cmd_len;
-  hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
+    prev_p = vlb_enab = vlb_disab = pci = NULL;
 
-  if (cmd->use_sg)
-  {
-    struct scatterlist *sg;  /* Must be mid-level SCSI code scatterlist */
+    temp_p = list_p;
+    while (temp_p != NULL)
+    {
+      switch(temp_p->type)
+      {
+        case AHC_AIC7770:
+        case AHC_274:
+        case AHC_284:
+          if (temp_p->flags & AHC_BIOS_ENABLED)
+          {
+            if (vlb_enab == NULL)
+            {
+              vlb_enab = temp_p;
+              temp_p = temp_p->next;
+              vlb_enab->next = NULL;
+            }
+            else
+            {
+              current_p = vlb_enab;
+              prev_p = NULL;
+              while ( (current_p != NULL) &&
+                      (current_p->bios_address < temp_p->bios_address))
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+              if (prev_p != NULL)
+              {
+                prev_p->next = temp_p;
+                temp_p = temp_p->next;
+                prev_p->next->next = current_p;
+              }
+              else
+              {
+                vlb_enab = temp_p;
+                temp_p = temp_p->next;
+                vlb_enab->next = current_p;
+              }
+            }
+          }
+          else
+          {
+            if (vlb_disab == NULL)
+            {
+              vlb_disab = temp_p;
+              temp_p = temp_p->next;
+              vlb_disab->next = NULL;
+            }
+            else
+            {
+              current_p = vlb_disab;
+              prev_p = NULL;
+              while ( (current_p != NULL) &&
+                      (current_p->base < temp_p->base))
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+              if (prev_p != NULL)
+              {
+                prev_p->next = temp_p;
+                temp_p = temp_p->next;
+                prev_p->next->next = current_p;
+              }
+              else
+              {
+                vlb_disab = temp_p;
+                temp_p = temp_p->next;
+                vlb_disab->next = current_p;
+              }
+            }
+          }
+          break;
+        default:  /* All PCI controllers fall through to default */
+          if (pci == NULL)
+          {
+            pci = temp_p;
+            temp_p = temp_p->next;
+            pci->next = NULL;
+          }
+          else
+          {
+            current_p = pci;
+            prev_p = NULL;
+            if (!aic7xxx_reverse_scan)
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) < 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            else
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) > 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            /*
+             * Are we dealing with a 7985 where we need to sort the
+             * channels as well, if so, the bios_address values should
+             * be the same
+             */
+            if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
+                 (temp_p->pci_bus == current_p->pci_bus) &&
+                 (PCI_SLOT(temp_p->pci_device_fn) ==
+                  PCI_SLOT(current_p->pci_device_fn)) )
+            {
+              if (temp_p->flags & AHC_CHNLB)
+              {
+                if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+              else
+              {
+                if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+            }
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              pci = temp_p;
+              temp_p = temp_p->next;
+              pci->next = current_p;
+            }
+          }
+          break;
+      }  /* End of switch(temp_p->type) */
+    } /* End of while (temp_p != NULL) */
+    /*
+     * At this point, the cards have been broken into 4 sorted lists, now
+     * we run through the lists in order and register each controller
+     */
+    left = found;
+    temp_p = vlb_enab;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+    temp_p = pci;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+    temp_p = vlb_disab;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+  }
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_buildscb
+ *
+ * Description:
+ *   Build a SCB.
+ *-F*************************************************************************/
+static void
+aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
+    struct aic7xxx_scb *scb)
+{
+  unsigned short mask;
+  struct aic7xxx_hwscb *hscb;
+
+  mask = (0x01 << TARGET_INDEX(cmd));
+  hscb = scb->hscb;
+
+  /*
+   * Setup the control byte if we need negotiation and have not
+   * already requested it.
+   */
+  hscb->control = 0;
+  scb->tag_action = 0;
+  if (p->discenable & mask)
+  {
+    hscb->control |= DISCENB;
+    if (p->tagenable & mask)
+    {
+      cmd->tag = hscb->tag;
+      p->dev_commands_sent[TARGET_INDEX(cmd)]++;
+      if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
+      {
+        hscb->control |= MSG_SIMPLE_Q_TAG;
+        scb->tag_action = MSG_SIMPLE_Q_TAG;
+      }
+      else
+      {
+        if (p->orderedtag & mask)
+        {
+          hscb->control |= MSG_ORDERED_Q_TAG;
+          scb->tag_action = MSG_ORDERED_Q_TAG;
+        }
+        else
+        {
+          hscb->control |= MSG_SIMPLE_Q_TAG;
+          scb->tag_action = MSG_SIMPLE_Q_TAG;
+        }
+        p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
+      }
+    }
+  }
+  if ( (p->needwdtr & mask) &&
+      !(p->wdtr_pending & mask) &&
+      !(scb->tag_action))
+  {
+    p->wdtr_pending |= mask;
+    hscb->control |= MK_MESSAGE;
+    if (p->needwdtr_copy & mask)
+      scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+    else
+      scb->flags |= SCB_MSGOUT_WDTR_8BIT;
+  }
+  else
+  {
+    if ( (p->needsdtr & mask) &&
+        !(p->sdtr_pending & mask) &&
+        !(p->wdtr_pending & mask) &&
+        !(scb->tag_action) )
+    {
+      p->sdtr_pending |= mask;
+      hscb->control |= MK_MESSAGE;
+      scb->flags |= SCB_MSGOUT_SDTR;
+    }
+  }
+  hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+        ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+
+  /*
+   * The interpretation of request_buffer and request_bufflen
+   * changes depending on whether or not use_sg is zero; a
+   * non-zero use_sg indicates the number of elements in the
+   * scatter-gather array.
+   */
+
+  /*
+   * XXX - this relies on the host data being stored in a
+   *       little-endian format.
+   */
+  hscb->SCSI_cmd_length = cmd->cmd_len;
+  hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
+
+  if (cmd->use_sg)
+  {
+    struct scatterlist *sg;  /* Must be mid-level SCSI code scatterlist */
 
     /*
      * We must build an SG list in adapter format, as the kernel's SG list
@@ -6272,46 +7954,42 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     int i;
 
     sg = (struct scatterlist *)cmd->request_buffer;
+    scb->sg_length = 0;
     for (i = 0; i < cmd->use_sg; i++)
     {
       scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
-      scb->sg_list[i].length = cpu_to_le32((unsigned int) sg[i].length);
+      scb->sg_list[i].length = cpu_to_le32(sg[i].length);
+      scb->sg_length += sg[i].length;
     }
     hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(scb->sg_list));
     hscb->SG_segment_count = cmd->use_sg;
-    scb->sg_count = hscb->SG_segment_count;
+    scb->sg_count = cmd->use_sg;
 
     /* Copy the first SG into the data pointer area. */
     hscb->data_pointer = scb->sg_list[0].address;
-    hscb->data_count = scb->sg_list[0].length | cpu_to_le32(SCB_LIST_NULL << 24);
-#if 0
-    printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
-           cmd->use_sg, aic7xxx_length(cmd, 0), le32_to_cpu(hscb->data_count));
-#endif
+    hscb->data_count = scb->sg_list[0].length;
   }
   else
   {
-#if 0
-  printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
-       (unsigned long) cmd->request_buffer, cmd->request_bufflen);
-#endif
     if (cmd->request_bufflen)
     {
-      hscb->SG_segment_count = 1;
       scb->sg_count = 1;
       scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
       scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+      scb->sg_length = cmd->request_bufflen;
+      hscb->SG_segment_count = 1;
       hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
-      hscb->data_count = scb->sg_list[0].length | cpu_to_le32(SCB_LIST_NULL << 24);
-      hscb->data_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+      hscb->data_count = scb->sg_list[0].length;
+      hscb->data_pointer = scb->sg_list[0].address;
     }
     else
     {
-      hscb->SG_segment_count = 0;
       scb->sg_count = 0;
+      scb->sg_length = 0;
+      hscb->SG_segment_count = 0;
       hscb->SG_list_pointer = 0;
+      hscb->data_count = 0;
       hscb->data_pointer = 0;
-      hscb->data_count = cpu_to_le32(SCB_LIST_NULL << 24);
     }
   }
 }
@@ -6326,58 +8004,51 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
 int
 aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 {
-  long processor_flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
+  int tindex = TARGET_INDEX(cmd);
+  unsigned long cpu_flags = 0;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  if (p->host != cmd->host)
-  {
-    printk(KERN_INFO "scsi%d: Internal host structure != scsi.c host "
-      "structure.\n", p->host_no);
-  }
-
   /*
    * Check to see if channel was scanned.
    */
-  if (!(p->flags & A_SCANNED) && (cmd->channel == 0))
+  if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
   {
-    printk(KERN_INFO "scsi%d: Scanning channel A for devices.\n", p->host_no);
-    p->flags |= A_SCANNED;
+    printk(INFO_LEAD "Scanning channel for devices.\n",
+      p->host_no, 0, -1, -1);
+    p->flags |= AHC_A_SCANNED;
   }
   else
   {
-    if (!(p->flags & B_SCANNED) && (cmd->channel == 1))
+    if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
     {
-      printk(KERN_INFO "scsi%d: Scanning channel B for devices.\n", p->host_no);
-      p->flags |= B_SCANNED;
+      printk(INFO_LEAD "Scanning channel for devices.\n",
+        p->host_no, 1, -1, -1);
+      p->flags |= AHC_B_SCANNED;
     }
   }
 
-#if 0
-  printk("aic7xxx: (queue) cmd(0x%x) size(%u), target %d, channel %d, lun %d.\n",
-       cmd->cmnd[0], cmd->cmd_len, cmd->target, cmd->channel,
-       cmd->lun & 0x07);
-#endif
-
-  if (p->device_status[TARGET_INDEX(cmd)].active_cmds
-      > cmd->device->queue_depth)
+  if (p->dev_active_cmds[tindex] > cmd->device->queue_depth)
   {
-    printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
-           p->host_no, cmd->target, cmd->channel);
+    printk(WARN_LEAD "Commands queued exceeds queue "
+           "depth, active=%d\n",
+           p->host_no, CTL_OF_CMD(cmd), 
+           p->dev_active_cmds[tindex]);
+    if ( p->dev_active_cmds[tindex] > 220 )
+      p->dev_active_cmds[tindex] = 0;
   }
-  scb = aic7xxx_allocate_scb(p);
+  DRIVER_LOCK
+  scb = aic7xxx_allocate_scb(p, FALSE);
+  DRIVER_UNLOCK
   if (scb == NULL)
   {
-    panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
+    panic("(scsi%d) aic7xxx_queue:Couldn't get a free SCB.\n", p->host_no);
   }
   else
   {
     scb->cmd = cmd;
     aic7xxx_position(cmd) = scb->hscb->tag;
-#if 0
-    debug_scb(scb);
-#endif;
 
     /*
      * Construct the SCB beforehand, so the sequencer is
@@ -6385,17 +8056,6 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
      */
     aic7xxx_buildscb(p, cmd, scb);
 
-#if 0
-    if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
-    {
-      printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
-             "address.\n");
-    }
-    printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
-          scb->hscb->tag, (unsigned int) scb->cmd,
-          scb->flags, (unsigned int) p->free_scb);
-#endif
-
     /*
      * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
      * is set up properly, and the parity error flag is reset, then send
@@ -6410,19 +8070,20 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 
     scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-    save_flags(processor_flags);
-    cli();
-    scbq_insert_tail(&p->waiting_scbs, scb);
-    if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
+    DRIVER_LOCK
+    if (p->delayed_scbs[tindex].head != NULL) 
+    {
+        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+    }
+    else
+    {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+    }
+    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
     {
       aic7xxx_run_waiting_queues(p);
     }
-
-    restore_flags(processor_flags);
-#if 0
-    printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
-           (long) cmd, (long) scb->cmd, scb->hscb->tag);
-#endif;
+    DRIVER_UNLOCK
   }
   return (0);
 }
@@ -6443,103 +8104,58 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
   struct aic7xxx_scb   *scb;
   struct aic7xxx_hwscb *hscb;
-  unsigned char bus_state;
   int result = -1;
-  char channel;
+  int channel;
+  unsigned char saved_scbptr, lastphase;
+  unsigned char hscb_index;
+  int disconnected;
 
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   hscb = scb->hscb;
 
-  /*
-   * Ensure that the card doesn't do anything behind our back.
-   * Also make sure that we didn't just miss an interrupt that
-   * could affect this abort/reset.
-   */
-  pause_sequencer(p);
-  while (inb(p->base + INTSTAT) & INT_PEND);
-  {
-    aic7xxx_isr(p->irq, (void *) p, (void *) NULL);
-    pause_sequencer(p);
-  } 
-  if ((cmd != scb->cmd) || ((scb->flags & SCB_ACTIVE) == 0))
-  {
-    result = SCSI_RESET_NOT_RUNNING;
-    unpause_sequencer(p, /* unpause_always */ TRUE);
-    return(result);
-  }
-
-
-  printk(KERN_WARNING "(scsi%d:%d:%d) Abort_reset, scb flags 0x%x, ",
-         p->host_no, TC_OF_SCB(scb), scb->flags);
-  bus_state = inb(p->base + LASTPHASE);
-
-  switch (bus_state)
+  lastphase = aic_inb(p, LASTPHASE);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
   {
-    case P_DATAOUT:
-      printk("Data-Out phase, ");
-      break;
-    case P_DATAIN:
-      printk("Data-In phase, ");
-      break;
-    case P_COMMAND:
-      printk("Command phase, ");
-      break;
-    case P_MESGOUT:
-      printk("Message-Out phase, ");
-      break;
-    case P_STATUS:
-      printk("Status phase, ");
-      break;
-    case P_MESGIN:
-      printk("Message-In phase, ");
-      break;
-    default:
+    printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
+         p->host_no, CTL_OF_SCB(scb), scb->flags);
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        printk("Data-Out phase\n");
+        break;
+      case P_DATAIN:
+        printk("Data-In phase\n");
+        break;
+      case P_COMMAND:
+        printk("Command phase\n");
+        break;
+      case P_MESGOUT:
+        printk("Message-Out phase\n");
+        break;
+      case P_STATUS:
+        printk("Status phase\n");
+        break;
+      case P_MESGIN:
+        printk("Message-In phase\n");
+        break;
+      default:
       /*
        * We're not in a valid phase, so assume we're idle.
        */
-      printk("while idle, LASTPHASE = 0x%x, ", bus_state);
-      break;
+        printk("while idle, LASTPHASE = 0x%x\n", lastphase);
+        break;
+    }
+    printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+         "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+         aic_inb(p, SCSISIGI),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
   }
-  printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
-         inb(p->base + SCSISIGI),
-         inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
-         inb(p->base + SSTAT0), inb(p->base + SSTAT1));
 
-  channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
-  /*
-   * Determine our course of action.
-   */
-  if (scb->flags & SCB_ABORT)
-  {
-    /*
-     * Been down this road before; do a full bus reset.
-     */
-    scb->flags |= SCB_RECOVERY_SCB;
-    unpause_sequencer(p, /* unpause_always */ TRUE);
-    result = -1;
-  }
-#if 0
-  else if (hscb->control & TAG_ENB)
-    {
-      /*
-       * We could be starving this command; try sending and ordered tag
-       * command to the target we come from.
-       */
-      scb->flags |= SCB_SENTORDEREDTAG | SCB_RECOVERY_SCB;
-      p->orderedtag = p->orderedtag | 0xFF;
-      result = SCSI_RESET_PENDING;
-      unpause_sequencer(p, /* unpause_always */ TRUE);
-      printk(KERN_WARNING "scsi%d: Abort_reset, odered tag queued.\n",
-             p->host_no);
-    }
-#endif
-  else
-  {
-    unsigned char active_scb_index, saved_scbptr;
-    struct aic7xxx_scb *active_scb;
+  channel = cmd->channel;
 
     /*
-     * Send an Abort Message:
+     * Send a Device Reset Message:
      * The target that is holding up the bus may not be the same as
      * the one that triggered this timeout (different commands have
      * different timeout lengths).  Our strategy here is to queue an
@@ -6550,152 +8166,153 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
      * fails, we'll get another timeout a few seconds later which will
      * attempt a bus reset.
      */
-    saved_scbptr = inb(p->base + SCBPTR);
-    active_scb_index = inb(p->base + SCB_TAG);
-    active_scb = p->scb_data->scb_array[active_scb_index];
+  saved_scbptr = aic_inb(p, SCBPTR);
+  disconnected = FALSE;
 
-    if (bus_state != P_BUSFREE)
+  if (lastphase != P_BUSFREE)
+  {
+    if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
     {
-      if (active_scb_index >= p->scb_data->numscbs)
+      printk(WARN_LEAD "Invalid SCB ID %d is active, "
+             "SCB flags = 0x%x.\n", p->host_no,
+            CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
+      return(SCSI_RESET_ERROR);
+    }
+    if (scb->hscb->tag == aic_inb(p, SCB_TAG))
+    { 
+      if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
       {
-        /*
-         * Perform a bus reset.
-         *
-         * XXX - We want to queue an abort for the timedout SCB
-         *       instead.
-         */
-        result = -1;
-        printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
-               "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
+        /* Send the abort message to the active SCB. */
+        aic_outb(p, MSG_BUS_DEV_RESET, MSG_OUT);
+        aic_outb(p, lastphase | ATNO, SCSISIGO);
+        if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+          printk(INFO_LEAD "Device reset message in "
+                "message buffer\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        aic7xxx_error(scb->cmd) = DID_RESET;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
+                ~DEVICE_SUCCESS;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
+        return(SCSI_RESET_PENDING);
       }
       else
       {
-        /* Send the abort message to the active SCB. */
-        outb(1, p->base + MSG_LEN);
-        if (active_scb->hscb->control & TAG_ENB)
-        {
-          outb(MSG_ABORT_TAG, p->base + MSG_OUT);
-        }
-        else
-        {
-          outb(MSG_ABORT, p->base + MSG_OUT);
-        }
-        outb(bus_state | ATNO, p->base + SCSISIGO);
-        printk(KERN_WARNING "scsi%d: abort message in message buffer\n",
-               p->host_no);
-        active_scb->flags |= SCB_ABORT | SCB_RECOVERY_SCB;
-        if (active_scb != scb)
-        {
-          /*
-           * XXX - We would like to increment the timeout on scb, but
-           *       access to that routine is denied because it is hidden
-           *       in scsi.c.  If we were able to do this, it would give
-           *       scb a new lease on life.
-           */
-          result = SCSI_RESET_PENDING;
-          aic7xxx_error(active_scb->cmd) = DID_RESET;
-        }
-        else
-        {
-          aic7xxx_error(scb->cmd) = DID_RESET;
-          result = SCSI_RESET_PENDING;
-        }
-        unpause_sequencer(p, /* unpause_always */ TRUE);
+        /* We want to send out the message, but it could screw an already */
+        /* in place and being used message.  Instead, we return an error  */
+        /* to try and start the bus reset phase since this command is     */
+        /* probably hung (aborts failed, and now reset is failing).  We   */
+        /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
+        /* any more on this device, but instead will escalate to a bus or */
+        /* host reset (additionally, we won't try to abort any more).     */
+        printk(WARN_LEAD "Device reset, Message buffer "
+                "in use\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        aic7xxx_error(scb->cmd) = DID_RESET;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
+                ~DEVICE_SUCCESS;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
+        return(SCSI_RESET_ERROR);
       }
     }
-    else
+  } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
+  hscb_index = aic7xxx_find_scb(p, scb);
+  if (hscb_index == SCB_LIST_NULL)
+  {
+    disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
+  }
+  else
+  {
+    aic_outb(p, hscb_index, SCBPTR);
+    if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
     {
-      unsigned char hscb_index, linked_next;
-      int disconnected;
-
-      disconnected = FALSE;
-      hscb_index = aic7xxx_find_scb(p, scb);
-      if (hscb_index == SCB_LIST_NULL)
-      {
-        disconnected = TRUE;
-        linked_next = (le32_to_cpu(scb->hscb->data_count) >> 24) & 0xFF;
-      }
-      else
-      {
-        outb(hscb_index, p->base + SCBPTR);
-        if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
-        {
-          disconnected = TRUE;
-        }
-        linked_next = inb(p->base + SCB_LINKED_NEXT);
-      }
-      if (disconnected)
-      {
+      disconnected = TRUE;
+    }
+  }
+  if (disconnected)
+  {
         /*
-         * Simply set the ABORT_SCB control bit and preserve the
-         * linked next pointer.
+         * Simply set the MK_MESSAGE flag and the SEQINT handler will do
+         * the rest on a reconnect.
          */
-        scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
-        scb->hscb->data_count &= cpu_to_le32(~0xFF000000);
-        scb->hscb->data_count |= cpu_to_le32(linked_next << 24);
-        if ((p->flags & PAGE_ENABLED) == 0)
-        {
-          scb->hscb->control &= ~DISCONNECTED;
-        }
-        scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
-        if (hscb_index != SCB_LIST_NULL)
-        {
-          unsigned char scb_control;
+    scb->hscb->control |= MK_MESSAGE;
+    scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] &= ~DEVICE_SUCCESS;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+        BUS_DEVICE_RESET_PENDING;
+    if (hscb_index != SCB_LIST_NULL)
+    {
+      unsigned char scb_control;
 
-          scb_control = inb(p->base + SCB_CONTROL);
-          outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
-        }
+      aic_outb(p, hscb_index, SCBPTR);
+      scb_control = aic_inb(p, SCB_CONTROL);
+      aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
+    }
         /*
          * Actually requeue this SCB in case we can select the
          * device before it reconnects.  If the transaction we
-         * want to abort is not tagged, unbusy it first so that
-         * we don't get held back from sending the command.
+         * want to abort is not tagged, then this will be the only
+         * outstanding command and we can simply shove it on the
+         * qoutfifo and be done.  If it is tagged, then it goes right
+         * in with all the others, no problem :)  We need to add it
+         * to the qinfifo and let the sequencer know it is there.
+         * Now, the only problem left to deal with is, *IF* this
+         * command completes, in spite of the MK_MESSAGE bit in the
+         * control byte, then we need to pick that up in the interrupt
+         * routine and clean things up.  This *shouldn't* ever happen.
          */
-        if ((scb->hscb->control & TAG_ENB) == 0)
-        {
-          unsigned char target;
-          int lun;
-
-          target = scb->cmd->target;
-          lun = scb->cmd->lun;
-          aic7xxx_search_qinfifo(p, target, channel, lun, SCB_LIST_NULL,
-              0, /* requeue */ TRUE);
-        }
-        printk(KERN_WARNING "(scsi%d:%d:%d) Queueing an Abort SCB.\n",
-               p->host_no, TC_OF_SCB(scb));
-        scbq_insert_head(&p->waiting_scbs, scb);
-        scb->flags |= SCB_WAITINGQ;
-        outb(saved_scbptr, p->base + SCBPTR);
-        if ((p->flags & IN_ISR) == 0)
-        {
-          /*
-           * Processing the waiting queue may unpause us.
-           */
-          aic7xxx_run_waiting_queues(p);
-          /*
-           * If we are using AAP, aic7xxx_run_waiting_queues() will not
-           * unpause us, so ensure we are unpaused.
-           */
-          unpause_sequencer(p, /*unpause_always*/ FALSE);
-        }
-        else
-        {
-          unpause_sequencer(p, /*unpause_always*/ TRUE);
-        }
-        result = SCSI_RESET_PENDING;
-      }
-      else
-      {
-        scb->flags |= SCB_RECOVERY_SCB;
-        unpause_sequencer(p, /* unpause_always */ TRUE);
-        result = -1;
-      }
-    }
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Queueing device reset "
+           "command.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    scb->flags |= SCB_QUEUED_ABORT;
+    result = SCSI_RESET_PENDING;
+  }
+  else if (result == -1)
+  {
+    result = SCSI_RESET_ERROR;
   }
+  aic_outb(p, saved_scbptr, SCBPTR);
   return (result);
 }
 
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_panic_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+void
+aic7xxx_panic_abort(struct aic7xxx_host *p)
+{
+  int i;
+
+  printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+  printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if(p->dev_flags[i] & DEVICE_PRESENT)
+    {
+      printk(INFO_LEAD "dev_flags=0x%x, WDTR:%s, SDTR:%s, q_depth=%d:%d\n",
+        p->host_no, 0, i, 0, p->dev_flags[i],
+        (p->needwdtr_copy & (1 << i)) ? "Yes" : "No",
+        (p->needsdtr_copy & (1 << i)) ? "Yes" : "No",
+        p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+    }
+  }
+  printk("SIMODE0=0x%x, SIMODE1=0x%x, SSTAT0=0x%x, SSTAT1=0x%x, INTSTAT=0x%x\n",
+    aic_inb(p, SIMODE0), aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+    aic_inb(p, SSTAT1), aic_inb(p, INTSTAT) );
+  printk("p->flags=0x%x, p->type=0x%x, sequencer %s paused\n",
+     p->flags, p->type,
+    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+  panic("Stopping to debug\n");
+}
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_abort
@@ -6708,86 +8325,307 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
 {
   struct aic7xxx_scb  *scb = NULL;
   struct aic7xxx_host *p;
-  int    base, result;
-  unsigned long processor_flags;
+  int    result, found=0;
+  unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
+  unsigned long cpu_flags = 0;
+  Scsi_Cmnd *cmd_next, *cmd_prev;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  base = p->base;
 
-  save_flags(processor_flags);
-  cli();
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  if (scb != NULL)
+  DRIVER_LOCK
+
+/*
+ *  Run the isr to grab any command in the QOUTFIFO and any other misc.
+ *  assundry tasks.  This should also set up the bh handler if there is
+ *  anything to be done, but it won't run until we are done here since
+ *  we are following a straight code path without entering the scheduler
+ *  code.
+ */
+
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
-    printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
-           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    aic7xxx_isr(p->irq, p, (void *)NULL);
+    pause_sequencer(p);
   }
-  else
+
+  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
+                      /*  Totally bogus cmd since it points beyond our  */
+  {                   /*  valid SCB range or doesn't even match it's own*/
+                      /*  timeout serial number.                        */
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
+        "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+  if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
+  {                     /*  NULL cmd pointer (NULLed out when freed) or it  */
+                        /*  has already been recycled for another command   */
+                        /*  Either way, this SCB has nothing to do with this*/
+                        /*  command and we need to deal with cmd without    */
+                        /*  touching the SCB.                               */
+                        /*  The theory here is to return a value that will  */
+                        /*  make the queued for complete command actually   */
+                        /*  finish successfully, or to indicate that we     */
+                        /*  don't have this cmd any more and the mid level  */
+                        /*  code needs to find it.                          */
+    cmd_next = p->completeq.head;
+    cmd_prev = NULL;
+    while (cmd_next != NULL) 
+    {
+      if (cmd_next == cmd) 
+      {
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "Abort called for command "
+          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        if ( cmd_prev == NULL )
+          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+        else
+          cmd_prev->host_scribble = cmd_next->host_scribble;
+        cmd_next->done(cmd_next);
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
+                                         * completion */
+      }                                  
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called for already completed"
+        " command.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+    
+/*   At this point we know the following:
+ *     the SCB pointer is valid
+ *     the command pointer passed in to us and the scb->cmd pointer match
+ *     this then means that the command we need to abort is the same as the
+ *     command held by the scb pointer and is a valid abort request.
+ *   Now, we just have to figure out what to do from here.  Current plan is:
+ *     if we have already been here on this command, escalate to a reset
+ *     if scb is on waiting list or QINFIFO, send it back as aborted
+ *     if scb is on WAITING_SCB list in sequencer, free scb and send back
+ *     if scb is disconnected and not completed, abort with abort message
+ *     if scb is currently running, then it may be causing the bus to hang
+ *       so we want a return value that indicates a reset would be appropriate
+ *       if the command does not finish shortly
+ *     if scb is already complete but not on completeq, we're screwed because
+ *       this can't happen (except if the command is in the QOUTFIFO, in which
+ *       case we would like it to complete successfully instead of having to
+ *       to be re-done)
+ *   All other scenarios already dealt with by previous code.
+ */
+
+  if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
   {
-    printk("aic7xxx: Abort called with no SCB for cmd.\n");
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB aborted once already, "
+        "escalating.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_SNOOZE);
   }
-#endif
+  if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || 
+          (p->dev_flags[TARGET_INDEX(scb->cmd)] & 
+           BUS_DEVICE_RESET_PENDING) )
+  {
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "Reset/Abort pending for this "
+        "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_PENDING);
+  }
+
+  found = 0;
+  p->flags |= AHC_IN_ABORT;
+  if (aic7xxx_verbose & VERBOSE_ABORT)
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+
+/*
+ *   First, let's check to see if the currently running command is our target
+ *    since if it is, the return is fairly easy and quick since we don't want
+ *    to touch the command in case it might complete, but we do want a timeout
+ *    in case it's actually hung, so we really do nothing, but tell the mid
+ *    level code to reset the timeout.
+ */
 
-  if (p->flags & IN_TIMEOUT)
+  if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
   {
-    /*
-     * We've already started a recovery operation.
-     */
-    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
-    {
-      restore_flags(processor_flags);
-      return (SCSI_ABORT_PENDING);
-    }
-    else
+   /*
+    *  Check to see if the sequencer is just sitting on this command, or
+    *   if it's actively being run.
+    */
+    result = aic_inb(p, LASTPHASE);
+    switch (result)
     {
-      /*
-       * This is the second time we've tried to abort the recovery
-       * SCB.  We want the mid-level SCSI code to call the reset
-       * function to reset the SCSI bus.
-       */
-      restore_flags(processor_flags);
-      return (SCSI_ABORT_NOT_RUNNING);
+      case P_DATAOUT:    /*    For any of these cases, we can assume we are */
+      case P_DATAIN:     /*    an active command and act according.  For    */
+      case P_COMMAND:    /*    anything else we are going to fall on through*/
+      case P_STATUS:     /*    The SCSI_ABORT_SNOOZE will give us two abort */
+      case P_MESGOUT:    /*    chances to finish and then escalate to a     */
+      case P_MESGIN:     /*    reset call                                   */
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB is currently active.  "
+                "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        unpause_sequencer(p, FALSE);
+        p->flags &= ~AHC_IN_ABORT;
+        scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
+        p->flags |= AHC_ABORT_PENDING;  /*  here so we will know not to    */
+        DRIVER_UNLOCK                   /*  muck with other SCBs if this   */
+        return(SCSI_ABORT_PENDING);     /*  one doesn't complete and clear */
+        break;                          /*  out.                           */
+      default:
+        break;
     }
   }
-  if (cmd->serial_number != cmd->serial_number_at_timeout)
+
+  if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+      int tindex = TARGET_INDEX(cmd);
+     
+      if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
+        printk(INFO_LEAD "SCB found on waiting list and "
+            "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+      scbq_remove(&p->waiting_scbs, scb);
+      scbq_remove(&p->delayed_scbs[tindex], scb);
+      p->dev_active_cmds[tindex]++;
+      p->activescbs++;
+      scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
+      scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+      found = 1;
   }
-  else if (scb == NULL)
+
+/*
+ *  We just checked the waiting_q, now for the QINFIFO
+ */
+  if ( found == 0 )
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+    if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, 
+                     cmd->channel,
+                     cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
+                     FALSE, NULL)) != 0) &&
+                    (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
+      printk(INFO_LEAD "SCB found in QINFIFO and "
+        "aborted.\n", p->host_no, CTL_OF_SCB(scb));
   }
-  else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
+
+/*
+ *  QINFIFO, waitingq, completeq done.  Next, check WAITING_SCB list in card
+ */
+
+  if ( found == 0 )
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+    unsigned char scb_next_ptr;
+    prev_hscbptr = SCB_LIST_NULL;
+    saved_hscbptr = aic_inb(p, SCBPTR);
+    next_hscbptr = aic_inb(p, WAITING_SCBH);
+    while ( next_hscbptr != SCB_LIST_NULL )
+    {
+      aic_outb(p,  next_hscbptr, SCBPTR );
+      if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
+      {
+        found = 1;
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB found on hardware waiting"
+            " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+        if ( prev_hscbptr == SCB_LIST_NULL )
+        {
+            aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
+            aic_outb(p, 0, SCSISEQ);    /* stop the selection since we just
+                                         * grabbed the scb out from under the
+                                         * card */
+        }
+        else
+        {
+            scb_next_ptr = aic_inb(p, SCB_NEXT);
+            aic_outb(p, prev_hscbptr, SCBPTR);
+            aic_outb(p, scb_next_ptr, SCB_NEXT);
+            aic_outb(p, next_hscbptr, SCBPTR);
+        }
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        aic7xxx_add_curscb_to_free_list(p);
+        scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+        break;
+      }
+      prev_hscbptr = next_hscbptr;
+      next_hscbptr = aic_inb(p, SCB_NEXT);
+    }
+    aic_outb(p,  saved_hscbptr, SCBPTR );
   }
-  else
+        
+/*
+ *  Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
+ *  OK...the sequencer's paused, interrupts are off, and we haven't found the
+ *  command anyplace where it could be easily aborted.  Time for the hard
+ *  work.  We also know the command is valid.  This essentially means the
+ *  command is disconnected, or connected but not into any phases yet, which
+ *  we know due to the tests we ran earlier on the current active scb phase.
+ *  At this point we can queue the abort tag and go on with life.
+ */
+
+  if ( found == 0 )
   {
-    /*
-     * XXX - Check use of IN_TIMEOUT to see if we're Doing the
-     *       Right Thing with it.
-     */
-    p->flags |= IN_TIMEOUT;
-    result = aic7xxx_bus_device_reset(p, scb->cmd);
-    switch (result)
+    p->flags |= AHC_ABORT_PENDING;
+    scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+    scb->hscb->control |= MK_MESSAGE;
+    result=aic7xxx_find_scb(p, scb);
+    if ( result != SCB_LIST_NULL ) 
     {
-      case SCSI_RESET_NOT_RUNNING:
-        p->flags &= ~IN_TIMEOUT;
-        result = SCSI_ABORT_NOT_RUNNING;
-        break;
-      case SCSI_RESET_PENDING:
-        result = SCSI_ABORT_PENDING;
-        break;
-      default:
-        p->flags &= ~IN_TIMEOUT;
-        result = SCSI_ABORT_SNOOZE;
-        break;
-     }
+      saved_hscbptr = aic_inb(p, SCBPTR);
+      aic_outb(p, result, SCBPTR);
+      tmp_char = aic_inb(p, SCB_CONTROL);
+      aic_outb(p,  tmp_char | MK_MESSAGE, SCB_CONTROL);
+      aic_outb(p, saved_hscbptr, SCBPTR);
+    }
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
+        " SCB.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
   }
-  restore_flags(processor_flags);
-  return (result);
+  if (found)
+  {
+    aic7xxx_run_done_queue(p, TRUE);
+    aic7xxx_run_waiting_queues(p);
+  }
+  p->flags &= ~AHC_IN_ABORT;
+  unpause_sequencer(p, FALSE);
+  DRIVER_UNLOCK
+
+/*
+ *  On the return value.  If we found the command and aborted it, then we know
+ *  it's already sent back and there is no reason for a further timeout, so
+ *  we use SCSI_ABORT_SUCCESS.  On the queued abort side, we aren't so certain
+ *  there hasn't been a bus hang or something that might keep the abort from
+ *  from completing.  Therefore, we use SCSI_ABORT_PENDING.  The first time this
+ *  is passed back, the timeout on the command gets extended, the second time
+ *  we pass this back, the mid level SCSI code calls our reset function, which
+ *  would shake loose a hung bus.
+ */
+  if ( found != 0 )
+    return(SCSI_ABORT_SUCCESS);
+  else
+    return(SCSI_ABORT_PENDING); 
 }
 
 
@@ -6806,190 +8644,257 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
 {
   struct aic7xxx_scb *scb = NULL;
   struct aic7xxx_host *p;
-  unsigned long base;
-  int    found, tindex, min_target, max_target;
+  int    tindex;
   int    result = -1;
-  char   channel = 'A';
-  unsigned long processor_flags;
+  unsigned long cpu_flags = 0;
+#define DEVICE_RESET 0x01
+#define BUS_RESET    0x02
+#define HOST_RESET   0x04
+#define FAIL         0x08
+#define RESET_DELAY  0x10
+  int        action;
+  Scsi_Cmnd *cmd_prev, *cmd_next;
 
-  p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  base = p->base;
-  channel = cmd->channel ? 'B': 'A';
-  tindex = TARGET_INDEX(cmd);
 
-#if 0   /* AIC7XXX_DEBUG_ABORT */
-  if (scb != NULL)
-  {
-    printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
-           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
-  }
-  else
+  if ( cmd == NULL )
   {
-    printk("aic7xxx: Reset called with no SCB for cmd.\n");
+    printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
+      "pointer, failing.\n");
+    return(SCSI_RESET_SNOOZE);
   }
-#endif
 
-  /* 
-   * This routine is called by scsi.c, in which case the interrupts
-   * very well may be on when we are called.  As such, we need to save
-   * the flags to be sure, then turn interrupts off, and then call our
-   * various method funtions which all assume interrupts are off.
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  tindex = TARGET_INDEX(cmd);
+
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
    */
-  save_flags(processor_flags);
-  cli();
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
 
-  if (scb->cmd != cmd)
-    scb = NULL;
+  DRIVER_LOCK
 
-  if (p->flags & IN_TIMEOUT)
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
-    /*
-     * We've already started a recovery operation.
-     */
-    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+    aic7xxx_isr(p->irq, p, (void *)NULL );
+    pause_sequencer(p);
+  }
+
+  if (scb == NULL)
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
+    {
+      action = HOST_RESET;
+    }
+    else
     {
-      restore_flags(processor_flags);
-      return (SCSI_RESET_PENDING);
+      action = BUS_RESET;
     }
   }
-  else
+  else if (scb->cmd != cmd) 
   {
-    if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
-        && (scb != NULL))
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+    printk(INFO_LEAD "Reset called with recycled SCB "
+        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+    cmd_prev = NULL;
+    cmd_next = p->completeq.head;
+    while ( cmd_next != NULL )
     {
-      /*
-       * Attempt a bus device reset if commands have completed successfully
-       * since the last bus device reset, or it has been less than 100ms
-       * since the last reset.
-       */
-      if ((p->flags & DEVICE_SUCCESS) ||
-          ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
+      if (cmd_next == cmd)
       {
-       if (cmd->serial_number != cmd->serial_number_at_timeout)
-       {
-          result = SCSI_RESET_NOT_RUNNING;
-       }
-       else if (scb == NULL)
-        {
-          result = SCSI_RESET_NOT_RUNNING;
-        }
-        else if (flags & SCSI_RESET_ASYNCHRONOUS)
-        {
-          if (scb->flags & SCB_ABORTED)
-          {
-            result = SCSI_RESET_PENDING;
-          }
-          else if (!(scb->flags & SCB_ACTIVE))
-          {
-            result = SCSI_RESET_NOT_RUNNING;
-          }
-        }
-
-        if (result == -1)
-        {
-          if ((flags & SCSI_RESET_SYNCHRONOUS) &&
-              (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
-          {
-            scb->flags |= SCB_ABORTED;
-            result = SCSI_RESET_PENDING;
-          }
-          else
-          {
-            p->flags |= IN_TIMEOUT;
-            result = aic7xxx_bus_device_reset(p, cmd);
-            if (result == 0)
-            {
-              p->flags &= ~IN_TIMEOUT;
-              result = SCSI_RESET_PENDING;
-            }
-          }
-       }
+        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+          printk(INFO_LEAD "Reset, found cmd on completeq"
+          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_RESET_NOT_RUNNING);
       }
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
+    {
+      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "Reset, cmd not found,"
+          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_NOT_RUNNING);
+    }
+    else
+    {
+      if (aic7xxx_verbose & VERBOSE_RESET_MID)
+        printk(INFO_LEAD "Reset called, no scb, "
+          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
+      scb = NULL;
+      action = HOST_RESET;
     }
   }
-  if (result == -1)
+  else
   {
-    /*
-     * The bus device reset failed; try resetting the channel.
-     */
-    if (!(flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
-        && (flags & SCSI_RESET_ASYNCHRONOUS))
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called, scb %d, flags "
+        "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
     {
-      if (scb == NULL)
-      {
-       result = SCSI_RESET_NOT_RUNNING;
-      }
-      else if (!(scb->flags & SCB_ACTIVE))
-      {
-       result = SCSI_RESET_NOT_RUNNING;
-      }
-      else if ((scb->flags & SCB_ABORTED) &&
-               (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
-      {
-       result = SCSI_RESET_PENDING;
-      }
+      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
+          CTL_OF_SCB(scb));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_NOT_RUNNING);
     }
-
-    if (result == -1)
+    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
-      /*
-       * The reset channel function assumes that the sequencer is paused.
-       */
-      pause_sequencer(p);
-      found = aic7xxx_reset_channel(p, channel, TRUE);
-      p->flags = p->flags & ~IN_TIMEOUT;
-
-      /*
-       * If this is a synchronous reset and there is no SCB for this
-       * command, perform completion processing.
-       *
-       */
-      if ((flags & SCSI_RESET_SYNCHRONOUS) && (scb == NULL))
+      action = HOST_RESET;
+    }
+    else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
+    {
+      action = BUS_RESET;
+    }
+    else 
+    {
+      action = DEVICE_RESET;
+    }
+  }
+  if ( (action & DEVICE_RESET) && 
+        (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Bus device reset already sent to "
+        "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) &&
+       (scb->flags & SCB_QUEUED_ABORT) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    {
+      printk(INFO_LEAD "Have already attempted to reach "
+        "device with queued\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "message, will escalate to bus "
+        "reset.\n", p->host_no, CTL_OF_CMD(cmd));
+    }
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) && 
+       (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+     printk(INFO_LEAD "Bus device reset stupid when "
+        "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & BUS_RESET) && !(p->type & AHC_TWIN) )
+  {
+    action = HOST_RESET;
+  }
+  if ( ((jiffies - p->dev_last_reset[tindex]) < (HZ * 3)) &&
+       !(action & (HOST_RESET | BUS_RESET)))
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    {
+      printk(INFO_LEAD "Reset called too soon after last "
+        "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
+        CTL_OF_CMD(cmd));
+    }
+    action = BUS_RESET;
+  }
+  if ( ((jiffies - p->last_reset) < (HZ * 3)) &&
+        (action & (HOST_RESET | BUS_RESET)) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Reset called too soon after "
+        "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = RESET_DELAY;
+  }
+  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & AHC_IN_RESET)
+        && ((jiffies - p->reset_start) > (2 * HZ * 3)) )
+  {
+    printk(KERN_ERR "(scsi%d:%d:%d:%d) Yikes!!  Card must have left to go "
+        "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_RESET_SNOOZE);
+  }
+/*
+ *  By this point, we want to already know what we are going to do and
+ *  only have the following code implement our course of action.
+ */
+  switch (action)
+  {
+    case RESET_DELAY:
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_PENDING);
+      break;
+    case FAIL:
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_ERROR);
+      break;
+    case DEVICE_RESET:
+      p->flags |= AHC_IN_RESET;
+      result = aic7xxx_bus_device_reset(p, cmd);
+      aic7xxx_run_done_queue(p, TRUE);
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
+      aic7xxx_run_waiting_queues(p);
+      unpause_sequencer(p, FALSE);
+      p->flags &= ~AHC_IN_RESET;
+      DRIVER_UNLOCK
+      return(result);
+      break;
+    case BUS_RESET:
+    case HOST_RESET:
+    default:
+      p->reset_start = jiffies;
+      p->flags |= AHC_IN_RESET;
+      aic7xxx_reset_channel(p, cmd->channel, TRUE);
+      if ( (p->type & AHC_TWIN) && (action & HOST_RESET) )
       {
-       cmd->result = DID_RESET << 16;
-       cmd->scsi_done(cmd);
+        aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
+        restart_sequencer(p);
       }
-
-      switch (p->bus_type)
+      if (scb == NULL)
       {
-       case AIC_TWIN:
-         if (channel == 'B')
-         {
-            min_target = 8;
-            max_target = 15;
-         }
-         else
-         {
-            min_target = 0;
-            max_target = 7;
-         }
-         break;
-
-       case AIC_WIDE:
-         min_target = 0;
-         max_target = 15;
-         break;
-
-       case AIC_SINGLE:
-        default:
-         min_target = 0;
-         max_target = 7;
-         break;
+        cmd->result = DID_RESET << 16;
+        cmd->done(cmd);
       }
-
-      for (tindex = min_target; tindex <= max_target; tindex++)
+      p->last_reset = jiffies;
+      if (action != HOST_RESET)
+        result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+      else
       {
-       p->device_status[tindex].last_reset = jiffies;
+        result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+        aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
+          SIMODE1);
+        aic7xxx_clear_intstat(p);
+        p->flags &= ~AHC_HANDLING_REQINITS;
+        p->msg_type = MSG_TYPE_NONE;
+        p->msg_index = 0;
+        p->msg_len = 0;
       }
-
-      result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-      p->flags &= ~IN_TIMEOUT;
-    }
+      p->flags &= ~AHC_IN_RESET;
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
+      aic7xxx_run_waiting_queues(p);
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(result);
+      break;
   }
-  aic7xxx_run_waiting_queues(p);
-  restore_flags(processor_flags);
-  return (result);
 }
 
 /*+F*************************************************************************
@@ -7016,7 +8921,7 @@ aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
   sectors = 32;
   cylinders = disk->capacity / (heads * sectors);
 
-  if ((p->flags & EXTENDED_TRANSLATION) && (cylinders > 1024))
+  if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
   {
     heads = 255;
     sectors = 63;
index d1b92b556368cbd460db6c6dca7e759bf09b2282..0fa8744b9c4732b20aa277788060ba1755d1ea38 100644 (file)
 #ifndef _aic7xxx_h
 #define _aic7xxx_h
 
-#define AIC7XXX_H_VERSION  "$Revision: 3.2 $"
+#define AIC7XXX_H_VERSION  "3.2.4"
 
-#ifdef __i386__
-#define AIC7XXX_BIOSPARAM      aic7xxx_biosparam
+#ifndef LINUX_KERNEL_VERSION
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if defined(__i386__)
+#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
 #else
-#define AIC7XXX_BIOSPARAM      NULL
+#  define AIC7XXX_BIOSPARAM NULL
 #endif
 
 /*
  * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
  * to do with card config are filled in after the card is detected.
  */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
+#define AIC7XXX        {                                               \
+       next: NULL,                                             \
+       module: NULL,                                           \
+       proc_dir: NULL,                                         \
+       proc_info: aic7xxx_proc_info,                           \
+       name: NULL,                                             \
+       detect: aic7xxx_detect,                                 \
+       release: NULL,                                          \
+       info: aic7xxx_info,                                     \
+       command: NULL,                                          \
+       queuecommand: aic7xxx_queue,                            \
+       eh_strategy_handler: NULL,                              \
+       eh_abort_handler: NULL,                                 \
+       eh_device_reset_handler: NULL,                          \
+       eh_bus_reset_handler: NULL,                             \
+       eh_host_reset_handler: NULL,                            \
+       abort: aic7xxx_abort,                                   \
+       reset: aic7xxx_reset,                                   \
+       slave_attach: NULL,                                     \
+       bios_param: AIC7XXX_BIOSPARAM,                          \
+       can_queue: 255,         /* max simultaneous cmds      */\
+       this_id: -1,            /* scsi id of host adapter    */\
+       sg_tablesize: 0,        /* max scatter-gather cmds    */\
+       cmd_per_lun: 3,         /* cmds per lun (linked cmds) */\
+       present: 0,             /* number of 7xxx's present   */\
+       unchecked_isa_dma: 0,   /* no memory DMA restrictions */\
+       use_clustering: ENABLE_CLUSTERING,                      \
+       use_new_eh_code: 0                                      \
+}
+#else
 #define AIC7XXX        {                                               \
-       proc_info:       aic7xxx_proc_info,                                     \
-       detect:          aic7xxx_detect,                                        \
-       info:            aic7xxx_info,                                          \
-       queuecommand:    aic7xxx_queue,                                         \
-       abort:           aic7xxx_abort,                                         \
-       reset:           aic7xxx_reset,                                         \
-       bios_param:      AIC7XXX_BIOSPARAM,                                     \
-       can_queue:       -1,                    /* max simultaneous cmds      */\
-       this_id:         -1,                    /* scsi id of host adapter    */\
-       sg_tablesize:    SG_ALL,                /* max scatter-gather cmds    */\
-       cmd_per_lun:     2,                     /* cmds per lun (linked cmds) */\
-       use_clustering:  ENABLE_CLUSTERING,                                     \
-       use_new_eh_code: 0                      /* Enable new error code */     \
+       next: NULL,                                             \
+       usage_count: NULL,                                      \
+       proc_dir: NULL,                                         \
+       proc_info: aic7xxx_proc_info,                           \
+       name: NULL,                                             \
+       detect: aic7xxx_detect,                                 \
+       release: NULL,                                          \
+       info: aic7xxx_info,                                     \
+       command: NULL,                                          \
+       queuecommand: aic7xxx_queue,                            \
+       abort: aic7xxx_abort,                                   \
+       reset: aic7xxx_reset,                                   \
+       slave_attach: NULL,                                     \
+       bios_param: AIC7XXX_BIOSPARAM,                          \
+       can_queue: 255,         /* max simultaneous cmds      */\
+       this_id: -1,            /* scsi id of host adapter    */\
+       sg_tablesize: 0,        /* max scatter-gather cmds    */\
+       cmd_per_lun: 3,         /* cmds per lun (linked cmds) */\
+       present: 0,             /* number of 7xxx's present   */\
+       unchecked_isa_dma: 0,   /* no memory DMA restrictions */\
+       use_clustering: ENABLE_CLUSTERING                       \
 }
+#endif
 
 extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
 extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
 extern int aic7xxx_detect(Scsi_Host_Template *);
 extern int aic7xxx_command(Scsi_Cmnd *);
-extern int aic7xxx_abort(Scsi_Cmnd *);
 extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
+extern int aic7xxx_abort(Scsi_Cmnd *);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
 
index 58254a2754ec8040a62baf2e18f2bb07c8f17e69..6dffebc8bf1cf20ede945c18ce04d7847ed633d6 100644 (file)
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
@@ -392,6 +389,27 @@ register SELID {
        bit     ONEBIT          0x08
 }
 
+/*
+ * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
+ * Indicates if external logic has been attached to the chip to
+ * perform the tasks of accessing a serial eeprom, testing termination
+ * strength, and performing cable detection.  On the aic7860, most of
+ * these features are handled on chip, but on the aic7855 an attached
+ * aic3800 does the grunt work.
+ */
+register SPIOCAP {
+       address                 0x01b
+       access_mode RW
+       bit     SOFT1           0x80
+       bit     SOFT0           0x40
+       bit     SOFTCMDEN       0x20    
+       bit     HAS_BRDCTL      0x10    /* External Board control */
+       bit     SEEPROM         0x08    /* External serial eeprom logic */
+       bit     EEPROM          0x04    /* Writable external BIOS ROM */
+       bit     ROM             0x02    /* Logic for accessing external ROM */
+       bit     SSPIOCPS        0x01    /* Termination and cable detection */
+}
+
 /*
  * SCSI Block Control (p. 3-32)
  * Controls Bus type and channel selection.  In a twin channel configuration
@@ -622,26 +640,19 @@ register INTSTAT {
        mask    NO_IDENT        0x20|SEQINT     /* no IDENTIFY after reconnect*/
        mask    NO_MATCH        0x30|SEQINT     /* no cmd match for reconnect */
        mask    EXTENDED_MSG    0x40|SEQINT     /* Extended message received */
-       mask    NO_MATCH_BUSY   0x50|SEQINT     /* Couldn't find BUSY SCB */
+       mask    ABORT_REQUESTED 0x50|SEQINT     /* Reconect of aborted SCB */
        mask    REJECT_MSG      0x60|SEQINT     /* Reject message received */
        mask    BAD_STATUS      0x70|SEQINT     /* Bad status from target */
        mask    RESIDUAL        0x80|SEQINT     /* Residual byte count != 0 */
-       mask    ABORT_CMDCMPLT  0x91            /*
-                                                * Command tagged for abort
-                                                * completed successfully.
-                                                */
        mask    AWAITING_MSG    0xa0|SEQINT     /*
                                                 * Kernel requested to specify
-                                                 * a message to this target
-                                                 * (command was null), so tell
-                                                 * it that it can fill the
-                                                 * message buffer.
-                                                 */
-       mask    MSG_BUFFER_BUSY 0xc0|SEQINT     /*
-                                                * Sequencer wants to use the
-                                                * message buffer, but it
-                                                * already contains a message
+                                                * a message to this target
+                                                * (command was null), so tell
+                                                * it that it can fill the
+                                                * message buffer.
                                                 */
+       mask    TRACEPOINT      0xb0|SEQINT
+       mask    TRACEPOINT2     0xc0|SEQINT
        mask    MSGIN_PHASEMIS  0xd0|SEQINT     /*
                                                 * Target changed phase on us
                                                 * when we were expecting
@@ -665,7 +676,10 @@ register INTSTAT {
 register ERROR {
        address                 0x092
        access_mode RO
-       bit     PARERR          0x08
+       bit     PCIERRSTAT      0x40    /* PCI only */
+       bit     MPARERR         0x20    /* PCI only */
+       bit     DPARERR         0x10    /* PCI only */
+       bit     SQPARERR        0x08
        bit     ILLOPCODE       0x04
        bit     ILLSADDR        0x02
        bit     ILLHADDR        0x01
@@ -677,6 +691,7 @@ register ERROR {
 register CLRINT {
        address                 0x092
        access_mode WO
+       bit     CLRPARERR       0x10    /* PCI only */
        bit     CLRBRKADRINT    0x08
        bit     CLRSCSIINT      0x04
        bit     CLRCMDINT       0x02
@@ -771,8 +786,6 @@ scb {
                bit     MK_MESSAGE      0x80
                bit     DISCENB         0x40
                bit     TAG_ENB         0x20
-               bit     MUST_DMAUP_SCB  0x10
-               bit     ABORT_SCB       0x08
                bit     DISCONNECTED    0x04
                mask    SCB_TAG_TYPE    0x03
        }
@@ -801,10 +814,11 @@ scb {
                size    4
        }
        SCB_DATACNT {
-               size    3
-       }
-       SCB_LINKED_NEXT {
-               size    1
+               /*
+                * Really only 3 bytes, but padded to make
+                * the kernel's job easier.
+                */
+               size    4
        }
        SCB_CMDPTR {
                size    4
@@ -924,6 +938,9 @@ scratch_ram {
        TARG_SCRATCH {
                size            16
        }
+       /*
+        * Bit vector of targets that have ULTRA enabled.
+        */
        ULTRA_ENB {
                size            2
        }
@@ -934,14 +951,11 @@ scratch_ram {
                size            2
        }
        /*
-        * Length of pending message
+        * Single byte buffer used to designate the type or message
+        * to send to a target.
         */
-       MSG_LEN {
-               size            1
-       }
-       /* We reserve 8bytes to store outgoing messages */
        MSG_OUT {
-               size            8
+               size            1
        }
        /* Parameters for DMA Logic */
        DMAPARAMS {
@@ -956,35 +970,12 @@ scratch_ram {
                bit     FIFOFLUSH       0x02
                bit     FIFORESET       0x01
        }
-       /*
-        * Number of SCBs supported by
-        * this card.
-        */
-       SCBCOUNT {
-               size            1
-       }
-       /*
-        * Two's complement of SCBCOUNT
-        */
-       COMP_SCBCOUNT {
-               size            1
-       }
-       /*
-        * Mask of bits to test against
-        * when looking at the Queue Count
-        * registers.  Works around a bug
-        * on aic7850 chips. 
-        */
-       QCNTMASK {
-               size            1
-       }
        SEQ_FLAGS {
                size            1
-               bit     RESELECTED      0x80
-               bit     IDENTIFY_SEEN   0x40
-               bit     TAGGED_SCB      0x20
+               bit     IDENTIFY_SEEN   0x80
+               bit     SCBPTR_VALID    0x20
                bit     DPHASE          0x10
-               bit     PAGESCBS        0x04
+               bit     AMTARGET        0x08
                bit     WIDE_BUS        0x02
                bit     TWIN_BUS        0x01
        }
@@ -996,33 +987,14 @@ scratch_ram {
        SAVED_TCL {
                size            1
        }
+       /* Working value of the number of SG segments left */
        SG_COUNT {
                size            1
        }
-       /* working value of SG pointer */
+       /* Working value of SG pointer */
        SG_NEXT {
                size            4
        }
-       /*
-        * head of list of SCBs awaiting
-        * selection
-        */
-       WAITING_SCBH {
-               size            1
-       }
-       SAVED_LINKPTR {
-               size            1
-       }
-       SAVED_SCBPTR {
-               size            1
-       }
-       /*
-        * The sequencer will stick the frist byte of any rejected message here
-        * so we can see what is getting thrown away.
-        */
-       REJBYTE {
-               size            1
-       }
        /*
         * The last bus phase as seen by the sequencer. 
         */
@@ -1040,23 +1012,12 @@ scratch_ram {
                mask    P_MESGIN        CDI|IOI|MSGI
                mask    P_BUSFREE       0x01
        }
-       MSGIN_EXT_LEN {
-               size            1
-       }
-       MSGIN_EXT_OPCODE {
-               size            1
-       }
        /*
-        * location 3, stores the last
-        * byte of an extended message if
-        * it passes the two bytes of space
-        * we allow now.  This byte isn't
-        * used for anything, it just makes
-        * the code shorter for tossing
-        * extra bytes.
+        * head of list of SCBs awaiting
+        * selection
         */
-       MSGIN_EXT_BYTES {
-               size            3
+       WAITING_SCBH {
+               size            1
        }
        /*
         * head of list of SCBs that are
@@ -1073,10 +1034,40 @@ scratch_ram {
        FREE_SCBH {
                size            1
        }
+       /*
+        * Address of the hardware scb array in the host.
+        */
        HSCB_ADDR {
                size            4
        }
-       CUR_SCBID {
+       /*
+        * Address of the 256 byte array storing the SCBID of outstanding
+        * untagged SCBs indexed by TCL.
+        */
+       SCBID_ADDR {
+               size            4
+       }
+       /*
+        * Address of the array of command descriptors used to store
+        * information about incoming selections.
+        */
+       TMODE_CMDADDR {
+               size            4
+       }
+       KERNEL_QINPOS {
+               size            1
+       }
+       QINPOS {
+               size            1
+       }
+       QOUTPOS {
+               size            1
+       }
+       /*
+        * Offset into the command descriptor array for the next
+        * available desciptor to use.
+        */
+       TMODE_CMDADDR_NEXT {
                size            1
        }
        ARG_1 {
@@ -1084,30 +1075,13 @@ scratch_ram {
                mask    SEND_MSG        0x80
                mask    SEND_SENSE      0x40
                mask    SEND_REJ        0x20
+               mask    MSGOUT_PHASEMIS 0x10
                alias   RETURN_1
        }
        /*
-        * Running count of commands placed in
-        * the QOUTFIFO.  This is cleared by the
-        * kernel driver every FIFODEPTH commands.
-        *
-        * NOTE: These scratch RAM registers are overlaying SCSICONF
-        *       and SCSICONF2 and are only used on cards that are
-        *       capable of SCB paging.   Currently, only the PCI
-        *       controllers can do this, which is good because the
-        *       AIC-7770 based controllers use the SCSICONF register
-        *       to control termination.  In other words, do not
-        *       destroy the contents of SCSICONF and SCSICONF2 for
-        *       AIC-7770 based controllers.
+        * Snapshot of MSG_OUT taken after each message is sent.
         */
-       CMDOUTCNT {
-               size            1
-       }
-       /*
-        * Maximum number of entries allowed in
-        * the QOUT/INFIFO.
-        */
-       FIFODEPTH {
+       LAST_MSG {
                size            1
        }
        /*
@@ -1118,12 +1092,10 @@ scratch_ram {
        SCSICONF {
                address         0x05a
                size            1
+               bit     TERM_ENB        0x80
                bit     RESET_SCSI      0x40
-       }
-        SCSICONF2 {
-               address         0x05b
-               size            1
-               bit     RESET_SCSI      0x40
+               mask    HSCSIID         0x07    /* our SCSI ID */
+               mask    HWSCSIID        0x0f    /* our SCSI ID if Wide Bus */
        }
        HOSTCONF {
                address         0x05d
@@ -1140,6 +1112,10 @@ scratch_ram {
 
 const SCB_LIST_NULL    0xff
 
+/* Offsets into the SCBID array where different data is stored */
+const UNTAGGEDSCB_OFFSET       0
+const QOUTFIFO_OFFSET          1
+const QINFIFO_OFFSET           2
 
 /* WDTR Message values */
 const BUS_8_BIT                0x00
@@ -1147,3 +1123,24 @@ const BUS_16_BIT         0x01
 const BUS_32_BIT               0x02
 const MAX_OFFSET_8BIT          0x0f
 const MAX_OFFSET_16BIT 0x08
+const HOST_MSG         0xFF
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT     0x05
+const CMD_GROUP0_BYTE_DELTA    -4
+const CMD_GROUP2_BYTE_DELTA    -6
+const CMD_GROUP4_BYTE_DELTA    4
+const CMD_GROUP5_BYTE_DELTA    11
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+/*
+ * Mask of bits to test against when looking at the Queue Count
+ * registers.  Works around a bug on aic7850 chips. 
+ */
+const QCNTMASK         download
+/*
+ * Number of command descriptors in the command descriptor array.
+ */
+const TMODE_NUMCMDS    download
index 201a99c0e0469853d7a7c431f553a7df6f3adc45..b4613387f2a913c6650bca1124cc5c92475be518 100644 (file)
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
@@ -38,8 +35,8 @@
  *     $Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
  */
 
-#include <aic7xxx.reg>
-#include <scsi_message.h>
+#include "aic7xxx.reg"
+#include "scsi_message.h"
 
 /*
  * A few words on the waiting SCB list:
  * automatically consume the entries.
  */
 
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
 reset:
        clr     SCSISIGO;               /* De-assert BSY */
        /* Always allow reselection */
+.if ( TARGET_MODE )
+       mvi     SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+.else
        mvi     SCSISEQ, ENRSELI|ENAUTOATNP;
+.endif
        call    clear_target_state;
+       and     SXFRCTL0, ~SPIOEN;
 poll_for_work:
-       test    SSTAT0,SELDO    jnz select;
-       test    SSTAT0,SELDI    jnz reselect;
+       mov     A, QINPOS;
+poll_for_work_loop:
+       and     SEQCTL, ~PAUSEDIS;
+       test    SSTAT0, SELDO|SELDI     jnz selection;
        test    SCSISEQ, ENSELO jnz poll_for_work;
 .if ( TWIN_CHANNEL )
        /*
@@ -80,16 +80,17 @@ poll_for_work:
         * either a selection or reselection occurs.
         */
        xor     SBLKCTL,SELBUSB;        /* Toggle to the other bus */
-       test    SSTAT0,SELDO    jnz select;
-       test    SSTAT0,SELDI    jnz reselect;
+       test    SSTAT0, SELDO|SELDI     jnz selection;
        test    SCSISEQ, ENSELO jnz poll_for_work;
        xor     SBLKCTL,SELBUSB;        /* Toggle back */
 .endif
        cmp     WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
 test_queue:
        /* Has the driver posted any work for us? */
-       mov     A, QCNTMASK;
-       test    QINCNT,A        jz poll_for_work;
+       or      SEQCTL, PAUSEDIS;
+       cmp     KERNEL_QINPOS, A je poll_for_work_loop;
+       inc     QINPOS;
+       and     SEQCTL, ~PAUSEDIS;
 
 /*
  * We have at least one queued SCB now and we don't have any 
@@ -99,76 +100,24 @@ test_queue:
  */
 .if ( SCB_PAGING )
        mov     ALLZEROS        call    get_free_or_disc_scb;
-       cmp     SINDEX, SCB_LIST_NULL   je poll_for_work;
 .endif
 dequeue_scb:
-       mov     CUR_SCBID,QINFIFO;
+       add     A, -1, QINPOS;
+       mvi     QINFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+       mvi     DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+       call    dma_finish;
+       mov     SINDEX, DFDAT;
 .if !( SCB_PAGING )
        /* In the non-paging case, the SCBID == hardware SCB index */
-       mov     SCBPTR, CUR_SCBID;
+       mov     SCBPTR, SINDEX;
 .endif
 dma_queued_scb:
 /*
  * DMA the SCB from host ram into the current SCB location.
  */
        mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     CUR_SCBID       call dma_scb;
-
-/*
- * See if there is not already an active SCB for this target.  This code
- * locks out on a per target basis instead of target/lun.  Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands.  We also don't have enough spare SCB space for us to store the
- * SCBID of the currently busy transaction for each target/lun making it
- * impossible to link up the SCBs.
- */
-test_busy:
-       test    SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
-       mvi     SEQCTL, PAUSEDIS|FASTMODE;
-       mov     SAVED_SCBPTR, SCBPTR;
-       mov     SCB_TCL         call    index_untagged_scb;
-       mov     ARG_1, SINDIR;                  /*
-                                                * ARG_1 should
-                                                * now have the SCB ID of
-                                                * any active, non-tagged,
-                                                * command for this target.
-                                                */
-       cmp     ARG_1, SCB_LIST_NULL je make_busy;
-.if ( SCB_PAGING )
-       /*
-        * Put this SCB back onto the free list.  It
-        * may be necessary to satisfy the search for
-        * the active SCB.
-        */
-       mov     SCBPTR, SAVED_SCBPTR;
-       call    add_scb_to_free_list;
-       /* Find the active SCB */
-       mov     ALLZEROS        call findSCB;
-       /*
-        * If we couldn't find it, tell the kernel.  This should
-        * never happen.
-        */
-       cmp     SINDEX, SCB_LIST_NULL   jne paged_busy_link;
-       mvi     INTSTAT, NO_MATCH_BUSY;
-paged_busy_link:
-       /* Link us in */
-       mov     SCB_LINKED_NEXT, CUR_SCBID;
-       /* Put it back on the disconnected list */
-       call    add_scb_to_disc_list;
-       mvi     SEQCTL, FASTMODE;
-       jmp     poll_for_work;
-.else
-simple_busy_link:
-       mov     SCBPTR, ARG_1;
-       mov     SCB_LINKED_NEXT, CUR_SCBID;
-       mvi     SEQCTL, FASTMODE;
-       jmp     poll_for_work;
-.endif
-make_busy:
-       mov     DINDIR, CUR_SCBID;
-       mov     SCBPTR, SAVED_SCBPTR;
-       mvi     SEQCTL, FASTMODE;
+       call    dma_scb;
 
 start_scb:
        /*
@@ -179,9 +128,7 @@ start_scb:
        mov     WAITING_SCBH, SCBPTR;
 start_waiting:
        /*
-        * Pull the first entry off of the waiting SCB list
-        * We don't have to "test_busy" because only transactions that
-        * have passed that test can be in the WAITING_SCB list.
+        * Pull the first entry off of the waiting SCB list.
         */
        mov     SCBPTR, WAITING_SCBH;
        call    start_selection;
@@ -199,17 +146,170 @@ initialize_scsiid:
        and     SCSIID, OID;            /* Clear old target */
        or      SCSIID, A;
        mvi     SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ * SINDEX should contain any additional bit's the client wants
+ * set in SXFRCTL0.
+ */
+initialize_channel:
+       or      A, CLRSTCNT|CLRCHN, SINDEX;
+       or      SXFRCTL0, A;
+.if ( ULTRA )
+ultra:
+       mvi     SINDEX, ULTRA_ENB+1;
+       test    SAVED_TCL, 0x80         jnz ultra_2;    /* Target ID > 7 */
+       dec     SINDEX;
+ultra_2:
+       mov     FUNCTION1,SAVED_TCL;
+       mov     A,FUNCTION1;
+       test    SINDIR, A       jz ndx_dtr;
+       or      SXFRCTL0, FAST20;
+.endif
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ * The SCSIRATE settings for each target are stored in an array
+ * based at TARG_SCRATCH.
+ */
+ndx_dtr:
+       shr     A,4,SAVED_TCL;
+       test    SBLKCTL,SELBUSB jz ndx_dtr_2;
+       or      SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
+       or      A,0x08;                 /* Channel B entries add 8 */
+ndx_dtr_2:
+       add     SINDEX,TARG_SCRATCH,A;
+       mov     SCSIRATE,SINDIR ret;
+
+
+selection:
+       test    SSTAT0,SELDO    jnz select_out;
+select_in:
+.if ( TARGET_MODE )
+       test    SSTAT0, TARGET  jz initiator_reselect;
+       /*
+        * We've just been selected.  Assert BSY and
+        * setup the phase for receiving the messages
+        * from the target.
+        */
+       mvi     SCSISIGO, P_MESGOUT|BSYO;
+       mvi     CLRSINT0, CLRSELDO;
+
+       /*
+        * If ATN isn't asserted, go directly to bus free.
+        */
+       test    SCSISIGI, ATNI  jz      target_busfree;
+
+       /*
+        * Setup the DMA for sending the identify and
+        * command information.
+        */
+       mov     A, TMODE_CMDADDR_NEXT;
+       mvi     TMODE_CMDADDR call set_32byte_haddr_and_clrcnt;
+       mvi     DFCNTRL, FIFORESET;
+
+       clr     SINDEX;
+       /* Watch ATN closely now */
+message_loop:
+       or      SXFRCTL0, SPIOEN;
+       test    SSTAT0, SPIORDY jz .;
+       and     SXFRCTL0, ~SPIOEN;
+       mov     DINDEX, SCSIDATL;
+       mov     DFDAT, DINDEX;
+       inc     SINDEX;
+
+       /* Message Testing... */
+       test    DINDEX, MSG_IDENTIFYFLAG jz . + 2;
+       mov     ARG_1, DINDEX;
+
+       test    SCSISIGI, ATNI  jnz     message_loop;
+       add     A, -4, SINDEX;
+       jc      target_cmdphase;
+       mvi     DFDAT, SCB_LIST_NULL;   /* Terminate the message list */
+
+target_cmdphase:
+       add     HCNT[0], 1, A;
+       mvi     SCSISIGO, P_COMMAND|BSYO;
+       or      SXFRCTL0, SPIOEN;
+       test    SSTAT0, SPIORDY jz .;
+       mov     A, SCSIDATL;
+       mov     DFDAT, A;       /* Store for host */
+
+       /*
+        * Determine the number of bytes to read
+        * based on the command group code.  Count is
+        * one less than the total since we've already
+        * fetched the first byte.
+        */
+       clr     SINDEX;
+       shr     A, CMD_GROUP_CODE_SHIFT;
+       add     SEQADDR0, A;
+
+       add     SINDEX, CMD_GROUP0_BYTE_DELTA;
+       nop;    /* Group 1 and 2 are the same */
+       add     SINDEX, CMD_GROUP2_BYTE_DELTA;
+       nop;    /* Group 3 is reserved */
+       add     SINDEX, CMD_GROUP4_BYTE_DELTA;
+       add     SINDEX, CMD_GROUP5_BYTE_DELTA;
+               /* Group 6 and 7 are not handled yet */
+
+       mov     A, SINDEX;
+       add     HCNT[0], A;
+
+command_loop:
+       test    SSTAT0, SPIORDY jz .;
+       cmp     SINDEX, 1 jne . + 2;
+       and     SXFRCTL0, ~SPIOEN;      /* Last Byte */
+       mov     DFDAT, SCSIDATL;
+       dec     SINDEX;
+       test    SINDEX, 0xFF jnz command_loop;
+
+       or      DFCNTRL, HDMAEN|FIFOFLUSH;
+       
+       call    dma_finish;
+
+       test    ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
+
+       mvi     SCSISIGO, P_MESGIN|BSYO;
+
+       or      SXFRCTL0, SPIOEN;
+
+       mvi     MSG_DISCONNECT call target_outb;
+       
+selectin_post:
+       inc     TMODE_CMDADDR_NEXT;
+       cmp     TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
+       clr     TMODE_CMDADDR_NEXT;
+       mvi     QOUTFIFO, SCB_LIST_NULL;
+       mvi     INTSTAT,CMDCMPLT;
+
+       test    ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
+
+       /* Busy loop on something then go to data or status phase */
+
+target_busfree:
+       clr     SCSISIGO;
+       jmp     poll_for_work;
+
+.endif /* TARGET_MODE */
 /*
  * Reselection has been initiated by a target. Make a note that we've been
  * reselected, but haven't seen an IDENTIFY message from the target yet.
  */
-reselect:
-       clr     MSG_LEN;        /* Don't have anything in the mesg buffer */
+initiator_reselect:
        mvi     CLRSINT0, CLRSELDI;
        /* XXX test for and handle ONE BIT condition */
        and     SAVED_TCL, SELID_MASK, SELID;
-       or      SEQ_FLAGS,RESELECTED;
-       jmp     select2;
+       mvi     CLRSINT1,CLRBUSFREE;
+       or      SIMODE1, ENBUSFREE;             /*
+                                                * We aren't expecting a
+                                                * bus free, so interrupt
+                                                * the kernel driver if it
+                                                * happens.
+                                                */
+       mvi     SPIOEN call     initialize_channel;
+       mvi     MSG_OUT, MSG_NOOP;              /* No message to send */
+       jmp     ITloop;
 
 /*
  * After the selection, remove this SCB from the "waiting SCB"
@@ -217,7 +317,7 @@ reselect:
  * WAITING_SCBH.  Our next pointer will be set to null the next time this
  * SCB is used, so don't bother with it now.
  */
-select:
+select_out:
        /* Turn off the selection hardware */
        mvi     SCSISEQ, ENRSELI|ENAUTOATNP;    /*
                                                 * ATN on parity errors
@@ -227,41 +327,6 @@ select:
        mov     SCBPTR, WAITING_SCBH;
        mov     WAITING_SCBH,SCB_NEXT;
        mov     SAVED_TCL, SCB_TCL;
-/*
- * As soon as we get a successful selection, the target should go
- * into the message out phase since we have ATN asserted.  Prepare
- * the message to send.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
-
-mk_identify:
-       and     MSG_OUT,0x7,SCB_TCL;    /* lun */
-       and     A,DISCENB,SCB_CONTROL;  /* mask off disconnect privledge */
-       or      MSG_OUT,A;              /* or in disconnect privledge */
-       or      MSG_OUT,MSG_IDENTIFYFLAG;
-       mvi     MSG_LEN, 1;
-
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-mk_tag:
-       test    SCB_CONTROL,TAG_ENB jz  mk_message;
-       and     MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
-       mov     MSG_OUT[2],SCB_TAG;
-       add     MSG_LEN,2;      /* update message length */
-
-/*
- * Interrupt the driver, and allow it to tweak the message buffer
- * if it asks.
- */
-mk_message:
-       test    SCB_CONTROL,MK_MESSAGE  jz select2;
-       mvi     INTSTAT,AWAITING_MSG;
-
-select2:
        mvi     CLRSINT1,CLRBUSFREE;
        or      SIMODE1, ENBUSFREE;             /*
                                                 * We aren't expecting a
@@ -269,54 +334,24 @@ select2:
                                                 * the kernel driver if it
                                                 * happens.
                                                 */
+       mvi     SPIOEN call     initialize_channel;
 /*
- * Initialize Ultra mode setting and clear the SCSI channel.
- */
-       or      SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
-.if ( ULTRA )
-ultra:
-       mvi     SINDEX, ULTRA_ENB+1;
-       test    SAVED_TCL, 0x80         jnz ultra_2;    /* Target ID > 7 */
-       dec     SINDEX;
-ultra_2:
-       mov     FUNCTION1,SAVED_TCL;
-       mov     A,FUNCTION1;
-       test    SINDIR, A       jz ndx_dtr;
-       or      SXFRCTL0, FAST20;
-.endif
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- * The SCSIRATE settings for each target are stored in an array
- * based at TARG_SCRATCH.
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.
  */
-ndx_dtr:
-       shr     A,4,SAVED_TCL;
-       test    SBLKCTL,SELBUSB jz ndx_dtr_2;
-       or      SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
-       or      A,0x08;                 /* Channel B entries add 8 */
-ndx_dtr_2:
-       add     SINDEX,TARG_SCRATCH,A;
-       mov     SCSIRATE,SINDIR;
-
+       mvi     MSG_OUT, MSG_IDENTIFYFLAG;
+       or      SEQ_FLAGS, IDENTIFY_SEEN;
 
 /*
- * Main loop for information transfer phases.  If BSY is false, then
- * we have a bus free condition, expected or not.  Otherwise, wait
- * for the target to assert REQ before checking MSG, C/D and I/O
- * for the bus phase.
- *
+ * Main loop for information transfer phases.  Wait for the target
+ * to assert REQ before checking MSG, C/D and I/O for the bus phase.
  */
 ITloop:
-       test    SSTAT1,REQINIT          jz ITloop;
-       test    SSTAT1, SCSIPERR        jnz ITloop;
+       call    phase_lock;
 
-       and     A,PHASE_MASK,SCSISIGI;
-       mov     LASTPHASE,A;
-       mov     SCSISIGO,A;
+       mov     A, LASTPHASE;
 
-       cmp     ALLZEROS,A      je p_dataout;
-       cmp     A,P_DATAIN      je p_datain;
+       test    A, ~P_DATAIN    jz p_data;
        cmp     A,P_COMMAND     je p_command;
        cmp     A,P_MESGOUT     je p_mesgout;
        cmp     A,P_STATUS      je p_status;
@@ -329,25 +364,27 @@ await_busfree:
        and     SIMODE1, ~ENBUSFREE;
        call    clear_target_state;
        mov     NONE, SCSIDATL;         /* Ack the last byte */
+       and     SXFRCTL0, ~SPIOEN;
        test    SSTAT1,REQINIT|BUSFREE  jz .;
        test    SSTAT1, BUSFREE jnz poll_for_work;
        mvi     INTSTAT, BAD_PHASE;
        
 clear_target_state:
-       clr     DFCNTRL;
+       clr     DFCNTRL;                /*
+                                        * We assume that the kernel driver
+                                        * may reset us at any time, even
+                                        * in the middle of a DMA, so clear
+                                        * DFCNTRL too.
+                                        */
        clr     SCSIRATE;               /*
                                         * We don't know the target we will
                                         * connect to, so default to narrow
                                         * transfers to avoid parity problems.
                                         */
-       and     SXFRCTL0, ~FAST20;      
+       and     SXFRCTL0, ~(FAST20);
        mvi     LASTPHASE, P_BUSFREE;
        /* clear target specific flags */
-       and     SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
-
-p_dataout:
-       mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
-       jmp     data_phase_init;
+       and     SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret;
 
 /*
  * If we re-enter the data phase after going through another phase, the
@@ -358,9 +395,10 @@ data_phase_reinit:
        mvi     SCB_RESID_DCNT  call bcopy_3;
        jmp     data_phase_loop;
 
-p_datain:
+p_data:
        mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
-data_phase_init:
+       test    LASTPHASE, IOI jnz . + 2;
+       or      DMAPARAMS, DIRECTION;
        call    assert;                 /*
                                         * Ensure entering a data
                                         * phase is okay - seen identify, etc.
@@ -398,6 +436,7 @@ data_phase_loop:
        mvi     HCNT[1], 0xff;
        mvi     HCNT[2], 0xff;
        call    set_stcnt_from_hcnt;
+       and     DMAPARAMS, ~(HDMAEN|SDMAEN);
 
 data_phase_inbounds:
 /* If we are the last SG block, ensure wideodd is off. */
@@ -512,54 +551,85 @@ p_status:
        jmp     ITloop;
 
 /*
- * Message out phase.  If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
+ * Message out phase.  If MSG_OUT is 0x80, build I full indentify message
+ * sequence and send it to the target.  In addition, if the MK_MESSAGE bit
+ * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
+ * it's own message.
+ * 
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the hsot to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
  */
 p_mesgout:
-       test    MSG_LEN, 0xff   jnz  p_mesgout_start;
-       mvi     MSG_NOOP        call mk_mesg;   /* build NOP message */
-p_mesgout_start:
+       mov     SINDEX, MSG_OUT;
+       cmp     SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+p_mesgout_identify:
+.if ( WIDE )
+       and     SINDEX,0xf,SCB_TCL;     /* lun */
+.else
+       and     SINDEX,0x7,SCB_TCL;     /* lun */
+.endif
+       and     A,DISCENB,SCB_CONTROL;  /* mask off disconnect privledge */
+       or      SINDEX,A;               /* or in disconnect privledge */
+       or      SINDEX,MSG_IDENTIFYFLAG;
+p_mesgout_mk_message:
+       test    SCB_CONTROL,MK_MESSAGE  jz p_mesgout_tag;
+       mov     SCSIDATL, SINDEX;       /* Send the last byte */
+       jmp     p_mesgout_from_host + 1;/* Skip HOST_MSG test */
 /*
- * Set up automatic PIO transfer from MSG_OUT.  Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
  */
-       mvi     SINDEX,MSG_OUT;
-       mov     DINDEX,MSG_LEN;
-
+p_mesgout_tag:
+       test    SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
+       mov     SCSIDATL, SINDEX;       /* Send the identify message */
+       call    phase_lock;
+       cmp     LASTPHASE, P_MESGOUT    jne p_mesgout_done;
+       and     SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+       call    phase_lock;
+       cmp     LASTPHASE, P_MESGOUT    jne p_mesgout_done;
+       mov     SCB_TAG jmp p_mesgout_onebyte;
 /*
- * When target asks for a byte, drop ATN if it's the last one in
- * the message.  Otherwise, keep going until the message is exhausted.
- * ATN must be dropped *at least* 90ns before we ack the last byte, so
- * the code is aranged to execute two instructions before the byte is
- * transferred to give a good margin of safety
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
+ * Interrupt the driver, and allow it to send a message
+ * if it asks.
  */
-p_mesgout_loop:
-       test    SSTAT1, REQINIT         jz p_mesgout_loop;
-       test    SSTAT1, SCSIPERR        jnz p_mesgout_loop;
-       and     LASTPHASE, PHASE_MASK, SCSISIGI;
-       cmp     LASTPHASE, P_MESGOUT jne p_mesgout_done;
-p_mesgout_testretry:
-       test    DINDEX,0xff     jnz p_mesgout_dropatn;
-       or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
-       jmp     p_mesgout_start;
+p_mesgout_from_host:
+       cmp     SINDEX, HOST_MSG        jne p_mesgout_onebyte;
+       mvi     INTSTAT,AWAITING_MSG;
+       /*
+        * Did the host detect a phase change?
+        */
+       cmp     RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
+
+p_mesgout_onebyte:
+       mvi     CLRSINT1, CLRATNO;
+       mov     SCSIDATL, SINDEX;
+
 /*
  * If the next bus phase after ATN drops is a message out, it means
  * that the target is requesting that the last message(s) be resent.
  */
-p_mesgout_dropatn:
-       cmp     DINDEX,1        jne p_mesgout_outb;     /* last byte? */
-       mvi     CLRSINT1,CLRATNO;                       /* drop ATN */
-p_mesgout_outb:
-       dec     DINDEX;
-       mov     SCSIDATL,SINDIR;
-       jmp     p_mesgout_loop;
+       call    phase_lock;
+       cmp     LASTPHASE, P_MESGOUT    jne p_mesgout_done;
+       or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+       jmp     p_mesgout;
 
 p_mesgout_done:
        mvi     CLRSINT1,CLRATNO;       /* Be sure to turn ATNO off */
-       clr     MSG_LEN;                /* no active msg */
+       mov     LAST_MSG, MSG_OUT;
+       cmp     MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
+       and     SCB_CONTROL, ~MK_MESSAGE;
+       mvi     MSG_OUT, MSG_NOOP;      /* No message left */
        jmp     ITloop;
 
 /*
@@ -567,7 +637,6 @@ p_mesgout_done:
  */
 p_mesgin:
        mvi     ACCUM           call inb_first; /* read the 1st message byte */
-       mov     REJBYTE,A;                      /* save it for the driver */
 
        test    A,MSG_IDENTIFYFLAG      jnz mesgin_identify;
        cmp     A,MSG_DISCONNECT        je mesgin_disconnect;
@@ -597,8 +666,8 @@ mesgin_complete:
 /*
  * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
  * and trigger a completion interrupt.  Before doing so, check to see if there
- * is a residual or the status byte is something other than NO_ERROR (0).  In
- * either of these conditions, we upload the SCB back to the host so it can
+ * is a residual or the status byte is something other than STATUS_GOOD (0).
+ * In either of these conditions, we upload the SCB back to the host so it can
  * process this information.  In the case of a non zero status byte, we 
  * additionally interrupt the kernel driver synchronously, allowing it to
  * decide if sense should be retrieved.  If the kernel driver wishes to request
@@ -616,60 +685,17 @@ mesgin_complete:
  * First check for residuals
  */
        test    SCB_RESID_SGCNT,0xff    jnz upload_scb;
-       test    SCB_TARGET_STATUS,0xff  jz status_ok;   /* Good Status? */
+       test    SCB_TARGET_STATUS,0xff  jz complete;    /* Good Status? */
 upload_scb:
        mvi     DMAPARAMS, FIFORESET;
        mov     SCB_TAG         call dma_scb;
 check_status:
-       test    SCB_TARGET_STATUS,0xff  jz status_ok;   /* Just a residual? */
+       test    SCB_TARGET_STATUS,0xff  jz complete;    /* Just a residual? */
        mvi     INTSTAT,BAD_STATUS;                     /* let driver know */
-       cmp     RETURN_1, SEND_SENSE    jne status_ok;
+       cmp     RETURN_1, SEND_SENSE    jne complete;
        /* This SCB becomes the next to execute as it will retrieve sense */
-       mov     SCB_LINKED_NEXT, SCB_TAG;
-       jmp     dma_next_scb;
-
-status_ok:
-/* First, mark this target as free. */
-       test    SCB_CONTROL,TAG_ENB jnz complete;       /*
-                                                        * Tagged commands
-                                                        * don't busy the
-                                                        * target.
-                                                        */
-       mov     SAVED_SCBPTR, SCBPTR;
-       mov     SAVED_LINKPTR, SCB_LINKED_NEXT;
-       mov     SCB_TCL call index_untagged_scb;
-       mov     DINDIR, SAVED_LINKPTR;
-       mov     SCBPTR, SAVED_SCBPTR;
-
-complete:
-       /* Post the SCB and issue an interrupt */
-.if ( SCB_PAGING )
-       /*
-        * Spin loop until there is space
-        * in the QOUTFIFO.
-        */
-       mov     A, FIFODEPTH;
-       cmp     CMDOUTCNT, A    je .;
-       inc     CMDOUTCNT;
-.endif
-       mov     QOUTFIFO,SCB_TAG;
-       mvi     INTSTAT,CMDCMPLT;
-       test    SCB_CONTROL, ABORT_SCB jz dma_next_scb;
-       mvi     INTSTAT, ABORT_CMDCMPLT;
-
-dma_next_scb:
-       cmp     SCB_LINKED_NEXT, SCB_LIST_NULL  je add_to_free_list;
-.if !( SCB_PAGING )
-       /* Only DMA on top of ourselves if we are the SCB to download */
-       mov     A, SCB_LINKED_NEXT;
-       cmp     SCB_TAG, A      je dma_next_scb2;
-       call    add_scb_to_free_list;
-       mov     SCBPTR, A;
-       jmp     add_to_waiting_list;
-.endif
-dma_next_scb2:
        mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     SCB_LINKED_NEXT         call dma_scb;
+       mov     SCB_TAG         call dma_scb;
 add_to_waiting_list:
        mov     SCB_NEXT,WAITING_SCBH;
        mov     WAITING_SCBH, SCBPTR;
@@ -679,6 +705,28 @@ add_to_waiting_list:
         */
        call    start_selection;
        jmp     await_busfree;
+
+complete:
+       /* If we are untagged, clear our address up in host ram */
+       test    SCB_CONTROL, TAG_ENB jnz complete_post;
+       mov     A, SAVED_TCL;
+       mvi     UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+       mvi     DFCNTRL, FIFORESET;
+       mvi     DFDAT, SCB_LIST_NULL;
+       or      DFCNTRL, HDMAEN|FIFOFLUSH;
+       call    dma_finish;
+
+complete_post:
+       /* Post the SCB and issue an interrupt */
+       mov     A, QOUTPOS;
+       mvi     QOUTFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+       mvi     DFCNTRL, FIFORESET;
+       mov     DFDAT, SCB_TAG;
+       or      DFCNTRL, HDMAEN|FIFOFLUSH;
+       call    dma_finish;
+       inc     QOUTPOS;
+       mvi     INTSTAT,CMDCMPLT;
+
 add_to_free_list:
        call    add_scb_to_free_list;
        jmp     await_busfree;
@@ -690,22 +738,8 @@ add_to_free_list:
  * or simply to do nothing.
  */
 mesgin_extended:
-       mvi     MSGIN_EXT_LEN    call inb_next;
-       mov     A, MSGIN_EXT_LEN;
-mesgin_extended_loop:
-       mov     DINDEX  call    inb_next;
-       dec     A;
-       cmp     DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
-       dec     DINDEX;         /* dump by repeatedly filling the last byte */
-mesgin_extended_loop_test:
-       test    A, 0xFF         jnz mesgin_extended_loop;
-mesgin_extended_intr:
        mvi     INTSTAT,EXTENDED_MSG;           /* let driver know */
-       cmp     RETURN_1,SEND_REJ je rej_mesgin;
-       cmp     RETURN_1,SEND_MSG jne mesgin_done;
-/* The kernel has setup a message to be sent */
-       or      SCSISIGO,ATNO,LASTPHASE;        /* turn on ATNO */
-       jmp     mesgin_done;
+       jmp     ITloop;
 
 /*
  * Is it a disconnect message?  Set a flag in the SCB to remind us
@@ -713,9 +747,7 @@ mesgin_extended_intr:
  */
 mesgin_disconnect:
        or      SCB_CONTROL,DISCONNECTED;
-.if ( SCB_PAGING )
        call    add_scb_to_disc_list;
-.endif
        jmp     await_busfree;
 
 /*
@@ -764,24 +796,30 @@ mesgin_rdptrs:
  * clearing the "disconnected" bit so we don't "find" it by accident later.
  */
 mesgin_identify:
-       test    A,0x78  jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/
+.if ( WIDE )
+       and     A,0x0f;                 /* lun in lower four bits */
+.else
        and     A,0x07;                 /* lun in lower three bits */
+.endif
        or      SAVED_TCL,A;            /* SAVED_TCL should be complete now */
-       mov     SAVED_TCL call index_untagged_scb;
-       mov     ARG_1, SINDIR;
+
+       call    get_untagged_SCBID;
+       cmp     ARG_1, SCB_LIST_NULL    je snoop_tag;
 .if ( SCB_PAGING )
-       cmp     ARG_1,SCB_LIST_NULL     jne use_findSCB;
-.else
-       cmp     ARG_1,SCB_LIST_NULL     je snoop_tag;
-       /* Directly index the SCB */
-       mov     SCBPTR,ARG_1;
-       test    SCB_CONTROL,DISCONNECTED jz not_found;
-       jmp     setup_SCB;
+       test    SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
 .endif
+       /*
+        * If the SCB was found in the disconnected list (as is
+        * always the case in non-paging scenarios), SCBPTR is already
+        * set to the correct SCB.  So, simply setup the SCB and get
+        * on with things.
+        */
+       mov     SCBPTR  call rem_scb_from_disc_list;
+       jmp     setup_SCB;
 /*
  * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
  * If we get one, we use the tag returned to find the proper
- * SCB.  With SCB paging, this requires using findSCB for both tagged
+ * SCB.  With SCB paging, this requires using search for both tagged
  * and non-tagged transactions since the SCB may exist in any slot.
  * If we're not using SCB paging, we can use the tag as the direct
  * index to the SCB.
@@ -789,44 +827,42 @@ mesgin_identify:
 snoop_tag:
        mov     NONE,SCSIDATL;          /* ACK Identify MSG */
 snoop_tag_loop:
-       test    SSTAT1,REQINIT          jz snoop_tag_loop;
-       test    SSTAT1, SCSIPERR        jnz snoop_tag_loop;
-       and     LASTPHASE, PHASE_MASK, SCSISIGI;
+       call    phase_lock;
        cmp     LASTPHASE, P_MESGIN     jne not_found;
        cmp     SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
 get_tag:
-       or      SEQ_FLAGS, TAGGED_SCB;
        mvi     ARG_1   call inb_next;  /* tag value */
-/*
- * See if the tag is in range.  The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incomming tag and there is
- * no carry.
- */
-       mov     A,COMP_SCBCOUNT;
-       add     SINDEX,A,ARG_1;
-       jc      not_found;
 
 .if ! ( SCB_PAGING )
 index_by_tag:
        mov     SCBPTR,ARG_1;
-       mov     A, SAVED_TCL;
-       cmp     SCB_TCL,A               jne not_found;
        test    SCB_CONTROL,TAG_ENB     jz  not_found;
-       test    SCB_CONTROL,DISCONNECTED jz not_found;
+       mov     SCBPTR  call rem_scb_from_disc_list;
 .else
 /*
  * Ensure that the SCB the tag points to is for an SCB transaction
  * to the reconnecting target.
  */
-use_findSCB:
-       mov     ALLZEROS        call findSCB;     /* Have to search */
-       cmp     SINDEX, SCB_LIST_NULL   je not_found;
+use_retrieveSCB:
+       call    retrieveSCB;
 .endif
 setup_SCB:
+       mov     A, SAVED_TCL;
+       cmp     SCB_TCL, A      jne not_found_cleanup_scb;
+       test    SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
        and     SCB_CONTROL,~DISCONNECTED;
        or      SEQ_FLAGS,IDENTIFY_SEEN;          /* make note of IDENTIFY */
+       /* See if the host wants to send a message upon reconnection */
+       test    SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+       and     SCB_CONTROL, ~MK_MESSAGE;
+       mvi     HOST_MSG        call mk_mesg;
        jmp     mesgin_done;
 
+not_found_cleanup_scb:
+       test    SCB_CONTROL, DISCONNECTED jz . + 3;
+       call    add_scb_to_disc_list;
+       jmp     not_found;
+       call    add_scb_to_free_list;
 not_found:
        mvi     INTSTAT, NO_MATCH;
        mvi     MSG_BUS_DEV_RESET       call mk_mesg;
@@ -851,23 +887,8 @@ mesgin_reject:
  * if there is no active message already.  SINDEX is returned intact.
  */
 mk_mesg:
-       mvi     SEQCTL, PAUSEDIS|FASTMODE;
-       test    MSG_LEN,0xff    jz mk_mesg1;    /* Should always succeed */
-       
-       /*
-        * Hmmm.  For some reason the mesg buffer is in use.
-        * Tell the driver.  It should look at SINDEX to find
-        * out what we wanted to use the buffer for and resolve
-        * the conflict.
-        */
-       mvi     SEQCTL,FASTMODE;
-       mvi     INTSTAT,MSG_BUFFER_BUSY;
-
-mk_mesg1:
        or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
-       mvi     MSG_LEN,1;              /* length = 1 */
-       mov     MSG_OUT,SINDEX;         /* 1-byte message */
-       mvi     SEQCTL,FASTMODE ret;
+       mov     MSG_OUT,SINDEX ret;
 
 /*
  * Functions to read data in Automatic PIO mode.
@@ -903,6 +924,17 @@ inb_first:
 inb_last:
        mov     NONE,SCSIDATL ret;              /*dummy read from latch to ACK*/
 
+.if ( TARGET_MODE )
+/*
+ * Send a byte to an initiator in Automatic PIO mode.
+ * SPIOEN must be on prior to calling this routine.
+ */
+target_outb:
+       mov     SCSIDATL, SINDEX;
+       test    SSTAT0, SPIORDY jz .;
+       ret;
+.endif
+       
 mesgin_phasemis:
 /*
  * We expected to receive another byte, but the target changed phase
@@ -957,60 +989,114 @@ return:
  * message.
  */
 assert:
-       test    SEQ_FLAGS,RESELECTED    jz return;      /* reselected? */
        test    SEQ_FLAGS,IDENTIFY_SEEN jnz return;     /* seen IDENTIFY? */
 
        mvi     INTSTAT,NO_IDENT        ret;    /* no - tell the kernel */
 
-.if ( SCB_PAGING )
 /*
  * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
- * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
- * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
- * otherwise, SCBPTR is set to the proper SCB.
+ * or by the SCBID ARG_1.  The search begins at the SCB index passed in
+ * via SINDEX which is an SCB that must be on the disconnected list.  If
+ * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
+ * is set to the proper SCB.
  */
 findSCB:
-       mov     SCBPTR,SINDEX;                  /* switch to next SCB */
+       mov     SCBPTR,SINDEX;                  /* Initialize SCBPTR */
+       cmp     ARG_1, SCB_LIST_NULL    jne findSCB_by_SCBID;
+       mov     A, SAVED_TCL;
+       mvi     SCB_TCL jmp findSCB_loop;       /* &SCB_TCL -> SINDEX */
+findSCB_by_SCBID:
        mov     A, ARG_1;                       /* Tag passed in ARG_1 */
-       cmp     SCB_TAG,A       jne findSCB_loop;
-       test    SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
+       mvi     SCB_TAG jmp findSCB_loop;       /* &SCB_TAG -> SINDEX */
+findSCB_next:
+       cmp     SCB_NEXT, SCB_LIST_NULL je notFound;
+       mov     SCBPTR,SCB_NEXT;
+       dec     SINDEX;         /* Last comparison moved us too far */
 findSCB_loop:
-       inc     SINDEX;
-       mov     A,SCBCOUNT;
-       cmp     SINDEX,A        jne findSCB;
+       cmp     SINDIR, A       jne findSCB_next;
+       mov     SINDEX, SCBPTR  ret;
+notFound:
+       mvi     SINDEX, SCB_LIST_NULL   ret;
+
 /*
- * We didn't find it.  If we're paging, pull an SCB and DMA down the
- * one we want.  If we aren't paging or the SCB we dma down has the
- * abort flag set, return not found.
+ * Retrieve an SCB by SCBID first searching the disconnected list falling
+ * back to DMA'ing the SCB down from the host.  This routine assumes that
+ * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
+ * disconnected list to start the search from.  If SINDEX is SCB_LIST_NULL,
+ * we go directly to the host for the SCB.
+ */
+retrieveSCB:
+       test    SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host;
+       mov     SCBPTR  call findSCB;   /* Continue the search */
+       cmp     SINDEX, SCB_LIST_NULL   je retrieve_from_host;
+
+/*
+ * This routine expects SINDEX to contain the index of the SCB to be
+ * removed and SCBPTR to be pointing to that SCB.
  */
-       mov     ALLZEROS        call    get_free_or_disc_scb;
-       mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     ARG_1   call dma_scb;
-       test    SCB_RESID_SGCNT, 0xff jz . + 2;
-       or      SCB_CONTROL, MUST_DMAUP_SCB;
-       test    SCB_CONTROL, ABORT_SCB jz return;
-find_error:
-       mvi     SINDEX, SCB_LIST_NULL ret;
-foundSCB:
-       test    SCB_CONTROL, ABORT_SCB jnz find_error;
 rem_scb_from_disc_list:
 /* Remove this SCB from the disconnection list */
        cmp     SCB_NEXT,SCB_LIST_NULL je unlink_prev;
-       mov     SAVED_LINKPTR, SCB_PREV;
+       mov     DINDEX, SCB_PREV;
        mov     SCBPTR, SCB_NEXT;
-       mov     SCB_PREV, SAVED_LINKPTR;
+       mov     SCB_PREV, DINDEX;
        mov     SCBPTR, SINDEX;
 unlink_prev:
        cmp     SCB_PREV,SCB_LIST_NULL  je rHead;/* At the head of the list */
-       mov     SAVED_LINKPTR, SCB_NEXT;
+       mov     DINDEX, SCB_NEXT;
        mov     SCBPTR, SCB_PREV;
-       mov     SCB_NEXT, SAVED_LINKPTR;
+       mov     SCB_NEXT, DINDEX;
        mov     SCBPTR, SINDEX ret;
 rHead:
        mov     DISCONNECTED_SCBH,SCB_NEXT ret;
-.else
-       ret;
-.endif
+
+retrieve_from_host:
+/*
+ * We didn't find it.  Pull an SCB and DMA down the one we want.
+ * We should never get here in the non-paging case.
+ */
+       mov     ALLZEROS        call    get_free_or_disc_scb;
+       mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+       /* Jump instead of call as we want to return anyway */
+       mov     ARG_1   jmp dma_scb;
+
+/*
+ * Determine whether a target is using tagged or non-tagged transactions
+ * by first looking for a matching transaction based on the TCL and if
+ * that fails, looking up this device in the host's untagged SCB array.
+ * The TCL to search for is assumed to be in SAVED_TCL.  The value is
+ * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
+ * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
+ * in an SCB instead of having to go to the host.
+ */
+get_untagged_SCBID:
+       cmp     DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
+       mvi     ARG_1, SCB_LIST_NULL;
+       mov     DISCONNECTED_SCBH call findSCB;
+       cmp     SINDEX, SCB_LIST_NULL   je get_SCBID_from_host;
+       or      SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
+       test    SCB_CONTROL, TAG_ENB    jnz . + 2;
+       mov     ARG_1, SCB_TAG  ret;
+       mvi     ARG_1, SCB_LIST_NULL ret;
+
+set_SCBID_host_addr_and_cnt:
+       mov     DINDEX, SINDEX;
+       mvi     SCBID_ADDR call set_1byte_haddr_and_clrcnt;
+       mvi     HCNT[0], 1 ret;
+
+get_SCBID_from_host:
+       mov     A, SAVED_TCL;
+       mvi     UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+       mvi     DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+       call    dma_finish;
+       mov     ARG_1, DFDAT ret;
+
+phase_lock:     
+       test    SSTAT1, REQINIT jz phase_lock;
+       test    SSTAT1, SCSIPERR jnz phase_lock;
+       and     LASTPHASE, PHASE_MASK, SCSISIGI;
+       mov     SCSISIGO, LASTPHASE ret;
 
 set_stcnt_from_hcnt:
        mov     STCNT[0], HCNT[0];
@@ -1029,23 +1115,32 @@ bcopy_3:
        mov     DINDIR, SINDIR;
        mov     DINDIR, SINDIR ret;
 
+/*
+ * Setup haddr and count assuming that A is an
+ * index into an array of 32byte objects.
+ */
+set_32byte_haddr_and_clrcnt:
+       shr     DINDEX, 3, A;
+       shl     A, 5;
+set_1byte_haddr_and_clrcnt:    /* DINDEX must be 0 upon call */
+       add     HADDR[0], A, SINDIR;
+       mov     A, DINDEX;
+       adc     HADDR[1], A, SINDIR;
+       clr     A;
+       adc     HADDR[2], A, SINDIR;
+       adc     HADDR[3], A, SINDIR;
+       /* Clear Count */
+       clr     HCNT[1];
+       clr     HCNT[2] ret;
+
 dma_scb:
        /*
         * SCB index is in SINDEX.  Determine the physical address in
         * the host where this SCB is located and load HADDR with it.
         */
-       shr     DINDEX, 3, SINDEX;
-       shl     A, 5, SINDEX;
-       add     HADDR[0], A, HSCB_ADDR[0];
-       mov     A, DINDEX;
-       adc     HADDR[1], A, HSCB_ADDR[1];
-       clr     A;
-       adc     HADDR[2], A, HSCB_ADDR[2];
-       adc     HADDR[3], A, HSCB_ADDR[3];
-       /* Setup Count */
+       mov     A, SINDEX;
+       mvi     HSCB_ADDR call set_32byte_haddr_and_clrcnt;
        mvi     HCNT[0], 28;
-       clr     HCNT[1];
-       clr     HCNT[2];
        mov     DFCNTRL, DMAPARAMS;
        test    DMAPARAMS, DIRECTION    jnz dma_scb_fromhost;
        /* Fill it with the SCB data */
@@ -1092,25 +1187,12 @@ dma_finish:
        test    DFCNTRL, HDMAEN jnz .;
        ret;
 
-index_untagged_scb:
-       mov     DINDEX, SINDEX;
-       shr     DINDEX, 4;
-       and     DINDEX, 0x03;                   /* Bottom two bits of tid */
-       add     DINDEX, SCB_BUSYTARGETS;
-       shr     A, 6, SINDEX;                   /* Target ID divided by 4 */
-       test    SINDEX, SELBUSB jz index_untagged_scb2;
-       add     A, 2;                           /* Add 2 positions */
-index_untagged_scb2:
-       mov     SCBPTR, A;                      /*
-                                                * Select the SCB with this 
-                                                * target's information.
-                                                */
-       mov     SINDEX, DINDEX  ret;
-
 add_scb_to_free_list:
+.if ( SCB_PAGING )
        mov     SCB_NEXT, FREE_SCBH;
-       mvi     SCB_TAG, SCB_LIST_NULL;
-       mov     FREE_SCBH, SCBPTR ret;
+       mov     FREE_SCBH, SCBPTR;
+.endif
+       mvi     SCB_TAG, SCB_LIST_NULL ret;
 
 .if ( SCB_PAGING )
 get_free_or_disc_scb:
@@ -1120,16 +1202,6 @@ return_error:
        mvi     SINDEX, SCB_LIST_NULL   ret;
 dequeue_disc_scb:
        mov     SCBPTR, DISCONNECTED_SCBH;
-/*
- * If we have a residual, then we are in the middle of some I/O
- * and we have to send this SCB back up to the kernel so that the
- * saved data pointers and residual information isn't lost.
- */
-       test    SCB_CONTROL, MUST_DMAUP_SCB jz . + 3;
-       and     SCB_CONTROL, ~MUST_DMAUP_SCB;
-       jmp     dma_up_scb;
-       test    SCB_RESID_SGCNT,0xff    jnz dma_up_scb;
-       cmp     SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
 dma_up_scb:
        mvi     DMAPARAMS, FIFORESET;
        mov     SCB_TAG         call dma_scb;
@@ -1139,6 +1211,7 @@ unlink_disc_scb:
 dequeue_free_scb:
        mov     SCBPTR, FREE_SCBH;
        mov     FREE_SCBH, SCB_NEXT ret;
+.endif
 
 add_scb_to_disc_list:
 /*
@@ -1153,4 +1226,3 @@ add_scb_to_disc_list:
        mov     SCBPTR,SCB_NEXT;
        mov     SCB_PREV,DISCONNECTED_SCBH;
        mov     SCBPTR,DISCONNECTED_SCBH ret;
-.endif
index 267a01591636d83aa7d3c00552561643603c73cc..16c40138893204060a9e32e784639357f70e80af 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * SCSI messages definitions.
- */
-
 /* Messages (1 byte) */                     /* I/T (M)andatory or (O)ptional */
 #define MSG_CMDCOMPLETE                0x00 /* M/M */
 #define MSG_EXTENDED           0x01 /* O/O */
@@ -30,6 +26,7 @@
 
 /* Identify message */              /* M/M */  
 #define MSG_IDENTIFYFLAG       0x80 
+#define MSG_IDENTIFY_DISCFLAG  0x40 
 #define MSG_IDENTIFY(lun, disc)        (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
 #define MSG_ISIDENTIFY(m)      ((m) & MSG_IDENTIFYFLAG)
 
@@ -39,3 +36,6 @@
 
 #define MSG_EXT_WDTR           0x03
 #define MSG_EXT_WDTR_LEN       0x02
+#define MSG_EXT_WDTR_BUS_8_BIT 0x00
+#define MSG_EXT_WDTR_BUS_16_BIT        0x01
+#define MSG_EXT_WDTR_BUS_32_BIT        0x02 
index 7112c2e3310fe5bc6145e9aa5479753e0aebacfd..875283fc8dbcbfdad99120378d5f4a24039b4175 100644 (file)
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *      $Id: sequencer.h,v 1.2 1997/06/27 19:38:52 gibbs Exp $
+ *      $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $
  */
 
-#if defined(__KERNEL__)
-typedef unsigned char u_int8_t;
-#endif
-
 struct ins_format1 {
-       u_int8_t immediate;
-       u_int8_t source;
-       u_int8_t destination;
-       u_int8_t opcode_ret;
+       unsigned char immediate;
+       unsigned char source;
+       unsigned char destination;
+       unsigned char opcode_ret;
+#define DOWNLOAD_CONST_IMMEDIATE 0x80
 };
 
 struct ins_format2 {
-       u_int8_t shift_control;
-       u_int8_t source;
-       u_int8_t destination;
-       u_int8_t opcode_ret;
+       unsigned char shift_control;
+       unsigned char source;
+       unsigned char destination;
+       unsigned char opcode_ret;
 #define RETURN_BIT 0x01
 };
 
 struct ins_format3 {
-       u_int8_t immediate;
-       u_int8_t source;
-       u_int8_t address;
-       u_int8_t opcode_addr;
+       unsigned char immediate;
+       unsigned char source;
+       unsigned char address;
+       unsigned char opcode_addr;
 #define ADDR_HIGH_BIT 0x01
 };
 
+#ifndef __KERNEL__
 struct instruction {
        union {
                struct ins_format1 format1;
                struct ins_format2 format2;
                struct ins_format3 format3;
-               u_int8_t           bytes[4];
+               unsigned char      bytes[4];
        } format;
        u_int   srcline;
        struct symbol *patch_label;
-       struct {
-               struct instruction *stqe_next; /* next element */
-       } links;
+       STAILQ_ENTRY(instruction) links;
 };
+#endif
 
 #define        AIC_OP_OR       0x0
 #define        AIC_OP_AND      0x1
index fe5f624616456750533205836ca838a538b3a9a5..c923cecec2fb942171b988267496de420cf406e1 100644 (file)
@@ -53,9 +53,6 @@ proc_debug(const char *fmt, ...)
 
 static int aic7xxx_buffer_size = 0;
 static char *aic7xxx_buffer = NULL;
-static const char *bus_names[] = { "Single", "Twin", "Wide" };
-static const char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
-   "AIC-787x", "AIC-788x" };
 
 
 /*+F*************************************************************************
@@ -87,13 +84,14 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
   int    size = 0;
+  unsigned char i;
 #ifdef AIC7XXX_PROC_STATS
   struct aic7xxx_xferstats *sp;
   unsigned char target, lun;
-  int i;
 #endif
 
   HBAptr = NULL;
+
   for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
     ;
 
@@ -109,6 +107,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
       return (length);
     }
   }
+
   HBAptr = p->host;
 
   if (inout == TRUE) /* Has data been written to the file? */ 
@@ -124,16 +123,20 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
    * if proc_stats is defined, then we sweep the stats structure to see
    * how many drives we will be printing out for and add 384 bytes per
    * device with active stats.
+   *
+   * Hmmmm...that 1.5k seems to keep growing as items get added so they
+   * can be easily viewed for debugging purposes.  So, we bumped that
+   * 1.5k to 4k so we can quit having to bump it all the time.
    */
 
-  size = 1536;
+  size = 4096;
 #ifdef AIC7XXX_PROC_STATS
   for (target = 0; target < MAX_TARGETS; target++)
   {
     for (lun = 0; lun < MAX_LUNS; lun++)
     {
       if (p->stats[target][lun].xfers != 0)
-        size += 384;
+        size += 512;
     }
   }
 #endif
@@ -156,29 +159,20 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
 
   size = 0;
   size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
-  size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
-  size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
-#if 0
-  size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
-#endif
+  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Compile Options:\n");
 #ifdef AIC7XXX_RESET_DELAY
   size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
 #endif
-#ifdef AIC7XXX_CMDS_PER_LUN
-  size += sprintf(BLS, "  AIC7XXX_CMDS_PER_LUN   : %d\n", AIC7XXX_CMDS_PER_LUN);
-#endif
-#ifdef AIC7XXX_TAGGED_QUEUEING
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Disabled\n");
-#endif
-#ifdef AIC7XXX_PAGE_ENABLE
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Disabled\n");
-#endif
+  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
+  size += sprintf(BLS, "                             Check below to see "
+                       "which\n"
+                       "                             devices use tagged "
+                       "queueing\n");
+  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled (This is no longer "
+                       "an option)\n");
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
 #else
@@ -187,17 +181,54 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
   size += sprintf(BLS, "           SCSI Adapter: %s\n",
-      board_names[p->chip_type]);
-  size += sprintf(BLS, "                         (%s chipset)\n",
-      chip_names[p->chip_class]);
-  size += sprintf(BLS, "               Host Bus: %s\n", bus_names[p->bus_type]);
-  size += sprintf(BLS, "                Base IO: 0x%lx\n", p->base);
-  size += sprintf(BLS, "         Base IO Memory: 0x%lx\n", p->mbase);
+      board_names[p->board_name_index]);
+  if (p->flags & AHC_TWIN)
+    size += sprintf(BLS, "                         Twin Channel\n");
+  else
+  {
+    char *channel = "";
+    char *ultra = "";
+    char *wide = "Narrow ";
+    if (p->flags & AHC_MULTI_CHANNEL)
+    {
+      channel = " Channel A";
+      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+    }
+    if (p->type & AHC_WIDE)
+      wide = "Wide ";
+    if (p->type & AHC_ULTRA)
+      ultra = "Ultra ";
+    size += sprintf(BLS, "                           %s%sController%s\n",
+      ultra, wide, channel);
+  }
+  if( !(p->maddr) )
+  {
+    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
+  }
+  else
+  {
+    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+  }
+  if( !(p->type & AHC_AIC78x0) )
+  {
+    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
+    size += sprintf(BLS, "                         %s\n",
+            (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  }
+  else
+  {
+    size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
+            (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  }
   size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
-  size += sprintf(BLS, "                   SCBs: Used %d, HW %d, Page %d\n",
-      p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
-  size += sprintf(BLS, "             Interrupts: %d", p->isr_count);
-  if (p->chip_class == AIC_777x)
+  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
+            p->activescbs, p->max_activescbs);
+  size += sprintf(BLS, "                         Allocated %d, HW %d, "
+            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+            p->scb_data->maxscbs);
+  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
+  if (p->type & AHC_AIC7770)
   {
     size += sprintf(BLS, " %s\n",
         (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
@@ -206,16 +237,39 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   {
     size += sprintf(BLS, "\n");
   }
-  size += sprintf(BLS, "          Serial EEPROM: %s\n",
-      (p->flags & HAVE_SEEPROM) ? "True" : "False");
+  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
+            p->bios_control);
+  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
+            p->adapter_control);
   size += sprintf(BLS, "   Extended Translation: %sabled\n",
-      (p->flags & EXTENDED_TRANSLATION) ? "En" : "Dis");
+      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
   size += sprintf(BLS, "         SCSI Bus Reset: %sabled\n",
       aic7xxx_no_reset ? "Dis" : "En");
-  size += sprintf(BLS, "             Ultra SCSI: %sabled\n",
-      (p->flags & ULTRA_ENABLED) ? "En" : "Dis");
-  size += sprintf(BLS, "Disconnect Enable Flags: 0x%x\n", p->discenable);
-  
+  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+  if (p->type & AHC_ULTRA)
+  {
+    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+  }
+  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
+  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
+#ifdef AIC7XXX_CMDS_PER_LUN
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
+#else
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
+#endif
+  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
+  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
+
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Statistics:\n");
@@ -228,15 +282,15 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
       {
         continue;
       }
-      if (p->bus_type == AIC_TWIN)
+      if (p->type & AHC_TWIN)
       {
-        size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
-            'A' + (target >> 3), (target & 0x7), lun);
+        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+            p->host_no, (target >> 3), (target & 0x7), lun);
       }
       else
       {
-        size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
-            'A', target, lun);
+        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+            p->host_no, 0, target, lun);
       }
       size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n",
           sp->xfers, sp->r_total, sp->w_total);
index 855a204411ac09c97b48c236acb883f14e5f866f..a0682fd3ee6e7bb82a9efffbfdf262d6db1fadc1 100644 (file)
 #define                ACTNEGEN                0x02
 #define                STPWEN                  0x01
 
-#define        SCSISIGI                        0x03
-#define                ATNI                    0x10
-#define                SELI                    0x08
-#define                BSYI                    0x04
-#define                REQI                    0x02
-#define                ACKI                    0x01
-
 #define        SCSISIGO                        0x03
 #define                CDO                     0x80
 #define                IOO                     0x40
 #define                REQO                    0x02
 #define                ACKO                    0x01
 
+#define        SCSISIGI                        0x03
+#define                ATNI                    0x10
+#define                SELI                    0x08
+#define                BSYI                    0x04
+#define                REQI                    0x02
+#define                ACKI                    0x01
+
 #define        SCSIRATE                        0x04
 #define                WIDEXFER                0x80
 #define                SXFR                    0x70
 #define                SELID_MASK              0xf0
 #define                ONEBIT                  0x08
 
+#define        SPIOCAP                         0x1b
+#define                SOFT1                   0x80
+#define                SOFT0                   0x40
+#define                SOFTCMDEN               0x20
+#define                HAS_BRDCTL              0x10
+#define                SEEPROM                 0x08
+#define                EEPROM                  0x04
+#define                ROM                     0x02
+#define                SSPIOCPS                0x01
+
 #define        BRDCTL                          0x1d
 #define                BRDDAT7                 0x80
 #define                BRDDAT6                 0x40
 
 #define        DISC_DSB                        0x32
 
-#define        MSG_LEN                         0x34
-
-#define        MSG_OUT                         0x35
+#define        MSG_OUT                         0x34
 
-#define        DMAPARAMS                       0x3d
+#define        DMAPARAMS                       0x35
 #define                WIDEODD                 0x40
 #define                SCSIEN                  0x20
 #define                SDMAENACK               0x10
 #define                FIFOFLUSH               0x02
 #define                FIFORESET               0x01
 
-#define        SCBCOUNT                        0x3e
-
-#define        COMP_SCBCOUNT                   0x3f
-
-#define        QCNTMASK                        0x40
-
-#define        SEQ_FLAGS                       0x41
-#define                RESELECTED              0x80
-#define                IDENTIFY_SEEN           0x40
-#define                TAGGED_SCB              0x20
+#define        SEQ_FLAGS                       0x36
+#define                IDENTIFY_SEEN           0x80
+#define                SCBPTR_VALID            0x20
 #define                DPHASE                  0x10
-#define                PAGESCBS                0x04
+#define                AMTARGET                0x08
 #define                WIDE_BUS                0x02
 #define                TWIN_BUS                0x01
 
-#define        SAVED_TCL                       0x42
-
-#define        SG_COUNT                        0x43
+#define        SAVED_TCL                       0x37
 
-#define        SG_NEXT                         0x44
+#define        SG_COUNT                        0x38
 
-#define        WAITING_SCBH                    0x48
+#define        SG_NEXT                         0x39
 
-#define        SAVED_LINKPTR                   0x49
-
-#define        SAVED_SCBPTR                    0x4a
-
-#define        REJBYTE                         0x4b
-
-#define        LASTPHASE                       0x4c
+#define        LASTPHASE                       0x3d
 #define                P_MESGIN                0xe0
 #define                PHASE_MASK              0xe0
 #define                P_STATUS                0xc0
 #define                P_BUSFREE               0x01
 #define                P_DATAOUT               0x00
 
-#define        MSGIN_EXT_LEN                   0x4d
+#define        WAITING_SCBH                    0x3e
+
+#define        DISCONNECTED_SCBH               0x3f
 
-#define        MSGIN_EXT_OPCODE                0x4e
+#define        FREE_SCBH                       0x40
 
-#define        MSGIN_EXT_BYTES                 0x4f
+#define        HSCB_ADDR                       0x41
 
-#define        DISCONNECTED_SCBH               0x52
+#define        SCBID_ADDR                      0x45
 
-#define        FREE_SCBH                       0x53
+#define        TMODE_CMDADDR                   0x49
 
-#define        HSCB_ADDR                       0x54
+#define        KERNEL_QINPOS                   0x4d
 
-#define        CUR_SCBID                       0x58
+#define        QINPOS                          0x4e
 
-#define        ARG_1                           0x59
-#define        RETURN_1                        0x59
+#define        QOUTPOS                         0x4f
+
+#define        TMODE_CMDADDR_NEXT              0x50
+
+#define        ARG_1                           0x51
+#define        RETURN_1                        0x51
 #define                SEND_MSG                0x80
 #define                SEND_SENSE              0x40
 #define                SEND_REJ                0x20
+#define                MSGOUT_PHASEMIS         0x10
 
-#define        SCSICONF                        0x5a
-
-#define        CMDOUTCNT                       0x5a
+#define        LAST_MSG                        0x52
 
-#define        SCSICONF2                       0x5b
+#define        SCSICONF                        0x5a
+#define                TERM_ENB                0x80
 #define                RESET_SCSI              0x40
-
-#define        FIFODEPTH                       0x5b
+#define                HWSCSIID                0x0f
+#define                HSCSIID                 0x07
 
 #define        HOSTCONF                        0x5d
 
 #define        HA_274_BIOSCTRL                 0x5f
-#define                BIOSDISABLED            0x30
 #define                BIOSMODE                0x30
+#define                BIOSDISABLED            0x30
 #define                CHANNEL_B_PRIMARY       0x08
 
 #define        SEQCTL                          0x60
 
 #define        STACK                           0x6f
 
+#define        BCTL                            0x84
+#define                ACE                     0x08
+#define                ENABLE                  0x01
+
 #define        DSCOMMAND                       0x84
 #define                CACHETHEN               0x80
 #define                DPARCKEN                0x40
 #define                MPARCKEN                0x20
 #define                EXTREQLCK               0x10
 
-#define        BCTL                            0x84
-#define                ACE                     0x08
-#define                ENABLE                  0x01
-
 #define        BUSTIME                         0x85
 #define                BOFF                    0xf0
 #define                BON                     0x0f
 #define                SEQINT_MASK             0xf1
 #define                DATA_OVERRUN            0xe1
 #define                MSGIN_PHASEMIS          0xd1
-#define                MSG_BUFFER_BUSY         0xc1
+#define                TRACEPOINT2             0xc1
+#define                TRACEPOINT              0xb1
 #define                AWAITING_MSG            0xa1
-#define                ABORT_CMDCMPLT          0x91
 #define                RESIDUAL                0x81
 #define                BAD_STATUS              0x71
 #define                REJECT_MSG              0x61
-#define                NO_MATCH_BUSY           0x51
+#define                ABORT_REQUESTED         0x51
 #define                EXTENDED_MSG            0x41
 #define                NO_MATCH                0x31
 #define                NO_IDENT                0x21
 #define                BAD_PHASE               0x01
 #define                SEQINT                  0x01
 
-#define        ERROR                           0x92
-#define                PARERR                  0x08
-#define                ILLOPCODE               0x04
-#define                ILLSADDR                0x02
-#define                ILLHADDR                0x01
-
 #define        CLRINT                          0x92
+#define                CLRPARERR               0x10
 #define                CLRBRKADRINT            0x08
 #define                CLRSCSIINT              0x04
 #define                CLRCMDINT               0x02
 #define                CLRSEQINT               0x01
 
+#define        ERROR                           0x92
+#define                PCIERRSTAT              0x40
+#define                MPARERR                 0x20
+#define                DPARERR                 0x10
+#define                SQPARERR                0x08
+#define                ILLOPCODE               0x04
+#define                ILLSADDR                0x02
+#define                ILLHADDR                0x01
+
 #define        DFCNTRL                         0x93
 
 #define        DFSTATUS                        0x94
 
 #define        QOUTCNT                         0x9e
 
-#define        SCB_BASE                        0xa0
-
 #define        SCB_CONTROL                     0xa0
 #define                MK_MESSAGE              0x80
 #define                DISCENB                 0x40
 #define                TAG_ENB                 0x20
-#define                MUST_DMAUP_SCB          0x10
-#define                ABORT_SCB               0x08
 #define                DISCONNECTED            0x04
 #define                SCB_TAG_TYPE            0x03
 
+#define        SCB_BASE                        0xa0
+
 #define        SCB_TCL                         0xa1
 #define                TID                     0xf0
 #define                SELBUSB                 0x08
 
 #define        SCB_DATACNT                     0xb0
 
-#define        SCB_LINKED_NEXT                 0xb3
-
 #define        SCB_CMDPTR                      0xb4
 
 #define        SCB_CMDLEN                      0xb8
 #define                DI_2840                 0x01
 
 
-#define        MAX_OFFSET_16BIT        0x08
+#define        CMD_GROUP_CODE_SHIFT    0x05
 #define        BUS_8_BIT       0x00
+#define        QOUTFIFO_OFFSET 0x01
+#define        CMD_GROUP2_BYTE_DELTA   0xfa
+#define        MAX_OFFSET_8BIT 0x0f
+#define        BUS_16_BIT      0x01
+#define        QINFIFO_OFFSET  0x02
+#define        CMD_GROUP5_BYTE_DELTA   0x0b
+#define        MAX_OFFSET_16BIT        0x08
+#define        UNTAGGEDSCB_OFFSET      0x00
 #define        SCB_LIST_NULL   0xff
 #define        SG_SIZEOF       0x08
-#define        MAX_OFFSET_8BIT 0x0f
+#define        CMD_GROUP4_BYTE_DELTA   0x04
+#define        CMD_GROUP0_BYTE_DELTA   0xfc
+#define        HOST_MSG        0xff
 #define        BUS_32_BIT      0x02
-#define        BUS_16_BIT      0x01
+
+
+/* Downloaded Constant Definitions */
+#define        TMODE_NUMCMDS   0x01
+#define        QCNTMASK        0x00
index 78359fb4e90d97ee73ff87c7f654a1f5ab798980..2721f6bcde906f442eec7f3968c84288fddceaac 100644 (file)
@@ -1,54 +1,39 @@
 /*
   * DO NOT EDIT - This file is automatically generated.
   */
-static u_int8_t seqprog[] = {
+static unsigned char seqprog[] = {
        0xff, 0x6a, 0x03, 0x02,
+       0x32, 0x6a, 0x00, 0x00,
        0x12, 0x6a, 0x00, 0x00,
-       0x00, 0x65, 0x6f, 0x16,
-       0x40, 0x0b, 0x3c, 0x1a,
-       0x20, 0x0b, 0x37, 0x1a,
-       0x40, 0x00, 0x03, 0x1a,
+       0x00, 0x65, 0x92, 0x16,
+       0xf7, 0x01, 0x01, 0x02,
+       0xff, 0x4e, 0x64, 0x02,
+       0xbf, 0x60, 0x60, 0x02,
+       0x60, 0x0b, 0x37, 0x1a,
+       0x40, 0x00, 0x05, 0x1a,
        0x08, 0x1f, 0x1f, 0x04,
-       0x40, 0x0b, 0x3c, 0x1a,
-       0x20, 0x0b, 0x37, 0x1a,
-       0x40, 0x00, 0x03, 0x1a,
+       0x60, 0x0b, 0x37, 0x1a,
+       0x40, 0x00, 0x05, 0x1a,
        0x08, 0x1f, 0x1f, 0x04,
-       0xff, 0x48, 0x2c, 0x18,
-       0xff, 0x40, 0x64, 0x02,
-       0x00, 0x9c, 0x03, 0x1e,
-       0x00, 0x6a, 0xad, 0x17,
-       0xff, 0x65, 0x03, 0x1c,
-       0xff, 0x9b, 0x58, 0x02,
-       0xff, 0x58, 0x90, 0x02,
-       0x0d, 0x6a, 0x3d, 0x00,
-       0x00, 0x58, 0x77, 0x17,
-       0x28, 0xa0, 0x2a, 0x1a,
-       0x50, 0x6a, 0x60, 0x00,
-       0xff, 0x90, 0x4a, 0x02,
-       0x00, 0xa1, 0xa1, 0x17,
-       0xff, 0x6c, 0x59, 0x02,
-       0xff, 0x59, 0x27, 0x1c,
-       0xff, 0x4a, 0x90, 0x02,
-       0x00, 0x65, 0xaa, 0x17,
-       0x00, 0x6a, 0x52, 0x17,
-       0xff, 0x65, 0x1f, 0x18,
-       0x51, 0x6a, 0x91, 0x00,
-       0xff, 0x58, 0xb3, 0x02,
-       0x00, 0x65, 0xbb, 0x17,
-       0x10, 0x6a, 0x60, 0x00,
-       0x00, 0x65, 0x03, 0x10,
-       0xff, 0x59, 0x90, 0x02,
-       0xff, 0x58, 0xb3, 0x02,
-       0x10, 0x6a, 0x60, 0x00,
-       0x00, 0x65, 0x03, 0x10,
-       0xff, 0x58, 0x6d, 0x02,
-       0xff, 0x4a, 0x90, 0x02,
-       0x10, 0x6a, 0x60, 0x00,
-       0xff, 0x48, 0xba, 0x02,
-       0xff, 0x90, 0x48, 0x02,
-       0xff, 0x48, 0x90, 0x02,
-       0x00, 0x65, 0x2f, 0x16,
-       0x00, 0x65, 0x03, 0x10,
+       0xff, 0x3e, 0x1d, 0x18,
+       0x40, 0x60, 0x60, 0x00,
+       0x00, 0x4d, 0x06, 0x1c,
+       0x01, 0x4e, 0x4e, 0x06,
+       0xbf, 0x60, 0x60, 0x02,
+       0x00, 0x6a, 0xd8, 0x17,
+       0xff, 0x4e, 0x64, 0x06,
+       0x02, 0x6a, 0x93, 0x17,
+       0x0d, 0x6a, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0xff, 0x99, 0x65, 0x02,
+       0xff, 0x65, 0x90, 0x02,
+       0x0d, 0x6a, 0x35, 0x00,
+       0x00, 0x65, 0xb3, 0x17,
+       0xff, 0x3e, 0xba, 0x02,
+       0xff, 0x90, 0x3e, 0x02,
+       0xff, 0x3e, 0x90, 0x02,
+       0x00, 0x65, 0x20, 0x16,
+       0x00, 0x65, 0x05, 0x10,
        0xf7, 0x1f, 0x65, 0x02,
        0x08, 0xa1, 0x64, 0x02,
        0x00, 0x65, 0x65, 0x00,
@@ -57,316 +42,381 @@ static u_int8_t seqprog[] = {
        0x0f, 0x05, 0x05, 0x02,
        0x00, 0x05, 0x05, 0x00,
        0x5a, 0x6a, 0x00, 0x01,
-       0xff, 0x6a, 0x34, 0x02,
-       0x20, 0x6a, 0x0b, 0x00,
-       0xf0, 0x19, 0x42, 0x02,
-       0x80, 0x41, 0x41, 0x00,
-       0x00, 0x65, 0x4c, 0x10,
-       0x12, 0x6a, 0x00, 0x00,
-       0x40, 0x6a, 0x0b, 0x00,
-       0xff, 0x48, 0x90, 0x02,
-       0xff, 0xba, 0x48, 0x02,
-       0xff, 0xa1, 0x42, 0x02,
-       0x07, 0xa1, 0x35, 0x02,
-       0x40, 0xa0, 0x64, 0x02,
-       0x00, 0x35, 0x35, 0x00,
-       0x80, 0x35, 0x35, 0x00,
-       0x01, 0x6a, 0x34, 0x00,
-       0x20, 0xa0, 0x4a, 0x1e,
-       0x23, 0xa0, 0x36, 0x02,
-       0xff, 0xb9, 0x37, 0x02,
-       0x02, 0x34, 0x34, 0x06,
-       0x80, 0xa0, 0x4c, 0x1e,
-       0xa1, 0x6a, 0x91, 0x00,
-       0x08, 0x6a, 0x0c, 0x00,
-       0x08, 0x11, 0x11, 0x00,
-       0x1a, 0x01, 0x01, 0x00,
+       0x12, 0x65, 0x64, 0x00,
+       0x00, 0x01, 0x01, 0x00,
        0x31, 0x6a, 0x65, 0x00,
-       0x80, 0x42, 0x52, 0x1a,
+       0x80, 0x37, 0x2d, 0x1a,
        0xff, 0x65, 0x65, 0x06,
-       0xff, 0x42, 0x6e, 0x02,
+       0xff, 0x37, 0x6e, 0x02,
        0xff, 0x6e, 0x64, 0x02,
-       0x00, 0x6c, 0x56, 0x1e,
+       0x00, 0x6c, 0x31, 0x1e,
        0x20, 0x01, 0x01, 0x00,
-       0x4c, 0x42, 0x64, 0x0a,
-       0x08, 0x1f, 0x5a, 0x1e,
-       0x08, 0x42, 0x42, 0x00,
+       0x4c, 0x37, 0x64, 0x0a,
+       0x08, 0x1f, 0x35, 0x1e,
+       0x08, 0x37, 0x37, 0x00,
        0x08, 0x64, 0x64, 0x00,
        0x20, 0x64, 0x65, 0x06,
-       0xff, 0x6c, 0x04, 0x02,
-       0x01, 0x0c, 0x5c, 0x1e,
-       0x04, 0x0c, 0x5c, 0x1a,
-       0xe0, 0x03, 0x64, 0x02,
-       0xff, 0x64, 0x4c, 0x02,
-       0xff, 0x64, 0x03, 0x02,
-       0x00, 0x6a, 0x74, 0x1c,
-       0x40, 0x64, 0x79, 0x1c,
-       0x80, 0x64, 0xa5, 0x1c,
-       0xa0, 0x64, 0xb0, 0x1c,
-       0xc0, 0x64, 0xad, 0x1c,
-       0xe0, 0x64, 0xc3, 0x1c,
+       0xff, 0x6c, 0x04, 0x03,
+       0x40, 0x0b, 0x78, 0x1a,
+       0x80, 0x0b, 0x71, 0x1e,
+       0xa4, 0x6a, 0x03, 0x00,
+       0x40, 0x6a, 0x0b, 0x00,
+       0x10, 0x03, 0x6f, 0x1e,
+       0xff, 0x50, 0x64, 0x02,
+       0x49, 0x6a, 0xa9, 0x17,
+       0x01, 0x6a, 0x93, 0x00,
+       0xff, 0x6a, 0x65, 0x02,
+       0x08, 0x01, 0x01, 0x00,
+       0x02, 0x0b, 0x41, 0x1e,
+       0xf7, 0x01, 0x01, 0x02,
+       0xff, 0x06, 0x66, 0x02,
+       0xff, 0x66, 0x99, 0x02,
+       0x01, 0x65, 0x65, 0x06,
+       0x80, 0x66, 0x48, 0x1e,
+       0xff, 0x66, 0x51, 0x02,
+       0x10, 0x03, 0x40, 0x1a,
+       0xfc, 0x65, 0x64, 0x06,
+       0x00, 0x65, 0x4c, 0x12,
+       0xff, 0x6a, 0x99, 0x00,
+       0x01, 0x64, 0x8c, 0x06,
+       0x84, 0x6a, 0x03, 0x00,
+       0x08, 0x01, 0x01, 0x00,
+       0x02, 0x0b, 0x4f, 0x1e,
+       0xff, 0x06, 0x64, 0x02,
+       0xff, 0x64, 0x99, 0x02,
+       0xff, 0x6a, 0x65, 0x02,
+       0x5b, 0x64, 0x64, 0x0a,
+       0x00, 0x62, 0x62, 0x06,
+       0xfc, 0x65, 0x65, 0x06,
+       0xff, 0x6a, 0x6a, 0x02,
+       0xfa, 0x65, 0x65, 0x06,
+       0xff, 0x6a, 0x6a, 0x02,
+       0x04, 0x65, 0x65, 0x06,
+       0x0b, 0x65, 0x65, 0x06,
+       0xff, 0x65, 0x64, 0x02,
+       0x00, 0x8c, 0x8c, 0x06,
+       0x02, 0x0b, 0x5d, 0x1e,
+       0x01, 0x65, 0x60, 0x18,
+       0xf7, 0x01, 0x01, 0x02,
+       0xff, 0x06, 0x99, 0x02,
+       0xff, 0x65, 0x65, 0x06,
+       0xff, 0x65, 0x5d, 0x1a,
+       0x0a, 0x93, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0x40, 0x51, 0x69, 0x1e,
+       0xe4, 0x6a, 0x03, 0x00,
+       0x08, 0x01, 0x01, 0x00,
+       0x04, 0x6a, 0x5c, 0x17,
+       0x01, 0x50, 0x50, 0x06,
+       0x01, 0x50, 0x6c, 0x98,
+       0xff, 0x6a, 0x50, 0x02,
+       0xff, 0x6a, 0x9d, 0x00,
+       0x02, 0x6a, 0x91, 0x00,
+       0x40, 0x51, 0x6f, 0x1a,
+       0xff, 0x6a, 0x03, 0x02,
+       0x00, 0x65, 0x05, 0x10,
+       0x20, 0x6a, 0x0b, 0x00,
+       0xf0, 0x19, 0x37, 0x02,
+       0x08, 0x6a, 0x0c, 0x00,
+       0x08, 0x11, 0x11, 0x00,
+       0x08, 0x6a, 0x28, 0x16,
+       0x08, 0x6a, 0x34, 0x00,
+       0x00, 0x65, 0x82, 0x10,
+       0x12, 0x6a, 0x00, 0x00,
+       0x40, 0x6a, 0x0b, 0x00,
+       0xff, 0x3e, 0x90, 0x02,
+       0xff, 0xba, 0x3e, 0x02,
+       0xff, 0xa1, 0x37, 0x02,
+       0x08, 0x6a, 0x0c, 0x00,
+       0x08, 0x11, 0x11, 0x00,
+       0x08, 0x6a, 0x28, 0x16,
+       0x80, 0x6a, 0x34, 0x00,
+       0x80, 0x36, 0x36, 0x00,
+       0x00, 0x65, 0x9b, 0x17,
+       0xff, 0x3d, 0x64, 0x02,
+       0xbf, 0x64, 0x9a, 0x1e,
+       0x80, 0x64, 0xc9, 0x1c,
+       0xa0, 0x64, 0xd4, 0x1c,
+       0xc0, 0x64, 0xd1, 0x1c,
+       0xe0, 0x64, 0xf5, 0x1c,
        0x01, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x5c, 0x10,
+       0x00, 0x65, 0x82, 0x10,
        0xf7, 0x11, 0x11, 0x02,
-       0x00, 0x65, 0x6f, 0x16,
+       0x00, 0x65, 0x92, 0x16,
        0xff, 0x06, 0x6a, 0x02,
-       0x09, 0x0c, 0x6c, 0x1e,
-       0x08, 0x0c, 0x03, 0x1a,
+       0xf7, 0x01, 0x01, 0x02,
+       0x09, 0x0c, 0x8f, 0x1e,
+       0x08, 0x0c, 0x05, 0x1a,
        0x01, 0x6a, 0x91, 0x00,
        0xff, 0x6a, 0x93, 0x02,
        0xff, 0x6a, 0x04, 0x02,
        0xdf, 0x01, 0x01, 0x02,
-       0x01, 0x6a, 0x4c, 0x00,
-       0x0f, 0x41, 0x41, 0x03,
-       0x7d, 0x6a, 0x3d, 0x00,
-       0x00, 0x65, 0x7a, 0x10,
+       0x01, 0x6a, 0x3d, 0x00,
+       0x03, 0x36, 0x36, 0x03,
        0x08, 0x6a, 0x66, 0x00,
-       0xa9, 0x6a, 0x74, 0x17,
-       0x00, 0x65, 0x82, 0x10,
-       0x79, 0x6a, 0x3d, 0x00,
-       0x00, 0x65, 0x4f, 0x17,
-       0x10, 0x41, 0x76, 0x1a,
+       0xa9, 0x6a, 0xa6, 0x17,
+       0x00, 0x65, 0xa5, 0x10,
+       0x79, 0x6a, 0x35, 0x00,
+       0x40, 0x3d, 0x9d, 0x1a,
+       0x04, 0x35, 0x35, 0x00,
+       0x00, 0x65, 0x6c, 0x17,
+       0x10, 0x36, 0x97, 0x1a,
        0x88, 0x6a, 0x66, 0x00,
-       0xac, 0x6a, 0x70, 0x17,
-       0x00, 0x65, 0x6d, 0x17,
-       0xff, 0xa3, 0x43, 0x02,
-       0x44, 0x6a, 0x66, 0x00,
-       0xa4, 0x6a, 0x73, 0x17,
-       0xff, 0x43, 0x88, 0x1a,
+       0xac, 0x6a, 0xa2, 0x17,
+       0x00, 0x65, 0x9f, 0x17,
+       0xff, 0xa3, 0x38, 0x02,
+       0x39, 0x6a, 0x66, 0x00,
+       0xa4, 0x6a, 0xa5, 0x17,
+       0xff, 0x38, 0xac, 0x1a,
        0x80, 0x02, 0x02, 0x00,
        0xff, 0x6a, 0x8c, 0x00,
        0xff, 0x6a, 0x8d, 0x00,
        0xff, 0x6a, 0x8e, 0x00,
-       0x00, 0x65, 0x6d, 0x17,
-       0x01, 0x43, 0x8a, 0x18,
-       0xbf, 0x3d, 0x3d, 0x02,
-       0x00, 0x3d, 0x44, 0x17,
-       0x80, 0x02, 0xa2, 0x1a,
-       0xff, 0x65, 0x9c, 0x1e,
-       0xff, 0x43, 0x43, 0x06,
-       0xff, 0x43, 0x9c, 0x1e,
+       0x00, 0x65, 0x9f, 0x17,
+       0xe7, 0x35, 0x35, 0x02,
+       0x01, 0x38, 0xae, 0x18,
+       0xbf, 0x35, 0x35, 0x02,
+       0x00, 0x35, 0x61, 0x17,
+       0x80, 0x02, 0xc6, 0x1a,
+       0xff, 0x65, 0xc0, 0x1e,
+       0xff, 0x38, 0x38, 0x06,
+       0xff, 0x38, 0xc0, 0x1e,
        0xff, 0x6a, 0x64, 0x02,
-       0x08, 0x44, 0x44, 0x06,
-       0x00, 0x45, 0x45, 0x08,
+       0x08, 0x39, 0x39, 0x06,
+       0x00, 0x3a, 0x3a, 0x08,
        0x88, 0x6a, 0x66, 0x00,
-       0x44, 0x6a, 0x73, 0x17,
+       0x39, 0x6a, 0xa5, 0x17,
        0x08, 0x6a, 0x8c, 0x00,
        0xff, 0x6a, 0x8d, 0x02,
        0xff, 0x6a, 0x8e, 0x02,
        0x0d, 0x93, 0x93, 0x00,
-       0x00, 0x65, 0x9d, 0x17,
-       0x88, 0x6a, 0x95, 0x17,
-       0x00, 0x65, 0x6d, 0x17,
-       0x10, 0x0c, 0x82, 0x1e,
+       0x00, 0x65, 0xd1, 0x17,
+       0x88, 0x6a, 0xc9, 0x17,
+       0x00, 0x65, 0x9f, 0x17,
+       0x10, 0x0c, 0xa5, 0x1e,
        0xff, 0x08, 0xa9, 0x02,
        0xff, 0x09, 0xaa, 0x02,
        0xff, 0x0a, 0xab, 0x02,
-       0xff, 0x43, 0xa8, 0x02,
-       0x10, 0x41, 0x41, 0x00,
-       0x00, 0x65, 0x5c, 0x10,
+       0xff, 0x38, 0xa8, 0x02,
+       0x10, 0x36, 0x36, 0x00,
+       0x00, 0x65, 0x82, 0x10,
        0x7f, 0x02, 0x02, 0x02,
        0xe1, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x5c, 0x10,
-       0x00, 0x65, 0x4f, 0x17,
+       0x00, 0x65, 0x82, 0x10,
+       0x00, 0x65, 0x6c, 0x17,
        0x88, 0x6a, 0x66, 0x00,
-       0xb4, 0x6a, 0x72, 0x17,
+       0xb4, 0x6a, 0xa4, 0x17,
        0xff, 0x6a, 0x8d, 0x02,
        0xff, 0x6a, 0x8e, 0x02,
-       0x00, 0x65, 0x6d, 0x17,
-       0x3d, 0x6a, 0x44, 0x17,
-       0x00, 0x65, 0x5c, 0x10,
-       0x00, 0x65, 0x4f, 0x17,
+       0x00, 0x65, 0x9f, 0x17,
+       0x3d, 0x6a, 0x61, 0x17,
+       0x00, 0x65, 0x82, 0x10,
+       0x00, 0x65, 0x6c, 0x17,
        0xff, 0x06, 0xa2, 0x02,
-       0x00, 0x65, 0x5c, 0x10,
-       0xff, 0x34, 0xb2, 0x1a,
-       0x08, 0x6a, 0x32, 0x17,
-       0x35, 0x6a, 0x65, 0x00,
-       0xff, 0x34, 0x66, 0x02,
-       0x01, 0x0c, 0xb4, 0x1e,
-       0x04, 0x0c, 0xb4, 0x1a,
-       0xe0, 0x03, 0x4c, 0x02,
-       0xa0, 0x4c, 0xc0, 0x18,
-       0xff, 0x66, 0xbb, 0x1a,
-       0x10, 0x4c, 0x03, 0x00,
-       0x00, 0x65, 0xb2, 0x10,
-       0x01, 0x66, 0xbd, 0x18,
+       0x00, 0x65, 0x82, 0x10,
+       0xff, 0x34, 0x65, 0x02,
+       0x80, 0x65, 0xe6, 0x18,
+       0x0f, 0xa1, 0x65, 0x02,
+       0x07, 0xa1, 0x65, 0x02,
+       0x40, 0xa0, 0x64, 0x02,
+       0x00, 0x65, 0x65, 0x00,
+       0x80, 0x65, 0x65, 0x00,
+       0x80, 0xa0, 0xde, 0x1e,
+       0xff, 0x65, 0x06, 0x02,
+       0x00, 0x65, 0xe7, 0x10,
+       0x20, 0xa0, 0xe9, 0x1e,
+       0xff, 0x65, 0x06, 0x02,
+       0x00, 0x65, 0x9b, 0x17,
+       0xa0, 0x3d, 0xef, 0x18,
+       0x23, 0xa0, 0x06, 0x02,
+       0x00, 0x65, 0x9b, 0x17,
+       0xa0, 0x3d, 0xef, 0x18,
+       0x00, 0xb9, 0xe9, 0x10,
+       0xff, 0x65, 0xe9, 0x18,
+       0xa1, 0x6a, 0x91, 0x00,
+       0x10, 0x51, 0xef, 0x1c,
        0x40, 0x6a, 0x0c, 0x00,
-       0xff, 0x66, 0x66, 0x06,
-       0xff, 0x6c, 0x06, 0x02,
-       0x00, 0x65, 0xb4, 0x10,
+       0xff, 0x65, 0x06, 0x02,
+       0x00, 0x65, 0x9b, 0x17,
+       0xa0, 0x3d, 0xef, 0x18,
+       0x10, 0x3d, 0x03, 0x00,
+       0x00, 0x65, 0xd4, 0x10,
        0x40, 0x6a, 0x0c, 0x00,
-       0xff, 0x6a, 0x34, 0x02,
-       0x00, 0x65, 0x5c, 0x10,
-       0x64, 0x6a, 0x3f, 0x17,
-       0xff, 0x64, 0x4b, 0x02,
-       0x80, 0x64, 0x0e, 0x1b,
-       0x04, 0x64, 0x01, 0x1d,
-       0x02, 0x64, 0x04, 0x1d,
-       0x00, 0x6a, 0xd1, 0x1c,
-       0x03, 0x64, 0x0c, 0x1d,
-       0x01, 0x64, 0xf5, 0x1c,
-       0x07, 0x64, 0x30, 0x1d,
-       0x08, 0x64, 0xcf, 0x1c,
+       0xff, 0x34, 0x52, 0x02,
+       0x80, 0x34, 0xf3, 0x18,
+       0x7f, 0xa0, 0xa0, 0x02,
+       0x08, 0x6a, 0x34, 0x00,
+       0x00, 0x65, 0x82, 0x10,
+       0x64, 0x6a, 0x59, 0x17,
+       0x80, 0x64, 0x2f, 0x1b,
+       0x04, 0x64, 0x22, 0x1d,
+       0x02, 0x64, 0x25, 0x1d,
+       0x00, 0x6a, 0x02, 0x1d,
+       0x03, 0x64, 0x2d, 0x1d,
+       0x01, 0x64, 0x20, 0x1d,
+       0x07, 0x64, 0x50, 0x1d,
+       0x08, 0x64, 0x00, 0x1d,
        0x11, 0x6a, 0x91, 0x00,
-       0x07, 0x6a, 0x32, 0x17,
+       0x07, 0x6a, 0x52, 0x17,
        0xff, 0x06, 0x6a, 0x02,
-       0x00, 0x65, 0x5c, 0x10,
-       0xff, 0xa8, 0xd3, 0x1a,
-       0xff, 0xa2, 0xda, 0x1e,
-       0x01, 0x6a, 0x3d, 0x00,
-       0x00, 0xb9, 0x77, 0x17,
-       0xff, 0xa2, 0xda, 0x1e,
+       0x00, 0x65, 0x82, 0x10,
+       0xff, 0xa8, 0x04, 0x1b,
+       0xff, 0xa2, 0x0f, 0x1f,
+       0x01, 0x6a, 0x35, 0x00,
+       0x00, 0xb9, 0xb3, 0x17,
+       0xff, 0xa2, 0x0f, 0x1f,
        0x71, 0x6a, 0x91, 0x00,
-       0x40, 0x59, 0xda, 0x18,
-       0xff, 0xb9, 0xb3, 0x02,
-       0x00, 0x65, 0xe7, 0x10,
-       0x20, 0xa0, 0xe0, 0x1a,
-       0xff, 0x90, 0x4a, 0x02,
-       0xff, 0xb3, 0x49, 0x02,
-       0x00, 0xa1, 0xa1, 0x17,
-       0xff, 0x49, 0x6d, 0x02,
-       0xff, 0x4a, 0x90, 0x02,
-       0xff, 0x5b, 0x64, 0x02,
-       0x00, 0x5a, 0xe1, 0x1c,
-       0x01, 0x5a, 0x5a, 0x06,
-       0xff, 0xb9, 0x9d, 0x02,
+       0x40, 0x51, 0x0f, 0x19,
+       0x0d, 0x6a, 0x35, 0x00,
+       0x00, 0xb9, 0xb3, 0x17,
+       0xff, 0x3e, 0xba, 0x02,
+       0xff, 0x90, 0x3e, 0x02,
+       0x00, 0x65, 0x20, 0x16,
+       0x00, 0x65, 0x8b, 0x10,
+       0x20, 0xa0, 0x16, 0x1b,
+       0xff, 0x37, 0x64, 0x02,
+       0x00, 0x6a, 0x93, 0x17,
+       0x01, 0x6a, 0x93, 0x00,
+       0xff, 0x6a, 0x99, 0x00,
+       0x0a, 0x93, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0xff, 0x4f, 0x64, 0x02,
+       0x01, 0x6a, 0x93, 0x17,
+       0x01, 0x6a, 0x93, 0x00,
+       0xff, 0xb9, 0x99, 0x02,
+       0x0a, 0x93, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0x01, 0x4f, 0x4f, 0x06,
        0x02, 0x6a, 0x91, 0x00,
-       0x08, 0xa0, 0xe7, 0x1e,
-       0x91, 0x6a, 0x91, 0x00,
-       0xff, 0xb3, 0xf3, 0x1c,
-       0xff, 0xb3, 0x64, 0x02,
-       0x00, 0xb9, 0xed, 0x1c,
-       0x00, 0x65, 0xaa, 0x17,
-       0xff, 0x64, 0x90, 0x02,
-       0x00, 0x65, 0xef, 0x10,
-       0x0d, 0x6a, 0x3d, 0x00,
-       0x00, 0xb3, 0x77, 0x17,
-       0xff, 0x48, 0xba, 0x02,
-       0xff, 0x90, 0x48, 0x02,
-       0x00, 0x65, 0x2f, 0x16,
-       0x00, 0x65, 0x69, 0x10,
-       0x00, 0x65, 0xaa, 0x17,
-       0x00, 0x65, 0x69, 0x10,
-       0x4d, 0x6a, 0x3a, 0x17,
-       0xff, 0x4d, 0x64, 0x02,
-       0x00, 0x66, 0x3a, 0x17,
-       0xff, 0x64, 0x64, 0x06,
-       0x52, 0x66, 0xfb, 0x18,
-       0xff, 0x66, 0x66, 0x06,
-       0xff, 0x64, 0xf7, 0x1a,
+       0x00, 0x65, 0xd5, 0x17,
+       0x00, 0x65, 0x8b, 0x10,
        0x41, 0x6a, 0x91, 0x00,
-       0x20, 0x59, 0xcd, 0x1c,
-       0x80, 0x59, 0xcf, 0x18,
-       0x10, 0x4c, 0x03, 0x00,
-       0x00, 0x65, 0xcf, 0x10,
+       0x00, 0x65, 0x82, 0x10,
        0x04, 0xa0, 0xa0, 0x00,
-       0x00, 0x65, 0xbb, 0x17,
-       0x00, 0x65, 0x69, 0x10,
-       0x10, 0x41, 0xcf, 0x1e,
-       0xff, 0x43, 0xa3, 0x02,
+       0x00, 0x65, 0xe1, 0x17,
+       0x00, 0x65, 0x8b, 0x10,
+       0x10, 0x36, 0x00, 0x1f,
+       0xff, 0x38, 0xa3, 0x02,
        0xa4, 0x6a, 0x66, 0x00,
-       0x44, 0x6a, 0x73, 0x17,
+       0x39, 0x6a, 0xa5, 0x17,
        0xac, 0x6a, 0x66, 0x00,
-       0x14, 0x6a, 0x73, 0x17,
-       0xa9, 0x6a, 0x74, 0x17,
-       0x00, 0x65, 0xcf, 0x10,
-       0xef, 0x41, 0x41, 0x02,
-       0x00, 0x65, 0xcf, 0x10,
-       0x78, 0x64, 0xcd, 0x1a,
+       0x14, 0x6a, 0xa5, 0x17,
+       0xa9, 0x6a, 0xa6, 0x17,
+       0x00, 0x65, 0x00, 0x11,
+       0xef, 0x36, 0x36, 0x02,
+       0x00, 0x65, 0x00, 0x11,
+       0x0f, 0x64, 0x64, 0x02,
        0x07, 0x64, 0x64, 0x02,
-       0x00, 0x42, 0x42, 0x00,
-       0x00, 0x42, 0xa1, 0x17,
-       0xff, 0x6c, 0x59, 0x02,
-       0xff, 0x59, 0x28, 0x19,
-       0xff, 0x59, 0x18, 0x1d,
-       0xff, 0x59, 0x90, 0x02,
-       0x04, 0xa0, 0x2d, 0x1f,
-       0x00, 0x65, 0x2a, 0x11,
+       0x00, 0x37, 0x37, 0x00,
+       0x00, 0x65, 0x8b, 0x17,
+       0xff, 0x51, 0x37, 0x1d,
+       0x20, 0x36, 0x3f, 0x1f,
+       0x00, 0x90, 0x7d, 0x17,
+       0x00, 0x65, 0x40, 0x11,
        0xff, 0x06, 0x6a, 0x02,
-       0x01, 0x0c, 0x19, 0x1f,
-       0x04, 0x0c, 0x19, 0x1b,
-       0xe0, 0x03, 0x4c, 0x02,
-       0xe0, 0x4c, 0x2d, 0x19,
-       0x20, 0x12, 0x2d, 0x19,
-       0x20, 0x41, 0x41, 0x00,
-       0x59, 0x6a, 0x3a, 0x17,
-       0xff, 0x3f, 0x64, 0x02,
-       0x00, 0x59, 0x65, 0x06,
-       0x00, 0x65, 0x2d, 0x13,
-       0xff, 0x59, 0x90, 0x02,
-       0xff, 0x42, 0x64, 0x02,
-       0x00, 0xa1, 0x2d, 0x19,
-       0x20, 0xa0, 0x2d, 0x1f,
-       0x04, 0xa0, 0x2d, 0x1f,
-       0x00, 0x6a, 0x52, 0x17,
-       0xff, 0x65, 0x2d, 0x1d,
+       0x00, 0x65, 0x9b, 0x17,
+       0xe0, 0x3d, 0x4d, 0x19,
+       0x20, 0x12, 0x4d, 0x19,
+       0x51, 0x6a, 0x54, 0x17,
+       0xff, 0x51, 0x90, 0x02,
+       0x20, 0xa0, 0x4d, 0x1f,
+       0x00, 0x90, 0x7d, 0x17,
+       0x00, 0x65, 0x7a, 0x17,
+       0xff, 0x37, 0x64, 0x02,
+       0x00, 0xa1, 0x49, 0x19,
+       0x04, 0xa0, 0x49, 0x1f,
        0xfb, 0xa0, 0xa0, 0x02,
-       0x40, 0x41, 0x41, 0x00,
-       0x00, 0x65, 0xcf, 0x10,
+       0x80, 0x36, 0x36, 0x00,
+       0x80, 0xa0, 0x00, 0x1f,
+       0x7f, 0xa0, 0xa0, 0x02,
+       0xff, 0x6a, 0x52, 0x17,
+       0x00, 0x65, 0x00, 0x11,
+       0x04, 0xa0, 0x4c, 0x1f,
+       0x00, 0x65, 0xe1, 0x17,
+       0x00, 0x65, 0x4d, 0x11,
+       0x00, 0x65, 0xd5, 0x17,
        0x31, 0x6a, 0x91, 0x00,
-       0x0c, 0x6a, 0x32, 0x17,
-       0x00, 0x65, 0xcf, 0x10,
+       0x0c, 0x6a, 0x52, 0x17,
+       0x00, 0x65, 0x00, 0x11,
        0x61, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0xcf, 0x10,
-       0x50, 0x6a, 0x60, 0x00,
-       0xff, 0x34, 0x36, 0x1f,
-       0x10, 0x6a, 0x60, 0x00,
-       0xc1, 0x6a, 0x91, 0x00,
-       0x10, 0x4c, 0x03, 0x00,
-       0x01, 0x6a, 0x34, 0x00,
-       0xff, 0x65, 0x35, 0x02,
-       0x10, 0x6a, 0x60, 0x01,
+       0x00, 0x65, 0x00, 0x11,
+       0x10, 0x3d, 0x03, 0x00,
+       0xff, 0x65, 0x34, 0x03,
        0xff, 0x06, 0x6a, 0x02,
-       0x01, 0x0c, 0x3b, 0x1f,
-       0x04, 0x0c, 0x3b, 0x1b,
-       0xe0, 0x03, 0x4c, 0x02,
-       0xe0, 0x4c, 0x42, 0x19,
+       0x01, 0x0c, 0x55, 0x1f,
+       0x04, 0x0c, 0x55, 0x1b,
+       0xe0, 0x03, 0x3d, 0x02,
+       0xe0, 0x3d, 0x5f, 0x19,
        0xff, 0x65, 0x66, 0x02,
        0xff, 0x12, 0x6d, 0x03,
        0xff, 0x06, 0x6a, 0x03,
+       0xff, 0x65, 0x06, 0x02,
+       0x02, 0x0b, 0x5d, 0x1f,
+       0xff, 0x6a, 0x6a, 0x03,
        0xd1, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x5c, 0x10,
+       0x00, 0x65, 0x82, 0x10,
        0xff, 0x65, 0x93, 0x02,
-       0x01, 0x0b, 0x4c, 0x1b,
-       0x10, 0x0c, 0x45, 0x1f,
-       0x04, 0x0b, 0x49, 0x1b,
+       0x01, 0x0b, 0x69, 0x1b,
+       0x10, 0x0c, 0x62, 0x1f,
+       0x04, 0x0b, 0x66, 0x1b,
        0xff, 0x6a, 0x65, 0x02,
-       0x04, 0x93, 0x4b, 0x1b,
-       0x01, 0x94, 0x4a, 0x1f,
-       0x10, 0x94, 0x4b, 0x1b,
+       0x04, 0x93, 0x68, 0x1b,
+       0x01, 0x94, 0x67, 0x1f,
+       0x10, 0x94, 0x68, 0x1b,
        0xc7, 0x93, 0x93, 0x02,
-       0x38, 0x93, 0x4d, 0x1b,
+       0x38, 0x93, 0x6a, 0x1b,
        0xff, 0x6a, 0x6a, 0x03,
-       0x80, 0x41, 0x4e, 0x1f,
-       0x40, 0x41, 0x4e, 0x1b,
+       0x80, 0x36, 0x6b, 0x1b,
        0x21, 0x6a, 0x91, 0x01,
        0xff, 0x65, 0x90, 0x02,
-       0xff, 0x59, 0x64, 0x02,
-       0x00, 0xb9, 0x56, 0x19,
-       0x04, 0xa0, 0x60, 0x1b,
-       0x01, 0x65, 0x65, 0x06,
-       0xff, 0x3e, 0x64, 0x02,
-       0x00, 0x65, 0x52, 0x19,
-       0x00, 0x6a, 0xad, 0x17,
-       0x0d, 0x6a, 0x3d, 0x00,
-       0x00, 0x59, 0x77, 0x17,
-       0xff, 0xa8, 0x5e, 0x1f,
-       0x10, 0xa0, 0xa0, 0x00,
-       0x08, 0xa0, 0x4e, 0x1f,
+       0xff, 0x51, 0x72, 0x19,
+       0xff, 0x37, 0x64, 0x02,
+       0xa1, 0x6a, 0x77, 0x11,
+       0xff, 0x51, 0x64, 0x02,
+       0xb9, 0x6a, 0x77, 0x11,
+       0xff, 0xba, 0x79, 0x1d,
+       0xff, 0xba, 0x90, 0x02,
+       0xff, 0x65, 0x65, 0x06,
+       0x00, 0x6c, 0x74, 0x19,
+       0xff, 0x90, 0x65, 0x03,
        0xff, 0x6a, 0x65, 0x01,
-       0x08, 0xa0, 0x5f, 0x1b,
-       0xff, 0xba, 0x66, 0x1d,
-       0xff, 0xbb, 0x49, 0x02,
+       0x20, 0x36, 0x88, 0x1f,
+       0x00, 0x90, 0x6e, 0x17,
+       0xff, 0x65, 0x88, 0x1d,
+       0xff, 0xba, 0x82, 0x1d,
+       0xff, 0xbb, 0x66, 0x02,
        0xff, 0xba, 0x90, 0x02,
-       0xff, 0x49, 0xbb, 0x02,
+       0xff, 0x66, 0xbb, 0x02,
        0xff, 0x65, 0x90, 0x02,
-       0xff, 0xbb, 0x6b, 0x1d,
-       0xff, 0xba, 0x49, 0x02,
+       0xff, 0xbb, 0x87, 0x1d,
+       0xff, 0xba, 0x66, 0x02,
        0xff, 0xbb, 0x90, 0x02,
-       0xff, 0x49, 0xba, 0x02,
+       0xff, 0x66, 0xba, 0x02,
        0xff, 0x65, 0x90, 0x03,
-       0xff, 0xba, 0x52, 0x03,
-       0xff, 0x6a, 0x6a, 0x03,
+       0xff, 0xba, 0x3f, 0x03,
+       0x00, 0x6a, 0xd8, 0x17,
+       0x0d, 0x6a, 0x35, 0x00,
+       0x00, 0x51, 0xb3, 0x11,
+       0xff, 0x3f, 0x96, 0x1d,
+       0xff, 0x6a, 0x51, 0x00,
+       0x00, 0x3f, 0x6e, 0x17,
+       0xff, 0x65, 0x96, 0x1d,
+       0x20, 0x36, 0x36, 0x00,
+       0x20, 0xa0, 0x92, 0x1b,
+       0xff, 0xb9, 0x51, 0x03,
+       0xff, 0x6a, 0x51, 0x01,
+       0xff, 0x65, 0x66, 0x02,
+       0x45, 0x6a, 0xab, 0x17,
+       0x01, 0x6a, 0x8c, 0x01,
+       0xff, 0x37, 0x64, 0x02,
+       0x00, 0x6a, 0x93, 0x17,
+       0x0d, 0x6a, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0xff, 0x99, 0x51, 0x03,
+       0x01, 0x0c, 0x9b, 0x1f,
+       0x04, 0x0c, 0x9b, 0x1b,
+       0xe0, 0x03, 0x3d, 0x02,
+       0xff, 0x3d, 0x03, 0x03,
        0xff, 0x8c, 0x08, 0x02,
        0xff, 0x8d, 0x09, 0x02,
        0xff, 0x8e, 0x0a, 0x03,
@@ -377,19 +427,21 @@ static u_int8_t seqprog[] = {
        0xff, 0x6c, 0x6d, 0x02,
        0xff, 0x6c, 0x6d, 0x02,
        0xff, 0x6c, 0x6d, 0x03,
-       0x3d, 0x65, 0x66, 0x0a,
-       0x55, 0x65, 0x64, 0x0a,
-       0x00, 0x54, 0x88, 0x06,
+       0x3d, 0x64, 0x66, 0x0a,
+       0x55, 0x64, 0x64, 0x0a,
+       0x00, 0x6c, 0x88, 0x06,
        0xff, 0x66, 0x64, 0x02,
-       0x00, 0x55, 0x89, 0x08,
+       0x00, 0x6c, 0x89, 0x08,
        0xff, 0x6a, 0x64, 0x02,
-       0x00, 0x56, 0x8a, 0x08,
-       0x00, 0x57, 0x8b, 0x08,
-       0x1c, 0x6a, 0x8c, 0x00,
+       0x00, 0x6c, 0x8a, 0x08,
+       0x00, 0x6c, 0x8b, 0x08,
        0xff, 0x6a, 0x8d, 0x02,
-       0xff, 0x6a, 0x8e, 0x02,
-       0xff, 0x3d, 0x93, 0x02,
-       0x04, 0x3d, 0x8f, 0x1b,
+       0xff, 0x6a, 0x8e, 0x03,
+       0xff, 0x65, 0x64, 0x02,
+       0x41, 0x6a, 0xa9, 0x17,
+       0x1c, 0x6a, 0x8c, 0x00,
+       0xff, 0x35, 0x93, 0x02,
+       0x04, 0x35, 0xc3, 0x1b,
        0xa0, 0x6a, 0x65, 0x00,
        0x1c, 0x65, 0x64, 0x06,
        0xff, 0x6c, 0x99, 0x02,
@@ -399,14 +451,14 @@ static u_int8_t seqprog[] = {
        0xff, 0x6c, 0x99, 0x02,
        0xff, 0x6c, 0x99, 0x02,
        0xff, 0x6c, 0x99, 0x02,
-       0x00, 0x65, 0x86, 0x19,
+       0x00, 0x65, 0xba, 0x19,
        0x0a, 0x93, 0x93, 0x00,
-       0x00, 0x65, 0x9d, 0x17,
-       0x04, 0x3d, 0x4e, 0x1f,
-       0xa0, 0x6a, 0x95, 0x17,
-       0x00, 0x65, 0x96, 0x17,
-       0x00, 0x65, 0x96, 0x17,
-       0x00, 0x65, 0x96, 0x11,
+       0x00, 0x65, 0xd1, 0x17,
+       0x04, 0x35, 0x6b, 0x1f,
+       0xa0, 0x6a, 0xc9, 0x17,
+       0x00, 0x65, 0xca, 0x17,
+       0x00, 0x65, 0xca, 0x17,
+       0x00, 0x65, 0xca, 0x11,
        0xff, 0x65, 0x66, 0x02,
        0xff, 0x99, 0x6d, 0x02,
        0xff, 0x99, 0x6d, 0x02,
@@ -415,69 +467,58 @@ static u_int8_t seqprog[] = {
        0xff, 0x99, 0x6d, 0x02,
        0xff, 0x99, 0x6d, 0x02,
        0xff, 0x99, 0x6d, 0x03,
-       0x08, 0x94, 0x9d, 0x1f,
+       0x08, 0x94, 0xd1, 0x1f,
        0xf7, 0x93, 0x93, 0x02,
-       0x08, 0x93, 0x9f, 0x1b,
+       0x08, 0x93, 0xd3, 0x1b,
        0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x65, 0x66, 0x02,
-       0x4c, 0x66, 0x66, 0x0a,
-       0x03, 0x66, 0x66, 0x02,
-       0xbc, 0x66, 0x66, 0x06,
-       0x6a, 0x65, 0x64, 0x0a,
-       0x08, 0x65, 0xa8, 0x1f,
-       0x02, 0x64, 0x64, 0x06,
-       0xff, 0x64, 0x90, 0x02,
-       0xff, 0x66, 0x65, 0x03,
-       0xff, 0x53, 0xba, 0x02,
-       0xff, 0x6a, 0xb9, 0x00,
-       0xff, 0x90, 0x53, 0x03,
-       0xff, 0x53, 0xb9, 0x19,
-       0xff, 0x52, 0xb0, 0x19,
+       0xff, 0x40, 0xba, 0x02,
+       0xff, 0x90, 0x40, 0x02,
+       0xff, 0x6a, 0xb9, 0x01,
+       0xff, 0x40, 0xdf, 0x19,
+       0xff, 0x3f, 0xdb, 0x19,
        0xff, 0x6a, 0x65, 0x01,
-       0xff, 0x52, 0x90, 0x02,
-       0x10, 0xa0, 0xb4, 0x1f,
-       0xef, 0xa0, 0xa0, 0x02,
-       0x00, 0x65, 0xb6, 0x11,
-       0xff, 0xa8, 0xb6, 0x1b,
-       0xff, 0xb3, 0xb8, 0x1d,
-       0x01, 0x6a, 0x3d, 0x00,
-       0x00, 0xb9, 0x77, 0x17,
-       0x00, 0x90, 0x61, 0x11,
-       0xff, 0x53, 0x90, 0x02,
-       0xff, 0xba, 0x53, 0x03,
+       0xff, 0x3f, 0x90, 0x02,
+       0x01, 0x6a, 0x35, 0x00,
+       0x00, 0xb9, 0xb3, 0x17,
+       0x00, 0x90, 0x7d, 0x11,
+       0xff, 0x40, 0x90, 0x02,
+       0xff, 0xba, 0x40, 0x03,
        0xff, 0x6a, 0xbb, 0x00,
-       0xff, 0x52, 0xba, 0x02,
-       0xff, 0x90, 0x52, 0x02,
-       0xff, 0xba, 0x4e, 0x1d,
+       0xff, 0x3f, 0xba, 0x02,
+       0xff, 0x90, 0x3f, 0x02,
+       0xff, 0xba, 0x6b, 0x1d,
        0xff, 0xba, 0x90, 0x02,
-       0xff, 0x52, 0xbb, 0x02,
-       0xff, 0x52, 0x90, 0x03,
+       0xff, 0x3f, 0xbb, 0x02,
+       0xff, 0x3f, 0x90, 0x03,
 };
-#define        ULTRA                   0x8
-#define        SCB_PAGING              0x4
-#define        TWIN_CHANNEL            0x2
+#define        WIDE                    0x20
+#define        ULTRA                   0x10
+#define        SCB_PAGING              0x8
+#define        TWIN_CHANNEL            0x4
+#define        TARGET_MODE             0x2
 struct patch {
        int     options;
        int     negative;
        int     begin;
        int     end;
 } patches[] = {
-       { 0x00000002, 0, 0x006, 0x00b },
-       { 0x00000004, 0, 0x00e, 0x010 },
-       { 0x00000004, 1, 0x011, 0x012 },
-       { 0x00000004, 0, 0x01a, 0x023 },
-       { 0x00000004, 1, 0x023, 0x027 },
-       { 0x00000002, 0, 0x02f, 0x033 },
-       { 0x00000008, 0, 0x04f, 0x056 },
-       { 0x00000004, 0, 0x0e0, 0x0e3 },
-       { 0x00000004, 1, 0x0e8, 0x0ed },
-       { 0x00000004, 0, 0x102, 0x103 },
-       { 0x00000004, 0, 0x113, 0x114 },
-       { 0x00000004, 1, 0x114, 0x118 },
-       { 0x00000004, 1, 0x123, 0x128 },
-       { 0x00000004, 0, 0x128, 0x12a },
-       { 0x00000004, 0, 0x152, 0x16c },
-       { 0x00000004, 1, 0x16c, 0x16d },
-       { 0x00000004, 0, 0x1ad, 0x1c2 },
+       { 0x00000002, 0, 0x001, 0x002 },
+       { 0x00000002, 1, 0x002, 0x003 },
+       { 0x00000004, 0, 0x009, 0x00d },
+       { 0x00000008, 0, 0x012, 0x013 },
+       { 0x00000008, 1, 0x018, 0x019 },
+       { 0x00000004, 0, 0x020, 0x024 },
+       { 0x00000010, 0, 0x02a, 0x031 },
+       { 0x00000002, 0, 0x038, 0x071 },
+       { 0x00000020, 0, 0x0d6, 0x0d7 },
+       { 0x00000020, 1, 0x0d7, 0x0d8 },
+       { 0x00000020, 0, 0x12f, 0x130 },
+       { 0x00000020, 1, 0x130, 0x131 },
+       { 0x00000008, 0, 0x134, 0x135 },
+       { 0x00000008, 1, 0x13c, 0x13f },
+       { 0x00000008, 0, 0x13f, 0x140 },
+       { 0x00000002, 0, 0x15c, 0x15f },
+       { 0x00000008, 0, 0x1d5, 0x1d7 },
+       { 0x00000008, 0, 0x1d8, 0x1e1 },
        { 0x00000000, 0, 0x000, 0x000 }
 };
index f45c133d7a8edddb4904601461c67aeadef487b9..fbfb39306bf11fabd7a47e84f07703646e364c2a 100644 (file)
@@ -263,7 +263,7 @@ __initfunc(int dtc_detect(Scsi_Host_Template * tpnt)) {
 /* With interrupts enabled, it will sometimes hang when doing heavy
  * reads. So better not enable them until I finger it out. */
       if (instance->irq != IRQ_NONE)
-        if (request_irq(instance->irq, dtc_intr, SA_INTERRUPT, "dtc")) {
+        if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) {
         printk("scsi%d : IRQ%d not free, interrupts disabled\n",
              instance->host_no, instance->irq);
         instance->irq = IRQ_NONE;
index c0e15f6ea5c165cb578afa650c1922cb606ec14c..9acdf4a04e64c95864d91bc40a00b62b3e5df353 100644 (file)
@@ -112,6 +112,7 @@ int dtc_proc_info (char *buffer, char **start, off_t offset,
 #endif
 
 #define NCR5380_intr dtc_intr
+#define do_NCR5380_intr do_dtc_intr
 #define NCR5380_queue_command dtc_queue_command
 #define NCR5380_abort dtc_abort
 #define NCR5380_reset dtc_reset
index 86a29fd5d66e656dc2c1d3c5718eeecdf808c3d9..0eb82b6d4cf27666a425703118b2902fafb85025 100644 (file)
@@ -316,6 +316,7 @@ MODULE_AUTHOR("Dario Ballabio");
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/spinlock.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -599,7 +600,7 @@ static unsigned long io_port[] __initdata = {
 #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
 #define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
 
-static void interrupt_handler(int, void *, struct pt_regs *);
+static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
 static int setup_done = FALSE;
@@ -872,7 +873,7 @@ __initfunc (static inline int port_detect \
       }
 
    /* Board detected, allocate its IRQ */
-   if (request_irq(irq, interrupt_handler,
+   if (request_irq(irq, do_interrupt_handler,
              SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
              driver_name, (void *) &sha[j])) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
@@ -1935,7 +1936,7 @@ static inline void ihdlr(int irq, void *shap, struct pt_regs *regs) {
    return;
 }
 
-static void interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
 
index 4b2c5c12f344d392f79da010307bdd9f475494d2..189b7a5e6091dd7f32f6981687f7104c3e1e3740 100644 (file)
@@ -81,6 +81,7 @@
 #include <asm/pgtable.h>
 #ifdef __mips__
 #include <asm/cachectl.h>
+#include <asm/spinlock.h>
 #endif
 #include <linux/blk.h>
 #include "scsi.h"
@@ -240,6 +241,16 @@ inline void eata_latency_out(struct eata_ccb *cp, Scsi_Cmnd *cmd)
     } 
 }
 
+void eata_int_handler(int, void *, struct pt_regs *);
+
+void do_eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    eata_int_handler(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
 {
@@ -1535,7 +1546,7 @@ int eata_detect(Scsi_Host_Template * tpnt)
     for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we     */
        if (reg_IRQ[i] >= 1){       /* exchange the interrupt handler which  */
            free_irq(i, NULL);      /* we used for probing with the real one */
-           request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT|SA_SHIRQ, 
+           request_irq(i, (void *)(do_eata_int_handler), SA_INTERRUPT|SA_SHIRQ, 
                        "eata_dma", NULL);
        }
     }
index d46c0a7e14bfb91b2b2e39a1b886f5ac4c710977..57de91f5b8d7d494684a510fd43ddbd00663916c 100644 (file)
@@ -56,6 +56,8 @@
 
 #include <linux/stat.h>
 #include <linux/config.h>      /* for CONFIG_PCI */
+#include <linux/blk.h>
+#include <asm/spinlock.h>
 
 struct proc_dir_entry proc_scsi_eata_pio = {
     PROC_SCSI_EATA_PIO, 9, "eata_pio",
@@ -109,6 +111,17 @@ void IncStat(Scsi_Pointer *SCp, uint Increment)
     }
 }
 
+void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs);
+
+void do_eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    eata_pio_int_handler(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
 {
     uint eata_stat = 0xfffff;
@@ -697,7 +710,7 @@ int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
     }
     
     if (!reg_IRQ[gc->IRQ]) {    /* Interrupt already registered ? */
-       if (!request_irq(gc->IRQ, eata_pio_int_handler, SA_INTERRUPT, 
+       if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, 
                         "EATA-PIO", NULL)){
            reg_IRQ[gc->IRQ]++;
            if (!gc->IRQ_TR)
@@ -983,7 +996,7 @@ int eata_pio_detect(Scsi_Host_Template * tpnt)
     
     for (i = 0; i <= MAXIRQ; i++)
        if (reg_IRQ[i])
-           request_irq(i, eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
+           request_irq(i, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
     
     HBA_ptr = first_HBA;
   
index c57d5a9a26433b5bfd0242163530972cd73e0cf8..57b84add6421044a9ad47fd22b6a6688ee46b057 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/idprom.h>
+#include <asm/spinlock.h>
 
 #define DEBUG_ESP
 /* #define DEBUG_ESP_HME */
@@ -172,6 +173,7 @@ static int esps_running = 0;
 
 /* Forward declarations. */
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+static void do_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
 
 /* Debugging routines */
 struct esp_cmdstrings {
@@ -799,7 +801,7 @@ __initfunc(int esp_detect(Scsi_Host_Template *tpnt))
                                        goto esp_irq_acquired; /* BASIC rulez */
                                }
                        }
-                       if(request_irq(esp->ehost->irq, esp_intr, SA_SHIRQ,
+                       if(request_irq(esp->ehost->irq, do_esp_intr, SA_SHIRQ,
                                       "Sparc ESP SCSI", NULL))
                                panic("Cannot acquire ESP irq line");
 esp_irq_acquired:
@@ -812,7 +814,7 @@ esp_irq_acquired:
                        dcookie.imap = dcookie.iclr = 0;
                        dcookie.pil = -1;
                        dcookie.bus_cookie = sbus;
-                       if(request_irq(esp->ehost->irq, esp_intr,
+                       if(request_irq(esp->ehost->irq, do_esp_intr,
                                       (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
                                       "Sparc ESP SCSI", &dcookie))
                                panic("Cannot acquire ESP irq line");
@@ -4038,6 +4040,15 @@ esp_handle_done:
        return;
 }
 
+static void do_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       esp_intr(irq, dev_id, pregs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 #ifndef __sparc_v9__
 
 #ifndef __SMP__
index 0276ac45890b9e952869af855afe7773d8877c26..e3afccaace7ef66684e335580f8cc1a19cd516c7 100644 (file)
 #include "hosts.h"
 #include "fdomain.h"
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
@@ -948,7 +949,7 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
       /* Register the IRQ with the kernel */
 
       retcode = request_irq( interrupt_level,
-                            fdomain_16x0_intr, SA_INTERRUPT, "fdomain", NULL);
+                            do_fdomain_16x0_intr, SA_INTERRUPT, "fdomain", NULL);
 
       if (retcode < 0) {
         if (retcode == -EINVAL) {
@@ -1610,6 +1611,15 @@ void fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
    return;
 }
 
+void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(&io_request_lock, flags);
+   fdomain_16x0_intr(irq, dev_id, regs);
+   spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 {
    if (in_command) {
index 006c98d8f62bf5425213827e20d8a5d01e3d1b50..9a667410a72ae8b773fe974d480c1bb25f424c9e 100644 (file)
@@ -251,7 +251,7 @@ __initfunc(int generic_NCR5380_detect(Scsi_Host_Template * tpnt)) {
            instance->irq = NCR5380_probe_irq(instance, 0xffff);
 
        if (instance->irq != IRQ_NONE) 
-           if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
+           if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
                printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
                    instance->host_no, instance->irq);
                instance->irq = IRQ_NONE;
index 00044927709c64dd331b5ff3dc3cb6b5e846f808..e0c34d9f80048bfa1e58db2208123cac8e5ab18f 100644 (file)
@@ -155,6 +155,7 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
     NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name)
 
 #define NCR5380_intr generic_NCR5380_intr
+#define do_NCR5380_intr do_generic_NCR5380_intr
 #define NCR5380_queue_command generic_NCR5380_queue_command
 #define NCR5380_abort generic_NCR5380_abort
 #define NCR5380_reset generic_NCR5380_reset
index d7ba32d15c4898e99980dbfae93a2cf6a4b65a34..c7182feefc39f04cd3eb343f633e1ce9e0939a5c 100644 (file)
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/spinlock.h>
 
 #if LINUX_VERSION_CODE >= 0x010300
 #include <linux/blk.h>
 
 #if LINUX_VERSION_CODE >= 0x010346
 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+static void do_gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
 #else
 static void gdth_interrupt(int irq,struct pt_regs *regs);
 #endif
@@ -2155,6 +2157,15 @@ static void gdth_clear_events()
 /* SCSI interface functions */
 
 #if LINUX_VERSION_CODE >= 0x010346
+static void do_gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    gdth_interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
 #else
 static void gdth_interrupt(int irq,struct pt_regs *regs)
@@ -2759,7 +2770,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
             save_flags(flags);
             cli();
 #if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
 #else
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
 #endif
@@ -2868,7 +2879,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
             save_flags(flags);
             cli();
 #if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
 #else
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
 #endif
@@ -2974,7 +2985,7 @@ int gdth_detect(Scsi_Host_Template *shtp)
             save_flags(flags);
             cli();
 #if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
 #else
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
 #endif
index b1fa60b113db6a65f910b2aac9b6e94c293c6486..0d8e89c747909061b20eb918db38cae0d0c7409e 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -51,6 +52,15 @@ static void gvp11_intr (int irq, void *dummy, struct pt_regs *fp)
     }
 }
 
+static void do_gvp11_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    gvp11_intr(irq, dummy, fp);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static int gvp11_xfer_mask = 0;
 
 void gvp11_setup (char *str, int *ints)
@@ -361,7 +371,7 @@ __initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
        if (num_gvp11++ == 0) {
                first_instance = instance;
                gvp11_template = instance->hostt;
-               request_irq(IRQ_AMIGA_PORTS, gvp11_intr, 0,
+               request_irq(IRQ_AMIGA_PORTS, do_gvp11_intr, 0,
                            "GVP11 SCSI", gvp11_intr);
        }
        DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
index d5f4c9c7cf1d6f807b7b67c6943054e041f42401..30a780acd87008b4c76c181a149319d718a4faf7 100644 (file)
@@ -107,6 +107,11 @@ typedef struct     SHT
      */
     const char *(* info)(struct Scsi_Host *);
 
+    /*
+     * ioctl interface
+     */
+    int (*ioctl)(Scsi_Device *dev, int cmd, void *arg);
+
     /*
      * The command function takes a target, a command (this is a SCSI
      * command formatted as per the SCSI spec, nothing strange), a
@@ -264,6 +269,11 @@ typedef struct     SHT
      */
     unsigned use_new_eh_code:1;
 
+    /*
+     * True for emulated SCSI host adapters (e.g. ATAPI)
+     */
+    unsigned emulated:1;
+
 } Scsi_Host_Template;
 
 /*
index 60be3c6199f739b40b2cc81459ce07c1caebaf31..034b219cc2354fc31cf8bece186d28b5385f6a9c 100644 (file)
 #include <linux/stat.h>
 #include <linux/mca.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include "sd.h"
 #include "scsi.h"
@@ -834,6 +835,7 @@ static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL };
 
 /*local functions in forward declaration */
 static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
+static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
 static void issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg, 
                        unsigned char attn_reg);
 static void internal_done (Scsi_Cmnd * cmd);
@@ -856,6 +858,17 @@ static int ldn_access_total_read_write(struct Scsi_Host *shpnt);
 
 /*--------------------------------------------------------------------*/
 
+
+static void 
+do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long flags;
+
+  spin_lock_irqsave(&io_request_lock, flags);
+  interrupt_handler(irq, dev_id, regs);
+  spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static void 
 interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -1526,7 +1539,7 @@ ibmmca_detect (Scsi_Host_Template * template)
     return 0;
 
   /* get interrupt request level */
-  if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmca", hosts))
+  if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmca", hosts))
     {
       printk("IBM MCA SCSI: Unable to get IRQ %d.\n", IM_IRQ);
       return 0;
index 0bfa8d8763462adc63a6622f62b42b143464acd0..d81cb5187461c3c5f88a7fc74addd5d9910afd20 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/scsi/ide-scsi.c       Version 0.5             Jan   2, 1998
+ * linux/drivers/scsi/ide-scsi.c       Version 0.6             Jan  27, 1998
  *
  * Copyright (C) 1996 - 1998 Gadi Oxman <gadio@netvision.net.il>
  */
  *                       Use variable timeout for each command.
  * Ver 0.5   Jan  2 98   Fix previous PD/CD support.
  *                       Allow disabling of SCSI-6 to SCSI-10 transformation.
+ * Ver 0.6   Jan 27 98   Allow disabling of SCSI command translation layer
+ *                        for access through /dev/sg.
+ *                       Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation.
  */
 
-#define IDESCSI_VERSION "0.5"
+#define IDESCSI_VERSION "0.6"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -37,6 +40,7 @@
 
 #include <asm/io.h>
 #include <asm/bitops.h>
+#include <asm/uaccess.h>
 
 #include "../block/ide.h"
 
@@ -44,6 +48,7 @@
 #include "hosts.h"
 #include "sd.h"
 #include "ide-scsi.h"
+#include <scsi/sg.h>
 
 #define IDESCSI_DEBUG_LOG              0
 
@@ -68,12 +73,25 @@ typedef struct idescsi_pc_s {
  */
 #define PC_DMA_IN_PROGRESS             0       /* 1 while DMA in progress */
 #define PC_WRITING                     1       /* Data direction */
+#define PC_TRANSFORM                   2       /* transform SCSI commands */
+
+/*
+ *     SCSI command transformation layer
+ */
+#define IDESCSI_TRANSFORM              0       /* Enable/Disable transformation */
+#define IDESCSI_SG_TRANSFORM           1       /* /dev/sg transformation */
+
+/*
+ *     Log flags
+ */
+#define IDESCSI_LOG_CMD                        0       /* Log SCSI commands */
 
 typedef struct {
        ide_drive_t *drive;
        idescsi_pc_t *pc;                       /* Current packet command */
        unsigned int flags;                     /* Status/Action flags */
-       int transform;                          /* Transform SCSI-6 commands */
+       int transform;                          /* SCSI cmd translation layer */
+       int log;                                /* log flags */
 } idescsi_scsi_t;
 
 /*
@@ -153,11 +171,10 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
  */
 static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
 {
-       idescsi_scsi_t *scsi = drive->driver_data;
-       u8 *c = pc->c, *buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
-       int i;
+       u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
+       char *atapi_buf;
 
-       if (!scsi->transform)
+       if (!test_bit(PC_TRANSFORM, &pc->flags))
                return;
        if (drive->media == ide_cdrom) {
                if (c[0] == READ_6 || c[0] == WRITE_6) {
@@ -165,35 +182,54 @@ static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
                        c[3] = c[1] & 0x1f;     c[2] = 0;               c[1] &= 0xe0;
                        c[0] += (READ_10 - READ_6);
                }
-               if (c[0] == MODE_SENSE || (c[0] == MODE_SELECT && buf[3] == 8)) {
-                       pc->request_transfer -= 4;
+               if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+                       if (!scsi_buf)
+                               return;
+                       if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
+                               return;
+                       memset(atapi_buf, 0, pc->buffer_size + 4);
                        memset (c, 0, 12);
-                       c[0] = sc[0] | 0x40;    c[2] = sc[2];           c[8] = sc[4] - 4;
-                       if (c[0] == MODE_SENSE_10) return;
-                       for (i = 0; i <= 7; i++) buf[i] = 0;
-                       for (i = 8; i < pc->buffer_size - 4; i++) buf[i] = buf[i + 4];
+                       c[0] = sc[0] | 0x40;    c[1] = sc[1];           c[2] = sc[2];
+                       c[8] = sc[4] + 4;       c[9] = sc[5];
+                       if (sc[4] + 4 > 255)
+                               c[7] = sc[4] + 4 - 255;
+                       if (c[0] == MODE_SELECT_10) {
+                               atapi_buf[1] = scsi_buf[0];     /* Mode data length */
+                               atapi_buf[2] = scsi_buf[1];     /* Medium type */
+                               atapi_buf[3] = scsi_buf[2];     /* Device specific parameter */
+                               atapi_buf[7] = scsi_buf[3];     /* Block descriptor length */
+                               memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
+                       }
+                       pc->buffer = atapi_buf;
+                       pc->request_transfer += 4;
+                       pc->buffer_size += 4;
                }
        }
 }
 
 static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
 {
-       idescsi_scsi_t *scsi = drive->driver_data;
-       u8 *buf = pc->buffer;
-       int i;
+       u8 *atapi_buf = pc->buffer;
+       u8 *sc = pc->scsi_cmd->cmnd;
+       u8 *scsi_buf = pc->scsi_cmd->request_buffer;
 
-       if (!scsi->transform)
+       if (!test_bit(PC_TRANSFORM, &pc->flags))
                return;
        if (drive->media == ide_cdrom) {
-               if (pc->c[0] == MODE_SENSE_10 && pc->scsi_cmd->cmnd[0] == MODE_SENSE) {
-                       buf[0] = buf[1];        buf[1] = buf[2];
-                       buf[2] = 0;             buf[3] = 8;
-                       for (i = pc->buffer_size - 1; i >= 12; i--) buf[i] = buf[i - 4];
-                       for (i = 11; i >= 4; i--) buf[i] = 0;
+               if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
+                       scsi_buf[0] = atapi_buf[1];             /* Mode data length */
+                       scsi_buf[1] = atapi_buf[2];             /* Medium type */
+                       scsi_buf[2] = atapi_buf[3];             /* Device specific parameter */
+                       scsi_buf[3] = atapi_buf[7];             /* Block descriptor length */
+                       memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
+               }
+               if (pc->c[0] == INQUIRY) {
+                       scsi_buf[2] |= 2;                       /* ansi_revision */
+                       scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */
                }
-               if (pc->c[0] == INQUIRY)
-                       buf[2] |= 2;
        }
+       if (atapi_buf && atapi_buf != scsi_buf)
+               kfree(atapi_buf);
 }
 
 static inline void idescsi_free_bh (struct buffer_head *bh)
@@ -207,12 +243,24 @@ static inline void idescsi_free_bh (struct buffer_head *bh)
        }
 }
 
+static void hexdump(u8 *x, int len)
+{
+       int i;
+
+       printk("[ ");
+       for (i = 0; i < len; i++)
+               printk("%x ", x[i]);
+       printk("]\n");
+}
+
 static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
 {
        ide_drive_t *drive = hwgroup->drive;
        idescsi_scsi_t *scsi = drive->driver_data;
        struct request *rq = hwgroup->rq;
        idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
+       int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
+       u8 *scsi_buf = pc->scsi_cmd->request_buffer;
 
        if (rq->cmd != IDESCSI_PC_RQ) {
                ide_end_request (uptodate, hwgroup);
@@ -220,21 +268,23 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
        }
        ide_end_drive_cmd (drive, 0, 0);
        if (rq->errors >= ERROR_MAX) {
-#if IDESCSI_DEBUG_LOG
-               printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
                pc->scsi_cmd->result = DID_ERROR << 16;
+               if (log)
+                       printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
        } else if (rq->errors) {
-#if IDESCSI_DEBUG_LOG
-               printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
                pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
+               if (log)
+                       printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
        } else {
-#if IDESCSI_DEBUG_LOG
-               printk ("ide-scsi: %s: success for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
                pc->scsi_cmd->result = DID_OK << 16;
                idescsi_transform_pc2 (drive, pc);
+               if (log) {
+                       printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
+                       if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
+                               printk(", rst = ");
+                               hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
+                       } else printk("\n");
+               }
        }
        pc->done(pc->scsi_cmd);
        idescsi_free_bh (rq->bh);
@@ -274,9 +324,8 @@ static void idescsi_pc_intr (ide_drive_t *drive)
        status = GET_STAT();                                            /* Clear the interrupt */
 
        if ((status & DRQ_STAT) == 0) {                                 /* No more interrupts */
-#if IDESCSI_DEBUG_LOG
-               printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-#endif /* IDESCSI_DEBUG_LOG */
+               if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+                       printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
                ide_sti();
                if (status & ERR_STAT)
                        rq->errors++;
@@ -306,11 +355,13 @@ static void idescsi_pc_intr (ide_drive_t *drive)
                }
        }
        if (ireason & IDESCSI_IREASON_IO) {
+               clear_bit(PC_WRITING, &pc->flags);
                if (pc->sg)
                        idescsi_input_buffers (drive, pc, bcount);
                else
                        atapi_input_bytes (drive,pc->current_position,bcount);
        } else {
+               set_bit(PC_WRITING, &pc->flags);
                if (pc->sg)
                        idescsi_output_buffers (drive, pc, bcount);
                else
@@ -421,7 +472,8 @@ static void idescsi_add_settings(ide_drive_t *drive)
        ide_add_setting(drive,  "bios_cyl",     SETTING_RW,     -1,     -1,             TYPE_SHORT,     0,      1023,   1,              1,              &drive->bios_cyl,       NULL);
        ide_add_setting(drive,  "bios_head",    SETTING_RW,     -1,     -1,             TYPE_BYTE,      0,      255,    1,              1,              &drive->bios_head,      NULL);
        ide_add_setting(drive,  "bios_sect",    SETTING_RW,     -1,     -1,             TYPE_BYTE,      0,      63,     1,              1,              &drive->bios_sect,      NULL);
-       ide_add_setting(drive,  "transform",    SETTING_RW,     -1,     -1,             TYPE_INT,       0,      1,      1,              1,              &scsi->transform,       NULL);
+       ide_add_setting(drive,  "transform",    SETTING_RW,     -1,     -1,             TYPE_INT,       0,      3,      1,              1,              &scsi->transform,       NULL);
+       ide_add_setting(drive,  "log",          SETTING_RW,     -1,     -1,             TYPE_INT,       0,      1,      1,              1,              &scsi->log,             NULL);
 }
 
 /*
@@ -437,7 +489,11 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
        scsi->drive = drive;
        if (drive->id && (drive->id->config & 0x0060) == 0x20)
                set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
-       scsi->transform = 1;
+       set_bit(IDESCSI_TRANSFORM, &scsi->transform);
+       clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+#if IDESCSI_DEBUG_LOG
+       set_bit(IDESCSI_LOG_CMD, &scsi->log);
+#endif /* IDESCSI_DEBUG_LOG */
        idescsi_add_settings(drive);
 }
 
@@ -554,6 +610,19 @@ const char *idescsi_info (struct Scsi_Host *host)
        return "SCSI host adapter emulation for IDE ATAPI devices";
 }
 
+int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
+{
+       ide_drive_t *drive = idescsi_drives[dev->id];
+       idescsi_scsi_t *scsi = drive->driver_data;
+
+       if (cmd == SG_SET_TRANSFORM) {
+               set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+               return 0;
+       } else if (cmd == SG_GET_TRANSFORM)
+               return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int *) arg);
+       return -EINVAL;
+}
+
 static inline struct buffer_head *idescsi_kmalloc_bh (int count)
 {
        struct buffer_head *bh, *bhp, *first_bh;
@@ -624,20 +693,27 @@ static inline struct buffer_head *idescsi_dma_bh (ide_drive_t *drive, idescsi_pc
        return first_bh;
 }
 
+static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
+{
+       idescsi_scsi_t *scsi = drive->driver_data;
+
+       if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
+               return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+       return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
+}
+
 int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
        ide_drive_t *drive = idescsi_drives[cmd->target];
+       idescsi_scsi_t *scsi;
        struct request *rq = NULL;
        idescsi_pc_t *pc = NULL;
 
-#if IDESCSI_DEBUG_LOG
-       printk ("idescsi_queue called, serial = %lu, cmd[0] = %x, id = %d\n", cmd->serial_number, cmd->cmnd[0], cmd->target);
-#endif /* IDESCSI_DEBUG_LOG */
-
        if (!drive) {
                printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
                goto abort;
        }
+       scsi = drive->driver_data;
        pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
        rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
        if (rq == NULL || pc == NULL) {
@@ -661,8 +737,20 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
        pc->scsi_cmd = cmd;
        pc->done = done;
        pc->timeout = jiffies + cmd->timeout_per_command;
+
+       if (should_transform(drive, cmd))
+               set_bit(PC_TRANSFORM, &pc->flags);
        idescsi_transform_pc1 (drive, pc);
 
+       if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
+               printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
+               hexdump(cmd->cmnd, cmd->cmd_len);
+               if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
+                       printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
+                       hexdump(pc->c, 12);
+               }
+       }
+
        ide_init_drive_cmd (rq);
        rq->buffer = (char *) pc;
        rq->bh = idescsi_dma_bh (drive, pc);
index 360850d75967a2975deea7316896e53199cd5eef..84fab92638ab4bbea2be8a31d5fc7728f90ee793 100644 (file)
@@ -10,6 +10,7 @@
 extern int idescsi_detect (Scsi_Host_Template *host_template);
 extern int idescsi_release (struct Scsi_Host *host);
 extern const char *idescsi_info (struct Scsi_Host *host);
+extern int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
 extern int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
 extern int idescsi_abort (Scsi_Cmnd *cmd);
 extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
@@ -20,6 +21,7 @@ extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
        detect:          idescsi_detect,        /* detect       */              \
        release:         idescsi_release,       /* release      */              \
        info:            idescsi_info,          /* info         */              \
+       ioctl:           idescsi_ioctl,         /* ioctl        */              \
        queuecommand:    idescsi_queue,         /* queuecommand */              \
        abort:           idescsi_abort,         /* abort        */              \
        reset:           idescsi_reset,         /* reset        */              \
@@ -28,7 +30,8 @@ extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
        this_id:         -1,                    /* this_id      */              \
        sg_tablesize:    256,                   /* sg_tablesize */              \
        cmd_per_lun:     5,                     /* cmd_per_lun  */              \
-       use_clustering:  DISABLE_CLUSTERING     /* clustering   */              \
+       use_clustering:  DISABLE_CLUSTERING,    /* clustering   */              \
+       emulated:        1                      /* emulated     */              \
 }
 
 #endif /* IDESCSI_H */
index a26d4200bb847e8222e9a233128075c2f67c595c..7e11430d4802fb36d46183d80fa8929bc21bba12 100644 (file)
 
 #include <linux/blk.h>
 #include <linux/stat.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "sd.h"
@@ -1638,7 +1639,14 @@ DB(DB_INTR,printk("} "))
 
 }
 
+static void do_in2000_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+   unsigned long flags;
 
+   spin_lock_irqsave(&io_request_lock, flags);
+   in2000_intr(irq, dev_id, regs);
+   spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 #define RESET_CARD         0
 #define RESET_CARD_AND_BUS 1
@@ -2064,7 +2072,7 @@ char buf[32];
       write1_io(0,IO_FIFO_READ);             /* start fifo out in read mode */
       write1_io(0,IO_INTR_MASK);    /* allow all ints */
       x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
-      if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", NULL)) {
+      if (request_irq(x, do_in2000_intr, SA_INTERRUPT, "in2000", NULL)) {
          printk("in2000_detect: Unable to allocate IRQ.\n");
          detect_count--;
          continue;
index e7d1470ae882514dfaaab9791fb80df2c28817d2..a779a3b2b32e9f401115a826008bbbc819741315 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -57,6 +58,7 @@ static struct fsc_state *all_53c94s;
 static void mac53c94_init(struct fsc_state *);
 static void mac53c94_start(struct fsc_state *);
 static void mac53c94_interrupt(int, void *, struct pt_regs *);
+static void do_mac53c94_interrupt(int, void *, struct pt_regs *);
 static void cmd_done(struct fsc_state *, int result);
 static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
 static int data_goes_out(Scsi_Cmnd *);
@@ -117,7 +119,7 @@ mac53c94_detect(Scsi_Host_Template *tp)
                *prev_statep = state;
                prev_statep = &state->next;
 
-               if (request_irq(state->intr, mac53c94_interrupt, 0,
+               if (request_irq(state->intr, do_mac53c94_interrupt, 0,
                                "53C94", state)) {
                        printk(KERN_ERR "mac53C94: can't get irq %d\n", state->intr);
                }
@@ -270,6 +272,16 @@ mac53c94_start(struct fsc_state *state)
                set_dma_cmds(state, cmd);
 }
 
+static void
+do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       mac53c94_interrupt(irq, dev_id, ptregs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static void
 mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
index 501aff777558c5aac1ed224729e3d8a67c698102..1f134d797eac378ee70b0b8991677f2a23330360 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -138,6 +139,7 @@ static void phase_mismatch(struct mesh_state *);
 static void reselected(struct mesh_state *);
 static void handle_reset(struct mesh_state *);
 static void mesh_interrupt(int, void *, struct pt_regs *);
+static void do_mesh_interrupt(int, void *, struct pt_regs *);
 static void handle_msgin(struct mesh_state *);
 static void mesh_done(struct mesh_state *);
 static void mesh_completed(struct mesh_state *, Scsi_Cmnd *);
@@ -207,7 +209,7 @@ mesh_detect(Scsi_Host_Template *tp)
                *prev_statep = ms;
                prev_statep = &ms->next;
 
-               if (request_irq(ms->meshintr, mesh_interrupt, 0, "MESH", ms)) {
+               if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
                        printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
                }
 
@@ -975,6 +977,16 @@ handle_reset(struct mesh_state *ms)
        out_8(&mr->sync_params, ASYNC_PARAMS);
 }
 
+static void
+do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       mesh_interrupt(irq, dev_id, ptregs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static void
 mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
index f794d321e31ff7aadb18ff979ef563f3e053a873..004d0a2c8d773ca87cb08cb65639fb24d948fd72 100644 (file)
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -557,6 +558,7 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
 #else
 static void ncr53c8xx_intr(int irq, struct pt_regs * regs);
 #endif
@@ -4612,10 +4614,10 @@ printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
        if (bootverbose > 1)
                printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
                        ncr_name(np), device->slot.irq, (u_long) np);
-       if (request_irq(device->slot.irq, ncr53c8xx_intr,
+       if (request_irq(device->slot.irq, do_ncr53c8xx_intr,
                        SA_INTERRUPT|SA_SHIRQ, "ncr53c8xx", np)) {
 #else
-       if (request_irq(device->slot.irq, ncr53c8xx_intr,
+       if (request_irq(device->slot.irq, do_ncr53c8xx_intr,
                        SA_INTERRUPT, "ncr53c8xx", np)) {
 #endif
 #else
@@ -9799,6 +9801,14 @@ static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
      spin_unlock_irqrestore(&io_request_lock, flags);
      if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
 }
+static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+     unsigned long flags;
+
+     spin_lock_irqsave(&io_request_lock, flags);
+     ncr53c8xx_intr(irq, dev_id, regs);
+     spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 #else
 static void ncr53c8xx_intr(int irq, struct pt_regs * regs)
index c126030d9f8d6c6788327cd96fb239474afd191a..0414f19ffc74200f68a4126df8e4b1406b639236 100644 (file)
@@ -426,7 +426,7 @@ __initfunc(int pas16_detect(Scsi_Host_Template * tpnt)) {
            instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
 
        if (instance->irq != IRQ_NONE) 
-           if (request_irq(instance->irq, pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
+           if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
                printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
                    instance->host_no, instance->irq);
                instance->irq = IRQ_NONE;
index 308f2647353c2733a89f0db9c525761512b4bd9e..fd8b83df647da56e5bdf0dba0942e1cb2cc32dd1 100644 (file)
@@ -186,6 +186,7 @@ int pas16_proc_info (char *buffer ,char **start, off_t offset,
 
 
 #define NCR5380_intr pas16_intr
+#define do_NCR5380_intr do_pas16_intr
 #define NCR5380_queue_command pas16_queue_command
 #define NCR5380_abort pas16_abort
 #define NCR5380_reset pas16_reset
index 8c3d67c1775d3d41131d56792fd45714bffd85e7..86798b27c80d8eb6cf8d807e69124f779270392e 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -466,6 +467,14 @@ finished:;
                OpDone (SCpnt, rc << 16);
        return 0;
        }
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+       {
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       Irq_Handler(irq, dev_id, regs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+       }
 /****************************************************************
  *     Name:   internal_done :LOCAL
  *
@@ -552,7 +561,7 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
                                }
                        if ( setirq )                                                                                                                           // if not shared, posses
                                {
-                               if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2000", NULL) )
+                               if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2000", NULL) )
                                        {
                                        printk ("Unable to allocate IRQ for PSI-2000 controller.\n");
                                        goto unregister;
index 128976a9a5a283b2d41969ce644184ac54477782..3a109fc804999312b85893268b512c37ba652847 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -431,6 +432,14 @@ irqerror:;
        SCpnt->result = DecodeError (shost, status);
        SCpnt->scsi_done (SCpnt);
        }
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+       {
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       Irq_Handler(irq, dev_id, regs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+       }
 /****************************************************************
  *     Name:   Pci2220i_QueueCommand
  *
@@ -691,7 +700,7 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt)
                                }
                        if ( setirq )                                                                                                                           // if not shared, posses
                                {
-                               if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2220i", NULL) )
+                               if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2220i", NULL) )
                                        {
                                        printk ("Unable to allocate IRQ for PSI-2220I controller.\n");
                                        goto unregister;
index 8e12f4b2311d2962e25a813862c367767e9efe55..a2cdbfd549e65c5a25291388cff1e275612204a4 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -370,6 +371,14 @@ irqerror:;
        SCpnt->result = DecodeError (shost, status);
        SCpnt->scsi_done (SCpnt);
        }
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+       {
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       Irq_Handler(irq, dev_id, regs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+       }
 /****************************************************************
  *     Name:   Psi240i_QueueCommand
  *
@@ -595,7 +604,7 @@ int Psi240i_Detect (Scsi_Host_Template *tpnt)
 
                save_flags (flags);
                cli ();
-               if ( request_irq (chipConfig.irq, Irq_Handler, 0, "psi240i", NULL) )
+               if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", NULL) )
                        {
                        printk ("Unable to allocate IRQ for PSI-240I controller.\n");
                        restore_flags (flags);
index e01cd5e2aeb0379fbce260a6f159f91aac2bf162..4279ee6f380ca65a03f4e6ac0bc3febb423950b2 100644 (file)
 #include <linux/unistd.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 #include "sd.h"
 #include "hosts.h"
 #include "qlogicfas.h"
@@ -446,7 +447,7 @@ rtrc(0)
 #if QL_USE_IRQ
 /*----------------------------------------------------------------*/
 /* interrupt handler */
-static void           ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
+static void        ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
 {
 Scsi_Cmnd         *icmd;
        REG0;
@@ -464,6 +465,15 @@ Scsi_Cmnd     *icmd;
 /* if result is CHECK CONDITION done calls qcommand to request sense */
        (icmd->scsi_done) (icmd);
 }
+
+static void        do_ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       ql_ihandl(irq, dev_id, regs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+}
 #endif
 
 /*----------------------------------------------------------------*/
@@ -609,7 +619,7 @@ host->proc_dir =  &proc_scsi_qlogicfas;
        else
                printk( "Ql: Using preset IRQ %d\n", qlirq );
 
-       if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL))
+       if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL))
                host->can_queue = 1;
 #endif
        request_region( qbase , 0x10 ,"qlogicfas");
index 4a0d34e13c6234e4974b69308854176ba247f746..7044d6ad1bf575a012cdace7c0f3c096456ad205 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/unistd.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 
 #include "sd.h"
 #include "hosts.h"
@@ -516,6 +517,7 @@ static int  isp1020_load_parameters(struct Scsi_Host *);
 static int     isp1020_mbox_command(struct Scsi_Host *, u_short []); 
 static int     isp1020_return_status(struct Status_Entry *);
 static void    isp1020_intr_handler(int, void *, struct pt_regs *);
+static void    do_isp1020_intr_handler(int, void *, struct pt_regs *);
 
 #if USE_NVRAM_DEFAULTS
 static int     isp1020_get_defaults(struct Scsi_Host *);
@@ -585,7 +587,7 @@ int isp1020_detect(Scsi_Host_Template *tmpt)
 
                host->this_id = hostdata->host_param.initiator_scsi_id;
 
-               if (request_irq(host->irq, isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
+               if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
                                "qlogicisp", host))
                {
                        printk("qlogicisp : interrupt %d already in use\n",
@@ -801,6 +803,15 @@ int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
 
 #define ASYNC_EVENT_INTERRUPT  0x01
 
+void do_isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       isp1020_intr_handler(irq, dev_id, regs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
        Scsi_Cmnd *Cmnd;
index ab6c12f5ca3c8c35a8302683eeb82b09c0f9f8b2..33ab799edaf95c44d7ed6ffc5359a5eafc332b63 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/machines.h>
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
@@ -562,6 +563,7 @@ static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
 }
 
 static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
+static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
 
 /* Detect all PTI Qlogic ISP's in the machine. */
 __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
@@ -669,7 +671,7 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
                                        goto qpti_irq_acquired; /* BASIC rulez */
                                }
                        }
-                       if(request_irq(qpti->qhost->irq, qlogicpti_intr_handler,
+                       if(request_irq(qpti->qhost->irq, do_qlogicpti_intr_handler,
                                       SA_SHIRQ, "PTI Qlogic/ISP SCSI", NULL)) {
                                printk("Cannot acquire PTI Qlogic/ISP irq line\n");
                                /* XXX Unmap regs, unregister scsi host, free things. */
@@ -685,7 +687,7 @@ qpti_irq_acquired:
                        dcookie.imap = dcookie.iclr = 0;
                        dcookie.pil = -1;
                        dcookie.bus_cookie = sbus;
-                       if(request_irq(qpti->qhost->irq, qlogicpti_intr_handler,
+                       if(request_irq(qpti->qhost->irq, do_qlogicpti_intr_handler,
                                       (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
                                       "PTI Qlogic/ISP SCSI", &dcookie)) {
                                printk("Cannot acquire PTI Qlogic/ISP irq line\n");
@@ -1040,6 +1042,15 @@ static int qlogicpti_return_status(struct Status_Entry *sts)
        return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
 }
 
+static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_request_lock, flags);
+       qlogicpti_intr_handler(irq, dev_id, regs);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 #ifndef __sparc_v9__
 
 static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
index e6036eea4edd3c53f8be427e56577aa0f07ad687..97eefddd9bb0867994c958b48e1d97a2487c7b36 100644 (file)
@@ -332,7 +332,6 @@ void
 scsi_make_blocked_list(void)  
 {
     int block_count = 0, index;
-    unsigned long flags;
     struct Scsi_Host * sh[128], * shpnt;
 
     /*
@@ -1078,7 +1077,6 @@ Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
     kdev_t dev;
     struct request * req = NULL;
     int tablesize;
-    unsigned long flags;
     struct buffer_head * bh, *bhp;
     struct Scsi_Host * host;
     Scsi_Cmnd * SCpnt = NULL;
@@ -1278,7 +1276,6 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
 #ifdef DEBUG_DELAY
     unsigned long clock;
 #endif
-    unsigned long        flags;
     struct Scsi_Host   * host;
     int                  rtn = 0;
     unsigned long        timeout;
@@ -1373,7 +1370,9 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
        SCpnt->result = temp;
 #ifdef DEBUG_DELAY
        clock = jiffies + 4 * HZ;
+       spin_unlock_irq(&io_request_lock);
        while (jiffies < clock) barrier();
+       spin_lock_irq(&io_request_lock);
        printk("done(host = %d, result = %04x) : routine at %p\n",
               host->host_no, temp, host->hostt->command);
 #endif
@@ -1401,7 +1400,6 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
                  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
                  int timeout, int retries)
 {
-    unsigned long flags;
     struct Scsi_Host * host = SCpnt->host;
     Scsi_Device      * device = SCpnt->device;
 
@@ -1795,7 +1793,6 @@ static void scsi_unregister_host(Scsi_Host_Template *);
 void *scsi_malloc(unsigned int len)
 {
     unsigned int nbits, mask;
-    unsigned long flags;
     int i, j;
     if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
        return NULL;
@@ -1821,7 +1818,6 @@ void *scsi_malloc(unsigned int len)
 int scsi_free(void *obj, unsigned int len)
 {
     unsigned int page, sector, nbits, mask;
-    unsigned long flags;
 
 #ifdef DEBUG
     unsigned long ret = 0;
@@ -2400,7 +2396,6 @@ static void resize_dma_pool(void)
     struct Scsi_Host * shpnt;
     struct Scsi_Host * host = NULL;
     Scsi_Device * SDpnt;
-    unsigned long flags;
     FreeSectorBitmap * new_dma_malloc_freelist = NULL;
     unsigned int new_dma_sectors = 0;
     unsigned int new_need_isa_buffer = 0;
@@ -2709,7 +2704,6 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
  */
 static void scsi_unregister_host(Scsi_Host_Template * tpnt)
 {
-    unsigned long                 flags;
     int                           online_status;
     int                           pcount;
     Scsi_Cmnd                   * SCpnt;
index eafaf6a00f744d0716f161533d9493c0fdf72b1e..8f6aff9850d154b65e58e80860a55192caf41399 100644 (file)
@@ -96,6 +96,7 @@ static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
 
 static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
 {
+    unsigned long flags;
     int result;
     Scsi_Cmnd * SCpnt;
     Scsi_Device * SDpnt;
@@ -105,9 +106,11 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
     {
        struct semaphore sem = MUTEX_LOCKED;
        SCpnt->request.sem = &sem;
+       spin_lock_irqsave(&io_request_lock, flags);
        scsi_do_cmd(SCpnt,  cmd, NULL,  0,
                    scsi_ioctl_done,  MAX_TIMEOUT,
                    MAX_RETRIES);
+       spin_unlock_irqrestore(&io_request_lock, flags);
        down(&sem);
         SCpnt->request.sem = NULL;
     }
@@ -166,6 +169,7 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
  */
 static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
 {
+    unsigned long flags;
     char * buf;
     unsigned char cmd[12]; 
     char * cmd_in;
@@ -271,8 +275,10 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
     {
        struct semaphore sem = MUTEX_LOCKED;
        SCpnt->request.sem = &sem;
+       spin_lock_irqsave(&io_request_lock, flags);
        scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
                    timeout, retries);
+       spin_unlock_irqrestore(&io_request_lock, flags);
        down(&sem);
         SCpnt->request.sem = NULL;
     }
@@ -405,6 +411,8 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
        return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
        break;
     default :           
+       if (dev->host->hostt->ioctl)
+               return dev->host->hostt->ioctl(dev, cmd, arg);
        return -EINVAL;
     }
     return -EINVAL;
index 5f4d401729f0f2e66d2dd274e1866bd07da314ba..fcb3348d471a0f88aa3f995b781d53a493eb8d60 100644 (file)
@@ -143,7 +143,9 @@ static void scsi_dump_status(void);
 
 void scsi_old_times_out (Scsi_Cmnd * SCpnt)
 {
+    unsigned long flags;
 
+    spin_lock_irqsave(&io_request_lock, flags);
     switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
     {
     case NORMAL_TIMEOUT:
@@ -154,12 +156,12 @@ void scsi_old_times_out (Scsi_Cmnd * SCpnt)
        }
 
        if (!scsi_abort (SCpnt, DID_TIME_OUT))
-           return;
+           break;
     case IN_ABORT:
        printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
               SCpnt->host->host_no, SCpnt->pid);
        if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
-           return;
+           break;
     case IN_RESET:
     case (IN_ABORT | IN_RESET):
        /* This might be controversial, but if there is a bus hang,
@@ -173,7 +175,7 @@ void scsi_old_times_out (Scsi_Cmnd * SCpnt)
        SCpnt->internal_timeout |= IN_RESET2;
         scsi_reset (SCpnt,
                    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
-        return;
+        break;
     case (IN_ABORT | IN_RESET | IN_RESET2):
        /* Obviously the bus reset didn't work.
         * Let's try even harder and call for an HBA reset.
@@ -185,28 +187,29 @@ void scsi_old_times_out (Scsi_Cmnd * SCpnt)
        SCpnt->internal_timeout |= IN_RESET3;
         scsi_reset (SCpnt,
                    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
-       return;
+       break;
 
     default:
        printk("SCSI host %d reset (pid %ld) timed out again -\n",
               SCpnt->host->host_no, SCpnt->pid);
        printk("probably an unrecoverable SCSI bus or device hang.\n");
-       return;
+       break;
 
     }
+    spin_unlock_irqrestore(&io_request_lock, flags);
 
 }
 
-
+/*
+ *  From what I can find in scsi_obsolete.c, this function is only called
+ *  by scsi_old_done and scsi_reset.  Both of these functions run with the
+ *  io_request_lock already held, so we need do nothing here about grabbing
+ *  any locks.
+ */
 static void scsi_request_sense (Scsi_Cmnd * SCpnt)
 {
-    unsigned long flags;
-
-    save_flags(flags);
-    cli();
     SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
     update_timeout(SCpnt, SENSE_TIMEOUT);
-    restore_flags(flags);
 
 
     memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
@@ -688,28 +691,25 @@ void scsi_old_done (Scsi_Cmnd * SCpnt)
 static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
 {
     int oldto;
-    unsigned long flags;
     struct Scsi_Host * host = SCpnt->host;
 
     while(1)
     {
-       save_flags(flags);
-       cli();
 
        /*
         * Protect against races here.  If the command is done, or we are
         * on a different command forget it.
         */
        if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
-           restore_flags(flags);
            return 0;
        }
 
        if (SCpnt->internal_timeout & IN_ABORT)
        {
-           restore_flags(flags);
+           spin_unlock_irq(&io_request_lock);
            while (SCpnt->internal_timeout & IN_ABORT)
                barrier();
+           spin_lock_irq(&io_request_lock);
        }
        else
        {
@@ -725,7 +725,6 @@ static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
                       SCpnt->channel, SCpnt->target, SCpnt->lun);
            }
 
-           restore_flags(flags);
            if (!host->host_busy) {
                SCpnt->internal_timeout &= ~IN_ABORT;
                update_timeout(SCpnt, oldto);
@@ -749,11 +748,8 @@ static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
                                   */
            case SCSI_ABORT_SNOOZE:
                if(why == DID_TIME_OUT) {
-                   save_flags(flags);
-                   cli();
                    SCpnt->internal_timeout &= ~IN_ABORT;
                    if(SCpnt->flags & WAS_TIMEDOUT) {
-                       restore_flags(flags);
                        return 1; /* Indicate we cannot handle this.
                                   * We drop down into the reset handler
                                   * and try again
@@ -763,15 +759,11 @@ static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
                        oldto = SCpnt->timeout_per_command;
                        update_timeout(SCpnt, oldto);
                    }
-                   restore_flags(flags);
                }
                return 0;
            case SCSI_ABORT_PENDING:
                if(why != DID_TIME_OUT) {
-                   save_flags(flags);
-                   cli();
                    update_timeout(SCpnt, oldto);
-                   restore_flags(flags);
                }
                return 0;
            case SCSI_ABORT_SUCCESS:
@@ -837,7 +829,6 @@ static void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
 static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
     int temp;
-    unsigned long flags;
     Scsi_Cmnd * SCpnt1;
     Scsi_Device * SDpnt;
     struct Scsi_Host * host = SCpnt->host;
@@ -894,8 +885,6 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 #endif
 
     while (1) {
-       save_flags(flags);
-       cli();
 
        /*
         * Protect against races here.  If the command is done, or we are
@@ -903,15 +892,15 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
         */
        if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
          if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
-           restore_flags(flags);
            return 0;
          }
 
        if (SCpnt->internal_timeout & IN_RESET)
        {
-           restore_flags(flags);
+           spin_unlock_irq(&io_request_lock);
            while (SCpnt->internal_timeout & IN_RESET)
                barrier();
+           spin_lock_irq(&io_request_lock);
        }
        else
        {
@@ -920,7 +909,6 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 
            if (host->host_busy)
            {
-               restore_flags(flags);
                 for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
                 {
                     SCpnt1 = SDpnt->device_queue;
@@ -955,7 +943,6 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
            else
            {
                if (!host->block) host->host_busy++;
-               restore_flags(flags);
                host->last_reset = jiffies;
                SCpnt->flags |= (WAS_RESET | IS_RESETTING);
                temp = host->hostt->reset(SCpnt, reset_flags);
@@ -985,10 +972,7 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
                else if (temp & SCSI_RESET_BUS_RESET)
                  scsi_mark_bus_reset(host, SCpnt->channel);
                else scsi_mark_device_reset(SCpnt->device);
-               save_flags(flags);
-               cli();
                SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-               restore_flags(flags);
                return 0;
            case SCSI_RESET_PENDING:
                if (temp & SCSI_RESET_HOST_RESET)
@@ -1048,11 +1032,8 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
                 * and we return 1 so that we get a message on the
                 * screen.
                 */
-               save_flags(flags);
-               cli();
                SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
                update_timeout(SCpnt, 0);
-               restore_flags(flags);
                /* If you snooze, you lose... */
            case SCSI_RESET_ERROR:
            default:
index e0838ba1786c193fbb0e47c9aa0629cdcf2532c5..09c3407d6bf71874c6590c2edef7b0b514137c33 100644 (file)
@@ -269,6 +269,15 @@ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
     }
 }
 
+static void
+do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    DC390_Interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 static void
 DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
index d532c13e4224330458faa5ca655bbc1c0ad039ba..2cd06a2d901f51fcb3696406853383f6bdfd0543 100644 (file)
@@ -91,6 +91,7 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -343,6 +344,7 @@ static const Signature signatures[] =
 
 static int hostno = -1;
 static void seagate_reconnect_intr (int, void *, struct pt_regs *);
+static void do_seagate_reconnect_intr (int, void *, struct pt_regs *);
 
 #ifdef FAST
 static int fast = 1;
@@ -505,7 +507,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt)
  */
     instance = scsi_register (tpnt, 0);
     hostno = instance->host_no;
-    if (request_irq ((int) irq, seagate_reconnect_intr, SA_INTERRUPT,
+    if (request_irq ((int) irq, do_seagate_reconnect_intr, SA_INTERRUPT,
                 (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", NULL))
     {
       printk ("scsi%d : unable to allocate IRQ%d\n", hostno, (int) irq);
@@ -631,6 +633,16 @@ static int should_reconnect = 0;
  * asserting SEL.
  */
 
+static void do_seagate_reconnect_intr (int irq, void *dev_id, 
+                                    struct pt_regs *regs)
+{
+  unsigned long flags;
+
+  spin_lock_irqsave(&io_request_lock, flags);
+  seagate_reconnect_intr(irq, dev_id, regs);
+  spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static void seagate_reconnect_intr (int irq, void *dev_id, 
                                     struct pt_regs *regs)
 {
index a6afe2a2ceefea01bfab3b05b785803f09c7e7bb..782de8fc0f6f24377d9cea47534f5e600b4bfae2 100644 (file)
@@ -95,6 +95,8 @@ static int sg_ioctl(struct inode * inode,struct file * file,
        return 0;
     case SG_GET_TIMEOUT:
        return scsi_generics[dev].timeout;
+    case SG_EMULATED_HOST:
+       return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg);
     default:
        return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
     }
@@ -364,6 +366,7 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
 static ssize_t sg_write(struct file *filp, const char *buf, 
                         size_t count, loff_t *ppos)
 {
+    unsigned long        flags;
     struct inode         *inode = filp->f_dentry->d_inode;
     int                          bsize,size,amt,i;
     unsigned char        cmnd[MAX_COMMAND_SIZE];
@@ -531,9 +534,11 @@ static ssize_t sg_write(struct file *filp, const char *buf,
      * do not do any more here - when the interrupt arrives, we will
      * then do the post-processing.
      */
+    spin_lock_irqsave(&io_request_lock, flags);
     scsi_do_cmd (SCpnt,(void *) cmnd,
                 (void *) device->buff,amt,
                 sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
+    spin_unlock_irqrestore(&io_request_lock, flags);
 
 #ifdef DEBUG
     printk("done cmd\n");
index 48036ed33aee4787303582c6a38ead4e7a44d8ea..5c40b1e7ef7b789dfda9e25b2128f2854584ebc5 100644 (file)
@@ -250,7 +250,7 @@ __initfunc(int t128_detect(Scsi_Host_Template * tpnt)) {
            instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
 
        if (instance->irq != IRQ_NONE) 
-           if (request_irq(instance->irq, t128_intr, SA_INTERRUPT, "t128", NULL)) {
+           if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) {
                printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
                    instance->host_no, instance->irq);
                instance->irq = IRQ_NONE;
index 8f4f27f85e03457ecf95ef963922ebb085ba4217..e3a8b6c90d38e02a99c619cfd6718abf8eeb728e 100644 (file)
@@ -163,6 +163,7 @@ int t128_proc_info (char *buffer, char **start, off_t offset,
 #endif
 
 #define NCR5380_intr t128_intr
+#define do_NCR5380_intr do_t128_intr
 #define NCR5380_queue_command t128_queue_command
 #define NCR5380_abort t128_abort
 #define NCR5380_reset t128_reset
index 06fd935c63792c66da76438852dbc62e2a5df9b1..ae272c215acd8b003eb2a2e5bd4be6577dfd2ac1 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -1157,7 +1158,7 @@ __initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT inde
 
     if( !used_irq )
     {
-       if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
+       if( request_irq(Irq, do_DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
        {
            printk("DC390: register IRQ error!\n");
            return( -1 );
index 20f90e6e0ca4f8e29f84c46b39bb0e291e1d8543..793875190f7822a85b41741478863b56ee3b9117 100644 (file)
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/dma.h>
 
 #define ULTRASTOR_PRIVATE      /* Get the private stuff from ultrastor.h */
@@ -294,6 +295,7 @@ static const unsigned short ultrastor_ports_14f[] = {
 #endif
 
 static void ultrastor_interrupt(int, void *, struct pt_regs *);
+static void do_ultrastor_interrupt(int, void *, struct pt_regs *);
 static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
 
 
@@ -507,7 +509,7 @@ static int ultrastor_14f_detect(Scsi_Host_Template * tpnt)
     config.mscp_free = ~0;
 #endif
 
-    if (request_irq(config.interrupt, ultrastor_interrupt, 0, "Ultrastor", NULL)) {
+    if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", NULL)) {
        printk("Unable to allocate IRQ%u for UltraStor controller.\n",
               config.interrupt);
        return FALSE;
@@ -577,7 +579,7 @@ static int ultrastor_24f_detect(Scsi_Host_Template * tpnt)
          printk("U24F: invalid IRQ\n");
          return FALSE;
        }
-      if (request_irq(config.interrupt, ultrastor_interrupt, 0, "Ultrastor", NULL))
+      if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", NULL))
        {
          printk("Unable to allocate IRQ%u for UltraStor controller.\n",
                 config.interrupt);
@@ -1157,6 +1159,15 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 #endif
 }
 
+static void do_ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    ultrastor_interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 #ifdef MODULE
 /* Eventually this will go into an include file, but this will be later */
 Scsi_Host_Template driver_template = ULTRASTOR_14F;
index beedc539fba652e28c2199b3026f600667dcd43f..89947e8a11d8da3151ce437902b3cce48b53efe5 100644 (file)
 #include <linux/sched.h>
 #include <linux/malloc.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <linux/ioport.h>
@@ -1148,6 +1149,15 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
 #endif
 }
 
+void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    wd7000_intr_handle(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 
 int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
 {
@@ -1314,7 +1324,7 @@ int wd7000_init (Adapter *host)
        return (0);
     }
 
-    if (request_irq (host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
+    if (request_irq (host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
        printk ("wd7000_init: can't get IRQ %d.\n", host->irq);
        return (0);
     }
index d4f13d256a05531e989db58ba09c372b2abe0045..8f1d2bec7f76f92478d0b892c196aee468567994 100644 (file)
@@ -2,6 +2,7 @@ dep_tristate 'ProAudioSpectrum 16 support' CONFIG_PAS $CONFIG_SOUND
 if [ "$CONFIG_PAS" = "y" ]; then
     int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10
     int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' CONFIG_PAS_DMA 3
+    bool 'Enable PAS16 joystick port' CONFIG_PAS_JOYSTICK
 fi
 
 dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND
index 21abba1a83a5cea19cc1df282ccbbcd44e65cd81..62d10257d2cbee50bf1d82ad942f0020ac4ecfb7 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Detection routine for the Gravis Ultrasound.
  */
 /*
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious
+ *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
+ *
+ * Status:
+ *              Tested... 
+ */
+      
 #include <linux/config.h>
 #include <linux/module.h>
 
 void            gusintr(int irq, void *dev_id, struct pt_regs *dummy);
 
 int             gus_base = 0, gus_irq = 0, gus_dma = 0;
+int             gus_no_wave_dma = 0; 
 extern int      gus_wave_volume;
 extern int      gus_pcm_volume;
 extern int      have_gus_max;
 int             gus_pnp_flag = 0;
+#ifdef CONFIG_GUS16
+static int      db16 = 0;      /* Has a Gus16 AD1848 on it */
+#endif
 
 void attach_gus_card(struct address_info *hw_config)
 {
@@ -120,6 +134,10 @@ void gusintr(int irq, void *dev_id, struct pt_regs *dummy)
 
 #ifdef CONFIG_GUSMAX
        if (have_gus_max)
+               adintr(irq, (void *)hw_config->slots[1], NULL);
+#endif
+#ifdef CONFIG_GUS16
+       if (db16)
                adintr(irq, (void *)hw_config->slots[3], NULL);
 #endif
 
@@ -192,6 +210,8 @@ void unload_gus_db16(struct address_info *hw_config)
 }
 #endif
 
+
+
 #ifdef MODULE
 
 static struct address_info config;
@@ -207,7 +227,10 @@ int             dma = -1;
 int             dma16 = -1;    /* Set this for modules that need it */
 int             type = 0;      /* 1 for PnP */
 int             gus16 = 0;
-static int      db16 = 0;      /* Has a Gus16 AD1848 on it */
+#ifdef CONFIG_GUSMAX
+static int      no_wave_dma = 0;/* Set if no dma is to be used for the 
+                                  wave table (GF1 chip) */
+#endif
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
@@ -215,7 +238,12 @@ MODULE_PARM(dma, "i");
 MODULE_PARM(dma16, "i");
 MODULE_PARM(type, "i");
 MODULE_PARM(gus16, "i");
+#ifdef CONFIG_GUSMAX
+MODULE_PARM(no_wave_dma, "i");
+#endif
+#ifdef CONFIG_GUS16
 MODULE_PARM(db16, "i");
+#endif
 
 int init_module(void)
 {
@@ -231,6 +259,10 @@ int init_module(void)
        config.dma = dma;
        config.dma2 = dma16;
        config.card_subtype = type;
+       
+#ifdef CONFIG_GUSMAX
+       gus_no_wave_dma = no_wave_dma;
+#endif
 
 #if defined(CONFIG_GUS16)
        if (probe_gus_db16(&config) && gus16)
index 54e3793fc47cbaed8a933d868d234bc6d5b403db..6dc52aef68ba475ca6c60678f30233e87de64927 100644 (file)
  * for more info.
  */
 /*
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ * Thomas Sailer    : ioctl code reworked (vmalloc/vfree removed)
+ * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
+ *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
  */
 #include <linux/config.h>
 
-
 #define GUSPNP_AUTODETECT
 
 #include "sound_config.h"
@@ -70,10 +73,11 @@ struct voice_info
 };
 
 static struct voice_alloc_info *voice_alloc;
-
+static struct address_info *gus_hw_config;
 extern int      gus_base;
 extern int      gus_irq, gus_dma;
 extern int      gus_pnp_flag;
+extern int      gus_no_wave_dma;
 static int      gus_dma2 = -1;
 static int      dual_dma_mode = 0;
 static long     gus_mem_size = 0;
@@ -833,7 +837,7 @@ static void gus_initialize(void)
 
        gus_select_voice(0);    /* This disables writes to IRQ/DMA reg */
 
-       gusintr(gus_irq, NULL, NULL);   /* Serve pending interrupts */
+       gusintr(gus_irq, (void *)gus_hw_config, NULL);  /* Serve pending interrupts */
 
        inb(u_Status);          /* Touch the status register */
 
@@ -1649,22 +1653,26 @@ static int guswave_open(int dev, int mode)
 
        voice_alloc->timestamp = 0;
 
-       if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
-       {
-               /* printk( "GUS: Loading samples without DMA\n"); */
-               gus_no_dma = 1; /* Upload samples using PIO */
+       if (gus_no_wave_dma) {
+               gus_no_dma = 1;
+       } else {
+               if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
+               {
+                       /* printk( "GUS: Loading samples without DMA\n"); */
+                       gus_no_dma = 1; /* Upload samples using PIO */
+               }
+               else
+                       gus_no_dma = 0;
        }
-       else
-               gus_no_dma = 0;
 
        init_waitqueue(&dram_sleeper);
        gus_busy = 1;
        active_device = GUS_DEV_WAVE;
 
-       gusintr(gus_irq, NULL, NULL);   /* Serve pending interrupts */
+       gusintr(gus_irq, (void *)gus_hw_config, NULL);  /* Serve pending interrupts */
        gus_initialize();
        gus_reset();
-       gusintr(gus_irq, NULL, NULL);   /* Serve pending interrupts */
+       gusintr(gus_irq, (void *)gus_hw_config, NULL);  /* Serve pending interrupts */
 
        return 0;
 }
@@ -2953,6 +2961,7 @@ void gus_wave_init(struct address_info *hw_config)
        gus_irq = irq;
        gus_dma = dma;
        gus_dma2 = dma2;
+       gus_hw_config = hw_config;
 
        if (gus_dma2 == -1)
                gus_dma2 = dma;
@@ -3114,8 +3123,8 @@ void gus_wave_init(struct address_info *hw_config)
        reset_sample_memory();
 
        gus_initialize();
-
-       if (gus_mem_size > 0)
+       
+       if ((gus_mem_size > 0) & !gus_no_wave_dma)
        {
                if ((dev = sound_alloc_audiodev()) != -1)
                {
index 4d4d9e4bd9d39749de1b05c38539fd2ff963dd5a..8eb29e72936b0426cf19bdf3e50582117116fb1a 100644 (file)
@@ -37,6 +37,11 @@ int             translate_code = 0;
 static int      pas_intr_mask = 0;
 static int      pas_irq = 0;
 static int      pas_sb_base = 0;
+#ifndef CONFIG_PAS_JOYSTICK
+static int     joystick = 0;
+#else
+static int     joystick = 1;
+#endif
 
 
 char            pas_model = 0;
@@ -142,9 +147,7 @@ static int config_pas_hw(struct address_info *hw_config)
                                                 */ , 0xB88);
 
        pas_write(0x80
-#ifdef PAS_JOYSTICK_ENABLE
-                 | 0x40
-#endif
+                 | joystick?0x40:0
                  ,0xF388);
 
        if (pas_irq < 0 || pas_irq > 15)
@@ -380,6 +383,8 @@ MODULE_PARM(sb_irq,"i");
 MODULE_PARM(sb_dma,"i");
 MODULE_PARM(sb_dma16,"i");
 
+MODULE_PARM(joystick,"i");
+
 struct address_info config;
 struct address_info sbhw_config;
 
index 8f8579d7c90c15e0d431ea4ba711b9e6ef124b29..bc1da662ee22352190c8b687c4fb1baee3b28dae 100644 (file)
@@ -34,7 +34,7 @@
 
 struct binfmt_entry {
        struct binfmt_entry *next;
-       int id;
+       long id;
        int flags;                      /* type, status, etc. */
        int offset;                     /* offset of magic */
        int size;                       /* size of magic/mask */
@@ -243,7 +243,7 @@ _ret:
 static char *copyarg(char **dp, const char **sp, int *count,
                     char del, int special, int *err)
 {
-       char c, *res = *dp;
+       char c = 0, *res = *dp;
 
        while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
                switch (c) {
@@ -370,7 +370,7 @@ static int proc_read_status(char *page, char **start, off_t off,
        if (!data)
                sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
        else {
-               if (!(e = get_entry((int) data))) {
+               if (!(e = get_entry((long) data))) {
                        err = -ENOENT;
                        goto _err;
                }
@@ -428,7 +428,7 @@ static int proc_write_status(struct file *file, const char *buffer,
                count--;
        if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
                if (data) {
-                       if ((e = get_entry((int) data)))
+                       if ((e = get_entry((long) data)))
                                e->flags = (e->flags & ~ENTRY_ENABLED)
                                            | (int)(buffer[0] - '0');
                        put_entry(e);
@@ -437,7 +437,7 @@ static int proc_write_status(struct file *file, const char *buffer,
                }
        } else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
                if (data)
-                       clear_entry((int) data);
+                       clear_entry((long) data);
                else
                        clear_entries();
        } else {
index 45e4a9cd6dde018831d857730779765072fed40c..12df46a9a7daacadacbc59f09e9d2510140a9c7a 100644 (file)
@@ -1,16 +1,18 @@
 #ifndef __ARM_A_OUT_H__
 #define __ARM_A_OUT_H__
 
+#include <linux/types.h>
+
 struct exec
 {
-  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
-  unsigned a_text;             /* length of text, in bytes */
-  unsigned a_data;             /* length of data, in bytes */
-  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;             /* length of symbol table data in file, in bytes */
-  unsigned a_entry;            /* start address */
-  unsigned a_trsize;           /* length of relocation info for text, in bytes */
-  unsigned a_drsize;           /* length of relocation info for data, in bytes */
+  __u32 a_info;                /* Use macros N_MAGIC, etc for access */
+  __u32 a_text;                /* length of text, in bytes */
+  __u32 a_data;                /* length of data, in bytes */
+  __u32 a_bss;         /* length of uninitialized data area for file, in bytes */
+  __u32 a_syms;                /* length of symbol table data in file, in bytes */
+  __u32 a_entry;       /* start address */
+  __u32 a_trsize;      /* length of relocation info for text, in bytes */
+  __u32 a_drsize;      /* length of relocation info for data, in bytes */
 };
 
 /*
diff --git a/include/asm-arm/arch-a5k/a.out.h b/include/asm-arm/arch-a5k/a.out.h
deleted file mode 100644 (file)
index 0653407..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/a.out.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#ifdef __KERNEL__
-#define STACK_TOP              (0x01a00000)
-#define LIBRARY_START_TEXT     (0x00c00000)
-#endif
-
-#endif
-
diff --git a/include/asm-arm/arch-a5k/dma.h b/include/asm-arm/arch-a5k/dma.h
deleted file mode 100644 (file)
index 9acb5c1..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#define MAX_DMA_ADDRESS                0x03000000
-
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    switch(dmanr) {
-       case 2:  disable_irq(64); break;
-       default: printk (dma_str, "disable_dma", dmanr); break;
-    }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-    switch(dmanr) {
-       case 2:  break;
-       default: printk (dma_str, "clear_dma_ff", dmanr); break;
-    }
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
-
-#endif /* _ASM_ARCH_DMA_H */
-
diff --git a/include/asm-arm/arch-a5k/hardware.h b/include/asm-arm/arch-a5k/hardware.h
deleted file mode 100644 (file)
index 317b4c6..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/hardware.h
- *
- * Copyright (C) 1996 Russell King.
- *
- * This file contains the hardware definitions of the A5000 series machines.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * What hardware must be present
- */
-#define HAS_IOC
-#define HAS_PCIO
-#define HAS_MEMC
-#define HAS_MEMC1A
-#define HAS_VIDC
-
-/*
- * Optional hardware
- */
-#define HAS_EXPMASK
-
-#ifndef __ASSEMBLER__
-
-/*
- * for use with inb/outb
- */
-#define VIDC_BASE              0x80100000
-#define IOCEC4IO_BASE          0x8009c000
-#define IOCECIO_BASE           0x80090000
-#define IOC_BASE               0x80080000
-#define MEMCECIO_BASE          0x80000000
-
-/*
- * IO definitions
- */
-#define EXPMASK_BASE           ((volatile unsigned char *)0x03360000)
-#define IOEB_BASE              ((volatile unsigned char *)0x03350050)
-#define PCIO_FLOPPYDMABASE     ((volatile unsigned char *)0x0302a000)
-#define PCIO_BASE              0x03010000
-
-/*
- * Mapping areas
- */
-#define IO_END                 0x03ffffff
-#define IO_BASE                        0x03000000
-#define IO_SIZE                        (IO_END - IO_BASE)
-#define IO_START               0x03000000
-
-/*
- * Screen mapping information
- */
-#define SCREEN2_END            0x02078000
-#define SCREEN2_BASE           0x02000000
-#define SCREEN1_END            SCREEN2_BASE
-#define SCREEN1_BASE           0x01f88000
-#define SCREEN_START           0x02000000
-
-/*
- * RAM definitions
- */
-#define MAPTOPHYS(a)           (((unsigned long)a & 0x007fffff) + PAGE_OFFSET)
-#define KERNTOPHYS(a)          ((((unsigned long)(&a)) & 0x007fffff) + PAGE_OFFSET)
-#define GET_MEMORY_END(p)      (PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
-#define PARAMS_BASE            (PAGE_OFFSET + 0x7c000)
-#define KERNEL_BASE            (PAGE_OFFSET + 0x80000)
-
-#else
-
-#define IOEB_BASE              0x03350050
-#define IOC_BASE               0x03200000
-#define PCIO_FLOPPYDMABASE     0x0302a000
-#define PCIO_BASE              0x03010000
-#define IO_BASE                        0x03000000
-
-#endif
-#endif
-
diff --git a/include/asm-arm/arch-a5k/ide.h b/include/asm-arm/arch-a5k/ide.h
deleted file mode 100644 (file)
index 3beb3c3..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/ide.h
- *
- * Copyright (c) 1997 Russell King
- */
-
-static __inline__ int
-ide_default_irq(ide_ioreg_t base)
-{
-       if (base == 0x1f0)
-               return 11;
-       return 0;
-}
-
-static __inline__ ide_ioreg_t
-ide_default_io_base(int index)
-{
-       if (index == 0)
-               return 0x1f0;
-       return 0;
-}
-
-static __inline__ int
-ide_default_stepping(int index)
-{
-       return 0;
-}
-
-static __inline__ void
-ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int stepping, int *irq)
-{
-       ide_ioreg_t port = base;
-       ide_ioreg_t ctrl = base + 0x206;
-       int i;
-
-       i = 8;
-       while (i--) {
-               *p++ = port;
-               port += 1 << stepping;
-       }
-       *p++ = ctrl;
-       if (irq != NULL)
-               irq = 0;
-}
diff --git a/include/asm-arm/arch-a5k/io.h b/include/asm-arm/arch-a5k/io.h
deleted file mode 100644 (file)
index b305c7d..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/io.h
- *
- * Copyright (C) 1997 Russell King
- *
- * Modifications:
- *  06-Dec-1997        RMK     Created.
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x) ((unsigned long)(x))
-#define bus_to_virt(x) ((void *)(x))
-
-/*
- * This architecture does not require any delayed IO, and
- * has the constant-optimised IO
- */
-#undef ARCH_IO_DELAY
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses.  PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
- * and are translated to the start of IO.  Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x) (!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-extern __inline__ void __outb (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "strb   %1, [%0, %2, lsl #2]"
-       : "=&r" (temp)
-       : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-extern __inline__ void __outw (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "str    %1, [%0, %2, lsl #2]"
-       : "=&r" (temp)
-       : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-extern __inline__ void __outl (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "str    %1, [%0, %2, lsl #2]"
-       : "=&r" (temp)
-       : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr)                                      \
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)               \
-{                                                                              \
-       unsigned long temp, value;                                              \
-       __asm__ __volatile__(                                                   \
-       "tst    %2, #0x80000000\n\t"                                            \
-       "mov    %0, %4\n\t"                                                     \
-       "addeq  %0, %0, %3\n\t"                                                 \
-       "ldr" ##instr## "       %1, [%0, %2, lsl #2]"                           \
-       : "=&r" (temp), "=r" (value)                                            \
-       : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)                \
-       : "cc");                                                                \
-       return (unsigned sz)value;                                              \
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port)                    \
-{                                                                              \
-       if (__PORT_PCIO(port))                                                  \
-               return (unsigned int)(PCIO_BASE + (port << 2));                 \
-       else                                                                    \
-               return (unsigned int)(IO_BASE + (port << 2));                   \
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr)  \
-       DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)                                                    \
-({                                                                             \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "strb   %0, [%1, %2]"                                           \
-               : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2));          \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "strb   %0, [%1, %2]"                                           \
-               : : "r" (value), "r" (IO_BASE), "r" ((port) << 2));             \
-})
-
-#define __inbc(port)                                                           \
-({                                                                             \
-       unsigned char result;                                                   \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldrb   %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldrb   %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result;                                                                 \
-})
-
-#define __outwc(value,port)                                                    \
-({                                                                             \
-       unsigned long v = value;                                                \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "str    %0, [%1, %2]"                                           \
-               : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2));        \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "str    %0, [%1, %2]"                                           \
-               : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2));           \
-})
-
-#define __inwc(port)                                                           \
-({                                                                             \
-       unsigned short result;                                                  \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result & 0xffff;                                                        \
-})
-
-#define __outlc(v,p) __outwc((v),(p))
-
-#define __inlc(port)                                                           \
-({                                                                             \
-       unsigned long result;                                                   \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result;                                                                 \
-})
-
-#define __ioaddrc(port)                                                                \
-({                                                                             \
-       unsigned long addr;                                                     \
-       if (__PORT_PCIO((port)))                                                \
-               addr = PCIO_BASE + ((port) << 2);                               \
-       else                                                                    \
-               addr = IO_BASE + ((port) << 2);                                 \
-       addr;                                                                   \
-})
-
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p)                                                            \
-       (*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p)                                                               \
-       (*(volatile unsigned char *)(p))
-
-#define outl_t(v,p)                                                            \
-       (*(volatile unsigned long *)(p) = (v))
-
-#define inl_t(p)                                                               \
-       (*(volatile unsigned long *)(p))
-
-#endif
diff --git a/include/asm-arm/arch-a5k/irq.h b/include/asm-arm/arch-a5k/irq.h
deleted file mode 100644 (file)
index 6c868d8..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * include/asm-arm/arch-a5k/irq.h
- *
- * Copyright (C) 1996 Russell King
- *
- * Changelog:
- *   24-09-1996        RMK     Created
- *   10-10-1996        RMK     Brought up to date with arch-sa110eval
- *   22-10-1996        RMK     Changed interrupt numbers & uses new inb/outb macros
- *   11-01-1998        RMK     Added mask_and_ack_irq
- */
-
-#define BUILD_IRQ(s,n,m) \
-       void IRQ##n##_interrupt(void); \
-       void fast_IRQ##n##_interrupt(void); \
-       void bad_IRQ##n##_interrupt(void); \
-       void probe_IRQ##n##_interrupt(void);
-
-/*
- * The timer is a special interrupt
- */
-#define IRQ5_interrupt         timer_IRQ_interrupt
-
-#define IRQ_INTERRUPT(n)       IRQ##n##_interrupt
-#define FAST_INTERRUPT(n)      fast_IRQ##n##_interrupt
-#define BAD_INTERRUPT(n)       bad_IRQ##n##_interrupt
-#define PROBE_INTERRUPT(n)     probe_IRQ##n##_interrupt
-                                
-#define X(x) (x)|0x01, (x)|0x02, (x)|0x04, (x)|0x08, (x)|0x10, (x)|0x20, (x)|0x40, (x)|0x80
-#define Z(x) (x), (x), (x), (x), (x), (x), (x), (x)
-
-static __inline__ void mask_and_ack_irq(unsigned int irq)
-{
-       static const int addrmasks[] = {
-               X((IOC_IRQMASKA - IOC_BASE)<<18 | (1 << 15)),
-               X((IOC_IRQMASKB - IOC_BASE)<<18),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               X((IOC_FIQMASK - IOC_BASE)<<18),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0)
-       };
-       unsigned int temp1, temp2;
-
-       __asm__ __volatile__(
-"      ldr     %1, [%5, %3, lsl #2]\n"
-"      teq     %1, #0\n"
-"      beq     2f\n"
-"      ldrb    %0, [%2, %1, lsr #16]\n"
-"      bic     %0, %0, %1\n"
-"      strb    %0, [%2, %1, lsr #16]\n"
-"      tst     %1, #0x8000\n"                  /* do we need an IRQ clear? */
-"      strneb  %1, [%2, %4]\n"
-"2:"
-       : "=&r" (temp1), "=&r" (temp2)
-       : "r" (ioaddr(IOC_BASE)), "r" (irq),
-         "I" ((IOC_IRQCLRA - IOC_BASE) << 2), "r" (addrmasks));
-}
-
-#undef X
-#undef Z
-
-static __inline__ void mask_irq(unsigned int irq)
-{
-       extern void ecard_disableirq (unsigned int);
-       extern void ecard_disablefiq (unsigned int);
-       unsigned char mask = 1 << (irq & 7);
-
-       switch (irq >> 3) {
-       case 0:
-               outb(inb(IOC_IRQMASKA) & ~mask, IOC_IRQMASKA);
-               break;
-       case 1:
-               outb(inb(IOC_IRQMASKB) & ~mask, IOC_IRQMASKB);
-               break;
-       case 4:
-               ecard_disableirq (irq & 7);
-               break;
-       case 8:
-               outb(inb(IOC_FIQMASK) & ~mask, IOC_FIQMASK);
-               break;
-       case 12:
-               ecard_disablefiq (irq & 7);
-       }
-}
-
-static __inline__ void unmask_irq(unsigned int irq)
-{
-       extern void ecard_enableirq (unsigned int);
-       extern void ecard_enablefiq (unsigned int);
-       unsigned char mask = 1 << (irq & 7);
-
-       switch (irq >> 3) {
-       case 0:
-               outb(inb(IOC_IRQMASKA) | mask, IOC_IRQMASKA);
-               break;
-       case 1:
-               outb(inb(IOC_IRQMASKB) | mask, IOC_IRQMASKB);
-               break;
-       case 4:
-               ecard_enableirq (irq & 7);
-               break;
-       case 8:
-               outb(inb(IOC_FIQMASK) | mask, IOC_FIQMASK);
-               break;
-       case 12:
-               ecard_enablefiq (irq & 7);
-       }
-}
-
-static __inline__ unsigned long get_enabled_irqs(void)
-{
-       return inb(IOC_IRQMASKA) | inb(IOC_IRQMASKB) << 8;
-}
-
-static __inline__ void irq_init_irq(void)
-{
-       outb(0, IOC_IRQMASKA);
-       outb(0, IOC_IRQMASKB);
-       outb(0, IOC_FIQMASK);
-}
diff --git a/include/asm-arm/arch-a5k/irqs.h b/include/asm-arm/arch-a5k/irqs.h
deleted file mode 100644 (file)
index b7188fb..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/irqs.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define IRQ_PRINTER            0
-#define IRQ_BATLOW             1
-#define IRQ_FLOPPYINDEX                2
-#define IRQ_VSYNCPULSE         3
-#define IRQ_POWERON            4
-#define IRQ_TIMER0             5
-#define IRQ_TIMER1             6
-#define IRQ_IMMEDIATE          7
-#define IRQ_EXPCARDFIQ         8
-#define IRQ_SOUNDCHANGE                9
-#define IRQ_SERIALPORT         10
-#define IRQ_HARDDISK           11
-#define IRQ_FLOPPYDISK         12
-#define IRQ_EXPANSIONCARD      13
-#define IRQ_KEYBOARDTX         14
-#define IRQ_KEYBOARDRX         15
-
-#define FIQ_FLOPPYDATA         0
-#define FIQ_ECONET             2
-#define FIQ_SERIALPORT         4
-#define FIQ_EXPANSIONCARD      6
-#define FIQ_FORCE              7
diff --git a/include/asm-arm/arch-a5k/mmu.h b/include/asm-arm/arch-a5k/mmu.h
deleted file mode 100644 (file)
index 3c2fb95..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/mmu.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  22-11-1996 RMK     Created
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys(vpage) vpage
-#define __phys_to_virt(ppage) ppage
-
-#endif
diff --git a/include/asm-arm/arch-a5k/oldlatches.h b/include/asm-arm/arch-a5k/oldlatches.h
deleted file mode 100644 (file)
index fa759a2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (a5k) machine"
-#endif
diff --git a/include/asm-arm/arch-a5k/processor.h b/include/asm-arm/arch-a5k/processor.h
deleted file mode 100644 (file)
index a8bf6e5..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/processor.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  10-09-1996 RMK     Created
- */
-
-#ifndef __ASM_ARCH_PROCESSOR_H
-#define __ASM_ARCH_PROCESSOR_H
-
-/*
- * Bus types
- */
-#define EISA_bus 0
-#define EISA_bus__is_a_macro /* for versions in ksyms.c */
-#define MCA_bus 0
-#define MCA_bus__is_a_macro /* for versions in ksyms.c */
-
-/*
- * User space: 26MB
- */
-#define TASK_SIZE      (0x01a00000UL)
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0x02000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-#endif
diff --git a/include/asm-arm/arch-a5k/serial.h b/include/asm-arm/arch-a5k/serial.h
deleted file mode 100644 (file)
index c839708..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/serial.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  15-10-1996 RMK     Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define RS_UARTS \
-       { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },     /* ttyS0 */     \
-       { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },     /* ttyS1 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS2 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS3 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS12 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS13 */
-
-#endif
diff --git a/include/asm-arm/arch-a5k/shmparam.h b/include/asm-arm/arch-a5k/shmparam.h
deleted file mode 100644 (file)
index 073c7c2..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff --git a/include/asm-arm/arch-a5k/system.h b/include/asm-arm/arch-a5k/system.h
deleted file mode 100644 (file)
index a1d845c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/system.h
- *
- * Copyright (c) 1996 Russell King
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-extern __inline__ void arch_hard_reset (void)
-{
-       extern void ecard_reset (int card);
-
-       /*
-        * Reset all expansion cards.
-        */
-       ecard_reset (-1);
-
-       /*
-        * copy branch instruction to reset location and call it
-        */
-       *(unsigned long *)0 = *(unsigned long *)0x03800000;
-       ((void(*)(void))0)();
-
-       /*
-        * If that didn't work, loop endlessly
-        */
-       while (1);
-}
-
-#endif
diff --git a/include/asm-arm/arch-a5k/time.h b/include/asm-arm/arch-a5k/time.h
deleted file mode 100644 (file)
index 0d12303..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/time.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  24-Sep-1996        RMK     Created
- *  10-Oct-1996        RMK     Brought up to date with arch-sa110eval
- *  04-Dec-1997        RMK     Updated for new arch/arm/time.c
- */
-
-extern __inline__ unsigned long gettimeoffset (void)
-{
-       unsigned int count1, count2, status1, status2;
-       unsigned long offset = 0;
-
-       status1 = IOC_IRQREQA;
-       barrier ();
-       outb (0, IOC_T0LATCH);
-       barrier ();
-       count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-       barrier ();
-       status2 = inb(IOC_IRQREQA);
-       barrier ();
-       outb (0, IOC_T0LATCH);
-       barrier ();
-       count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-
-       if (count2 < count1) {
-               /*
-                * This means that we haven't just had an interrupt
-                * while reading into status2.
-                */
-               if (status2 & (1 << 5))
-                       offset = tick;
-               count1 = count2;
-       } else if (count2 > count1) {
-               /*
-                * We have just had another interrupt while reading
-                * status2.
-                */
-               offset += tick;
-               count1 = count2;
-       }
-
-       count1 = LATCH - count1;
-       /*
-        * count1 = number of clock ticks since last interrupt
-        */
-       offset += count1 * tick / LATCH;
-       return offset;
-}
-
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
-
-/*
- * Updating of the RTC.  We don't currently write the time to the
- * CMOS clock.
- */
-#define update_rtc()
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-extern __inline__ unsigned long setup_timer (void)
-{
-       extern int iic_control (unsigned char, int, char *, int);
-       unsigned int year, mon, day, hour, min, sec;
-       char buf[8];
-
-       outb(LATCH & 255, IOC_T0LTCHL);
-       outb(LATCH >> 8, IOC_T0LTCHH);
-       outb(0, IOC_T0GO);
-
-       iic_control (0xa0, 0xc0, buf, 1);
-       year = buf[0];
-       if ((year += 1900) < 1970)
-               year += 100;
-
-       iic_control (0xa0, 2, buf, 5);
-       mon  = buf[4] & 0x1f;
-       day  = buf[3] & 0x3f;
-       hour = buf[2];
-       min  = buf[1];
-       sec  = buf[0];
-       BCD_TO_BIN(mon);
-       BCD_TO_BIN(day);
-       BCD_TO_BIN(hour);
-       BCD_TO_BIN(min);
-       BCD_TO_BIN(sec);
-
-       return mktime(year, mon, day, hour, min, sec);
-}
diff --git a/include/asm-arm/arch-a5k/timex.h b/include/asm-arm/arch-a5k/timex.h
deleted file mode 100644 (file)
index 84baf1f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/timex.h
- *
- * A5000 architecture timex specifications
- *
- * Copyright (C) 1997, 1998 Russell King
- */
-
-/*
- * On the RiscPC, the clock ticks at 2MHz.
- */
-#define CLOCK_TICK_RATE                2000000
-
diff --git a/include/asm-arm/arch-a5k/uncompress.h b/include/asm-arm/arch-a5k/uncompress.h
deleted file mode 100644 (file)
index e6af264..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/uncompress.h
- *
- * Copyright (C) 1996 Russell King
- */
-#define VIDMEM ((char *)0x02000000)
-#include "../arch/arm/drivers/char/font.h"
-
-int video_num_columns, video_num_lines, video_size_row;
-int white, bytes_per_char_h;
-extern unsigned long con_charconvtable[256];
-
-struct param_struct {
-       unsigned long page_size;
-       unsigned long nr_pages;
-       unsigned long ramdisk_size;
-       unsigned long mountrootrdonly;
-       unsigned long rootdev;
-       unsigned long video_num_cols;
-       unsigned long video_num_rows;
-       unsigned long video_x;
-       unsigned long video_y;
-       unsigned long memc_control_reg;
-       unsigned char sounddefault;
-       unsigned char adfsdrives;
-       unsigned char bytes_per_char_h;
-       unsigned char bytes_per_char_v;
-       unsigned long unused[256/4-11];
-};
-
-static struct param_struct *params = (struct param_struct *)0x0207c000;
-/*
- * This does not append a newline
- */
-static void puts(const char *s)
-{
-       extern void ll_write_char(char *, unsigned long);
-       int x,y;
-       unsigned char c;
-       char *ptr;
-
-       x = params->video_x;
-       y = params->video_y;
-
-       while ( ( c = *(unsigned char *)s++ ) != '\0' ) {
-               if ( c == '\n' ) {
-                       x = 0;
-                       if ( ++y >= video_num_lines ) {
-                               y--;
-                       }
-               } else {
-                       ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h);
-                       ll_write_char(ptr, c|(white<<8));
-                       if ( ++x >= video_num_columns ) {
-                               x = 0;
-                               if ( ++y >= video_num_lines ) {
-                                       y--;
-                               }
-                       }
-               }
-       }
-
-       params->video_x = x;
-       params->video_y = y;
-}
-
-static void error(char *x);
-
-/*
- * Setup for decompression
- */
-static void arch_decomp_setup(void)
-{
-       int i;
-       
-       video_num_lines = params->video_num_rows;
-       video_num_columns = params->video_num_cols;
-       bytes_per_char_h = params->bytes_per_char_h;
-       video_size_row = video_num_columns * bytes_per_char_h;
-       if (bytes_per_char_h == 4)
-               for (i = 0; i < 256; i++)
-                       con_charconvtable[i] =
-                               (i & 128 ? 1 << 0  : 0) |
-                               (i & 64  ? 1 << 4  : 0) |
-                               (i & 32  ? 1 << 8  : 0) |
-                               (i & 16  ? 1 << 12 : 0) |
-                               (i & 8   ? 1 << 16 : 0) |
-                               (i & 4   ? 1 << 20 : 0) |
-                               (i & 2   ? 1 << 24 : 0) |
-                               (i & 1   ? 1 << 28 : 0);
-       else
-               for (i = 0; i < 16; i++)
-                       con_charconvtable[i] =
-                               (i & 8   ? 1 << 0  : 0) |
-                               (i & 4   ? 1 << 8  : 0) |
-                               (i & 2   ? 1 << 16 : 0) |
-                               (i & 1   ? 1 << 24 : 0);
-
-       white = bytes_per_char_h == 8 ? 0xfc : 7;
-
-       if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n");
-}
index 985c27e90ffb7ce5fb85313b294021c8d34044d8..a8ef7645f58dd0aba3c10192a5311f9bcd64da18 100644 (file)
@@ -2,8 +2,9 @@
  * linux/include/asm-arm/arch-arc/a.out.h
  *
  * Copyright (C) 1996 Russell King
+ *
+ * Acorn Archimedes/A5000 a.out.h specs
  */
-
 #ifndef __ASM_ARCH_A_OUT_H
 #define __ASM_ARCH_A_OUT_H
 
index 8e82fe58d7da6f81e2688c75645b14c26ac0bace..3420d7d6d817c16fb8c4ea0dc93051bf0120c6dc 100644 (file)
@@ -1,95 +1,38 @@
+/*
+ * linux/include/asm-arm/arch-arc/dma.h
+ *
+ * Copyright (C) 1996-1998 Russell King
+ *
+ * Acorn Archimedes/A5000 architecture virtual DMA
+ * implementation
+ *
+ * Modifications:
+ *  04-04-1998 RMK     Merged arc and a5k versions
+ */
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-#define MAX_DMA_ADDRESS                0x03000000
-
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
+#include <linux/config.h>
 
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    switch(dmanr) {
-    case 0:  disable_irq(64); break;
-    case 1:  break;
-    default: printk (dma_str, "disable_dma", dmanr); break;
-    }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-#define clear_dma_ff(dmanr)
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
+#define MAX_DMA_ADDRESS                0x03000000
 
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
+/*
+ * DMA modes - we have two, IN and OUT
  */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
+typedef enum {
+       DMA_MODE_READ,
+       DMA_MODE_WRITE
+} dmamode_t;
 
+#define MAX_DMA_CHANNELS       4
 
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
+#define DMA_0                  0
+#define DMA_1                  1
+#define DMA_VIRTUAL_FLOPPY     2
+#define DMA_VIRTUAL_SOUND      3
 
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
+#ifdef CONFIG_ARCH_A5K
+#define DMA_FLOPPY             DMA_VIRTUAL_FLOPPY
+#endif
 
 #endif /* _ASM_ARCH_DMA_H */
index 21d933d865557915be075ad904b35b9c1e40fd72..4990ca132ed97c375cf588bfd391279634f4b775 100644 (file)
@@ -3,20 +3,31 @@
  *
  * Copyright (C) 1996 Russell King.
  *
- * This file contains the hardware definitions of the A3/4/5xx series machines.
+ * This file contains the hardware definitions of the
+ * Acorn Archimedes/A5000 machines.
+ *
+ * Modifications:
+ *  04-04-1998 PJB/RMK Merged arc and a5k versions
  */
 
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
+#include <linux/config.h>
+
 /*
- * What hardware must be present
+ * What hardware must be present - these can be tested by the kernel
+ * source.
  */
 #define HAS_IOC
 #define HAS_MEMC
 #define HAS_MEMC1A
 #define HAS_VIDC
 
+#ifdef CONFIG_ARCH_A5K
+#define HAS_PCIO
+#endif
+
 /*
  * Optional hardware
  */
  */
 #define VIDC_BASE              0x80100000
 #define IOCEC4IO_BASE          0x8009c000
+#ifdef CONFIG_ARCH_ARC
 #define LATCHAADDR             0x80094010
 #define LATCHBADDR             0x80094006
+#endif
 #define IOCECIO_BASE           0x80090000
 #define IOC_BASE               0x80080000
 #define MEMCECIO_BASE          0x80000000
index 9da7a9c5659d697688a47d33c6581a9d627e3e8a..8cc1baaa4d19d26f29e562d829448a608a4dbd73 100644 (file)
@@ -2,17 +2,33 @@
  * linux/include/asm-arm/arch-arc/ide.h
  *
  * Copyright (c) 1997,1998 Russell King
+ *
+ * IDE definitions for the Acorn Archimedes/A5000
+ * architecture
+ *
+ * Modifications:
+ *  04-04-1998 PJB     Merged `arc' and `a5k' versions
  */
 
+#include <linux/config.h>
+
 static __inline__ int
 ide_default_irq(ide_ioreg_t base)
 {
+#ifdef CONFIG_ARCH_A5K
+       if (base == 0x1f0)
+               return 11;
+#endif
        return 0;
 }
 
 static __inline__ ide_ioreg_t
 ide_default_io_base(int index)
 {
+#ifdef CONFIG_ARCH_A5K
+       if (index == 0)
+               return 0x1f0;
+#endif
        return 0;
 }
 
index 40775ec8fd7463581e6b54599c23f875210cc40f..1639e6d46d5a0493600ca582dec33a473e413704 100644 (file)
@@ -9,16 +9,6 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x) ((unsigned long)(x))
-#define bus_to_virt(x) ((void *)(x))
-
 /*
  * This architecture does not require any delayed IO, and
  * has the constant-optimised IO
@@ -58,7 +48,7 @@ extern __inline__ void __outw (unsigned int value, unsigned int port)
        "tst    %2, #0x80000000\n\t"
        "mov    %0, %4\n\t"
        "addeq  %0, %0, %3\n\t"
-       "strb   %1, [%0, %2, lsl #2]"
+       "str    %1, [%0, %2, lsl #2]"
        : "=&r" (temp)
        : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
        : "cc");
@@ -71,7 +61,7 @@ extern __inline__ void __outl (unsigned int value, unsigned int port)
        "tst    %2, #0x80000000\n\t"
        "mov    %0, %4\n\t"
        "addeq  %0, %0, %3\n\t"
-       "strb   %1, [%0, %2, lsl #2]"
+       "str    %1, [%0, %2, lsl #2]"
        : "=&r" (temp)
        : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
        : "cc");
index 62ea30478c33de2b02ddb7632cdf3f3da588bbda..937a79c3cac1f7eab514b307cf8845f645be7eff 100644 (file)
@@ -6,7 +6,7 @@
  * Changelog:
  *   24-09-1996        RMK     Created
  *   10-10-1996        RMK     Brought up to date with arch-sa110eval
- *   05-11-1996        RMK     Changed interrupt numbers & uses new inb/outb macros
+ *   22-10-1996        RMK     Changed interrupt numbers & uses new inb/outb macros
  *   11-01-1998        RMK     Added mask_and_ack_irq
  */
 
index e4043aaef1abe0a6b91bf7aee9d31db911647267..48e90b1d7bcb50864ee56b6a0e9d8982d223198d 100644 (file)
@@ -1,12 +1,26 @@
 /*
  * linux/include/asm-arm/arch-arc/irqs.h
  *
- * Copyright (C) 1996 Russell King, Dave Gilbert (gilbertd@cs.man.ac.uk)
+ * Copyright (C) 1996 Russell King, Dave Gilbert
+ *
+ * Modifications:
+ *  04-04-1998 PJB     Merged arc and a5k versions
  */
 
+#include <linux/config.h>
+
+#if defined(CONFIG_ARCH_A5K)
+#define IRQ_PRINTER            0
+#define IRQ_BATLOW             1
+#define IRQ_FLOPPYINDEX                2
+#define IRQ_FLOPPYDISK         12
+#elif defined(CONFIG_ARCH_ARC)
 #define IRQ_PRINTERBUSY                0
-#define IRQ_SERIALRING         1
+#define        IRQ_SERIALRING          1
 #define IRQ_PRINTERACK         2
+#define IRQ_FLOPPYCHANGED      12
+#endif
+
 #define IRQ_VSYNCPULSE         3
 #define IRQ_POWERON            4
 #define IRQ_TIMER0             5
 #define IRQ_SOUNDCHANGE                9
 #define IRQ_SERIALPORT         10
 #define IRQ_HARDDISK           11
-#define IRQ_FLOPPYCHANGED      12
 #define IRQ_EXPANSIONCARD      13
 #define IRQ_KEYBOARDTX         14
 #define IRQ_KEYBOARDRX         15
 
-#define FIQ_FLOPPYDATA         0
+#if defined(CONFIG_ARCH_A5K)
+#define FIQ_SERIALPORT         4
+#elif defined(CONFIG_ARCH_ARC)
 #define FIQ_FLOPPYIRQ          1
+#define FIQ_FD1772             FIQ_FLOPPYIRQ
+#endif
+
+#define FIQ_FLOPPYDATA         0
 #define FIQ_ECONET             2
 #define FIQ_EXPANSIONCARD      6
 #define FIQ_FORCE              7
 
-#define FIQ_FD1772             FIQ_FLOPPYIRQ
+#define IRQ_TIMER              IRQ_TIMER0
diff --git a/include/asm-arm/arch-arc/keyboard.h b/include/asm-arm/arch-arc/keyboard.h
new file mode 100644 (file)
index 0000000..59272e2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-arm/arch-arc/keyboard.h
+ *
+ * Keyboard driver definitions for Acorn Archimedes/A5000
+ * architecture
+ *
+ * Copyright (C) 1998 Russell King
+ */
+
+#include <asm/irq.h>
+
+#define NR_SCANCODES 128
+
+extern int a5kkbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
+extern void a5kkbd_leds(unsigned char leds);
+extern void a5kkbd_init_hw(void);
+extern unsigned char a5kkbd_sysrq_xlate[NR_SCANCODES];
+
+#define kbd_setkeycode(sc,kc)          (-EINVAL)
+#define kbd_getkeycode(sc)             (-EINVAL)
+
+/* Prototype: int kbd_pretranslate(scancode, raw_mode)
+ * Returns  : 0 to ignore scancode
+ */
+#define kbd_pretranslate(sc,rm)        (1)
+
+/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
+ * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
+ *            set to 0200 if scancode indicates release
+ */
+#define kbd_translate(sc, kcp, ufp, rm)        a5kkbd_translate(sc, kcp, ufp)
+#define kbd_unexpected_up(kc)          (0200)
+#define kbd_leds(leds)                 a5kkbd_leds(leds)
+#define kbd_init_hw()                  a5kkbd_init_hw()
+#define kbd_sysrq_xlate                        a5kkbd_sysrq_xlate
+#define kbd_disable_irq()              disable_irq(IRQ_KEYBOARDRX)
+#define kbd_enable_irq()               enable_irq(IRQ_KEYBOARDRX)
index 747f61adac661a1aa73b2168c8e7df9259cba68d..1e54d98633e041f67515ff05d4df44f55f5136fe 100644 (file)
@@ -9,7 +9,21 @@
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
+#define __virt_to_phys__is_a_macro
 #define __virt_to_phys(vpage) vpage
+#define __phys_to_virt__is_a_macro
 #define __phys_to_virt(ppage) ppage
 
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)       (x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)       (x)
+
 #endif
index 747a5e86dad05d989e4d0e463c7b29b209938b0f..3252e1109123fac6beaa8bc341a3e6084243b0cd 100644 (file)
@@ -1,6 +1,19 @@
-#ifndef _ASM_ARM_ARCHARC_OLDLATCH_H
-#define _ASM_ARM_ARCHARC_OLDLATCH_H
+/*
+ * linux/include/asm-arm/arch-arc/oldlatches.h
+ *
+ * Copyright (C) 1996 Russell King, Dave Gilbert
+ *
+ * Dummy oldlatches.h
+ *
+ * Modifications:
+ *  04-04-1998 PJB/RMK Merged arc and a5k versions
+ */
+#ifndef _ASM_ARCH_OLDLATCH_H
+#define _ASM_ARCH_OLDLATCH_H
 
+#include <linux/config.h>
+
+#if defined(CONFIG_ARCH_ARC)
 #define LATCHA_FDSEL0    (1<<0)
 #define LATCHA_FDSEL1    (1<<1)
 #define LATCHA_FDSEL2    (1<<2)
@@ -21,4 +34,12 @@ void oldlatch_bupdate(unsigned char mask,unsigned char newdata);
 /* newval=(oldval & mask)|newdata */
 void oldlatch_aupdate(unsigned char mask,unsigned char newdata);
 
+#elif defined(CONFIG_ARCH_A5K)
+
+#ifdef __need_oldlatches
+#error "Old latches not present in this (a5k) machine"
+#endif
+
+#endif
 #endif
+
index 0d3aee84a6d23af735d46ad75d1e52b8d5a30e02..3acb4886e336d849f053d79d026c33431c627d1f 100644 (file)
@@ -29,6 +29,6 @@
 #define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
 
 #define INIT_MMAP \
-{ &init_mm, 0, 0x02000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
index d9a6bde58aded626a37c1b7be65f389a040f88a3..4fdfcdb2109efb6da100c973fa9664973168bcd3 100644 (file)
@@ -5,10 +5,13 @@
  *
  * Changelog:
  *  15-10-1996 RMK     Created
+ *  04-04-1998 PJB     Merged `arc' and `a5k' architectures
  */
 #ifndef __ASM_ARCH_SERIAL_H
 #define __ASM_ARCH_SERIAL_H
 
+#include <linux/config.h>
+
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
  *
 
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
 
+#if defined(CONFIG_ARCH_A5K)
+     /* UART CLK        PORT  IRQ     FLAGS        */
+#define RS_UARTS \
+       { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },     /* ttyS0 */     \
+       { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },     /* ttyS1 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS2 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS3 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS4 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS5 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS6 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS7 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS8 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS9 */     \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS10 */    \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS11 */    \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS12 */    \
+       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS13 */
+
+#elif defined(CONFIG_ARCH_ARC)
+
      /* UART CLK        PORT  IRQ     FLAGS        */
 #define RS_UARTS \
        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS0 */     \
@@ -38,3 +61,4 @@
        { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS13 */
 
 #endif
+#endif
index 6807cc66c2a2f1599038a3316897450b79448477..a76c25845e421e11ea963c2b79415301823d136d 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
+#ifdef CONFIG_ARCH_ARC
+
 #define cliIF()                                \
        do {                            \
          unsigned long temp;           \
@@ -17,6 +19,8 @@
     : );       \
   } while(0)
 
+#endif
+
 extern __inline__ void arch_hard_reset (void)
 {
        extern void ecard_reset (int card);
index 5161a9a62df89f30348c741a0d16e743d7e47e12..569e01bb21a5f72fdeef8b70d4943f963656d42c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-arc/timex.h
  *
- * Archimedes architecture timex specifications
+ * Acorn Archimedes/A5000 architecture timex specifications
  *
  * Copyright (C) 1997, 1998 Russell King
  */
index e6af264b50ba8f81f4f2235c63b997a443365231..f3acb5c25948cfa7925024428327816bd91b92da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-a5k/uncompress.h
+ * linux/include/asm-arm/arch-arc/uncompress.h
  *
  * Copyright (C) 1996 Russell King
  */
index a34c23ef2b8867228e8b2f3fbc0b51077c3aba4d..0123eb29a1998e8dd09e58bf789dec819e624dcd 100644 (file)
@@ -8,7 +8,7 @@
 #define __ASM_ARCH_A_OUT_H
 
 #ifdef __KERNEL__
-#define STACK_TOP              (0xc0000000)
+#define STACK_TOP              ((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
 #define LIBRARY_START_TEXT     (0x00c00000)
 #endif
 
index 73340527ac626446a025913f5a539b219bfc2367..96a265927c0eeaec4fc3fd33eb446f0df793c6e7 100644 (file)
@@ -8,93 +8,22 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    printk (dma_str, "disable_dma", dmanr);
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-    printk (dma_str, "clear_dma_ff", dmanr);
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
  */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
+#define MAX_DMA_ADDRESS                0xd0000000
 
-/* Set transfer size for a specific DMA channel.
+/*
+ * DMA modes - we have two, IN and OUT
  */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
+typedef enum {
+       DMA_MODE_READ,
+       DMA_MODE_WRITE
+} dmamode_t;
 
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
+#define MAX_DMA_CHANNELS       8
 
 #endif /* _ASM_ARCH_DMA_H */
 
index 14655b47b17ecd9db055a7b97d2e1057483bd293..61ac7492ebbbfd68456e8e8a328eb5ce22fd085d 100644 (file)
@@ -39,6 +39,7 @@
 #define MAPTOPHYS(a)           ((unsigned long)(a) - PAGE_OFFSET)
 #define KERNTOPHYS(a)          ((unsigned long)(&a))
 #define KERNEL_BASE            (0xc0008000)
+#define SAFE_ADDR              0x40000000
 
 #else
 
index 30621db0a13e266851e1cb547c79185f35afef03..39f574d555a0cc18bb4b8ac0f017039952ae750a 100644 (file)
@@ -9,16 +9,6 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x) ((unsigned long)(x))
-#define bus_to_virt(x) ((void *)(x))
-
 /*
  * This architecture does not require any delayed IO, and
  * has the constant-optimised IO
@@ -146,7 +136,18 @@ DECLARE_IO(long,l,"")
        result & 0xffff;                                                        \
 })
 
-#define __outlc(v,p) __outwc((v),(p))
+#define __outlc(v,p)                                                           \
+({                                                                             \
+       unsigned long v = value;                                                \
+       if (__PORT_PCIO((port)))                                                \
+               __asm__ __volatile__(                                           \
+               "str    %0, [%1, %2]"                                           \
+               : : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2));              \
+       else                                                                    \
+               __asm__ __volatile__(                                           \
+               "str    %0, [%1, %2]"                                           \
+               : : "r" (v), "r" (IO_BASE), "r" ((port) << 2));                 \
+})
 
 #define __inlc(port)                                                           \
 ({                                                                             \
index b83b5967cf99bf58875dcfc9af79d483ec5cf740..016686df9814d937375b1fe96a9b8fd3f3964aa8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-sa100eval/irqs.h
+ * linux/include/asm-arm/arch-ebsa110/irqs.h
  *
  * Copyright (C) 1996 Russell King
  */
@@ -12,3 +12,5 @@
 #define IRQ_TIMER1             5
 #define IRQ_PCMCIA             6
 #define IRQ_IMMEDIATE          7
+
+#define IRQ_TIMER              IRQ_TIMER0
index 9c70f75053468e6003ce86b5991b1a8b657183ba..3e37941409cf0c3cc02fa32d9b69306bd7efd87a 100644 (file)
@@ -1,11 +1,6 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/mm-init.h
+ * linux/include/asm-arm/arch-ebsa110/mmap.h
  *
- * Copyright (C) 1997,1998 Russell King
- *
- * Description of the initial memory map for EBSA-110
+ * Copyright (C) 1996,1997,1998 Russell King
  */
 
-static init_mem_map_t init_mem_map[] = {
-       INIT_MEM_MAP_SENTINEL
-};
diff --git a/include/asm-arm/arch-ebsa110/mmap.h b/include/asm-arm/arch-ebsa110/mmap.h
deleted file mode 100644 (file)
index 2ba0c2a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR      0x40000000
index fb684dd749f2dfdfbbda681e8630f8ed824c8cfe..07006f82ec8920440ed7c848139e1a8d814db1e9 100644 (file)
 /*
  * On ebsa, the dram is contiguous
  */
+#define __virt_to_phys__is_a_macro
 #define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
 #define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
 
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)       __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)       __phys_to_virt(x)
+
 #endif
index b54085946904f5a4be9b510198b168524a5832a9..732c9142cda9479aa609f3d2b666c6f449665667 100644 (file)
@@ -26,6 +26,6 @@
 #define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
 
 #define INIT_MMAP \
-{ &init_mm, 0xc0000000, 0xc2000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+{ &init_mm, 00, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff --git a/include/asm-arm/arch-ebsa285/a.out.h b/include/asm-arm/arch-ebsa285/a.out.h
new file mode 100644 (file)
index 0000000..0123eb2
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/a.out.h
+ *
+ * Copyright (C) 1996 Russell King
+ */
+
+#ifndef __ASM_ARCH_A_OUT_H
+#define __ASM_ARCH_A_OUT_H
+
+#ifdef __KERNEL__
+#define STACK_TOP              ((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
+#define LIBRARY_START_TEXT     (0x00c00000)
+#endif
+
+#endif
+
diff --git a/include/asm-arm/arch-ebsa285/dma.h b/include/asm-arm/arch-ebsa285/dma.h
new file mode 100644 (file)
index 0000000..96a2659
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/dma.h
+ *
+ * Architecture DMA routes
+ *
+ * Copyright (C) 1997.1998 Russell King
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
+ */
+#define MAX_DMA_ADDRESS                0xd0000000
+
+/*
+ * DMA modes - we have two, IN and OUT
+ */
+typedef enum {
+       DMA_MODE_READ,
+       DMA_MODE_WRITE
+} dmamode_t;
+
+#define MAX_DMA_CHANNELS       8
+
+#endif /* _ASM_ARCH_DMA_H */
+
diff --git a/include/asm-arm/arch-ebsa285/hardware.h b/include/asm-arm/arch-ebsa285/hardware.h
new file mode 100644 (file)
index 0000000..8d6af3b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/hardware.h
+ *
+ * Copyright (C) 1998 Russell King.
+ *
+ * This file contains the hardware definitions of the EBSA-285.
+ */
+
+
+/*    Logical    Physical
+ * 0xfff00000  0x40000000      X-Bus
+ * 0xffe00000  0x7c000000      PCI I/O space
+ *
+ * 0xfe000000  0x42000000      CSR
+ * 0xfd000000  0x78000000      Outbound write flush
+ * 0xfc000000  0x79000000      PCI IACK/special space
+ *
+ * 0xf9030000  0x7a080000      PCI Config type 1 card 4
+ * 0xf9020000  0x7a040000      PCI Config type 1 card 3
+ * 0xf9010000  0x7a020000      PCI Config type 1 card 2
+ * 0xf9000000  0x7a010000      PCI Config type 1 card 1
+ *
+ * 0xf8030000  0x7b080000      PCI Config type 0 card 4
+ * 0xf8020000  0x7b040000      PCI Config type 0 card 3
+ * 0xf8010000  0x7b020000      PCI Config type 0 card 2
+ * 0xf8000000  0x7b010000      PCI Config type 0 card 1
+ * 
+ */
+#define IO_END                 0xffffffff
+#define IO_BASE                        0xe0000000
+#define IO_SIZE                        (IO_END - IO_BASE)
+
+#define HAS_PCIO
+
+#define XBUS_LEDS              ((volatile unsigned char *)0xfff12000)
+#define XBUS_LED_AMBER         (1 << 0)
+#define XBUS_LED_GREEN         (1 << 1)
+#define XBUS_LED_RED           (1 << 2)
+#define XBUS_LED_TOGGLE                (1 << 8)
+
+#define XBUS_SWITCH            ((volatile unsigned char *)0xfff12000)
+#define XBUS_SWITCH_SWITCH     ((*XBUS_SWITCH) & 15)
+#define XBUS_SWITCH_J17_13     ((*XBUS_SWITCH) & (1 << 4))
+#define XBUS_SWITCH_J17_11     ((*XBUS_SWITCH) & (1 << 5))
+#define XBUS_SWITCH_J17_9      ((*XBUS_SWITCH) & (1 << 6))
+
+#define PCIO_BASE              0xffe00000
+#define CSR_SA110_CNTL         ((volatile unsigned long *)0xfe00013c)
+#define CSR_PCIADDR_EXTN       ((volatile unsigned long *)0xfe000140)
+#define CSR_PREFETCHMEMRANGE   ((volatile unsigned long *)0xfe000144)
+#define CSR_XBUS_CYCLE         ((volatile unsigned long *)0xfe000148)
+#define CSR_XBUS_IOSTROBE      ((volatile unsigned long *)0xfe00014c)
+#define CSR_DOORBELL_PCI       ((volatile unsigned long *)0xfe000150)
+#define CSR_DOORBELL_SA110     ((volatile unsigned long *)0xfe000154)
+
+
+#define CSR_UARTDR             ((volatile unsigned long *)0xfe000160)
+#define CSR_RXSTAT             ((volatile unsigned long *)0xfe000164)
+#define CSR_H_UBRLCR           ((volatile unsigned long *)0xfe000168)
+#define CSR_M_UBRLCR           ((volatile unsigned long *)0xfe00016c)
+#define CSR_L_UBRLCR           ((volatile unsigned long *)0xfe000170)
+#define CSR_UARTCON            ((volatile unsigned long *)0xfe000174)
+#define CSR_UARTFLG            ((volatile unsigned long *)0xfe000178)
+
+#define CSR_IRQ_STATUS         ((volatile unsigned long *)0xfe000180)
+#define CSR_IRQ_RAWSTATUS      ((volatile unsigned long *)0xfe000184)
+#define CSR_IRQ_ENABLE         ((volatile unsigned long *)0xfe000188)
+#define CSR_IRQ_DISABLE                ((volatile unsigned long *)0xfe00018c)
+#define CSR_IRQ_SOFT           ((volatile unsigned long *)0xfe000190)
+
+#define CSR_FIQ_STATUS         ((volatile unsigned long *)0xfe000280)
+#define CSR_FIQ_RAWSTATUS      ((volatile unsigned long *)0xfe000284)
+#define CSR_FIQ_ENABLE         ((volatile unsigned long *)0xfe000288)
+#define CSR_FIQ_DISABLE                ((volatile unsigned long *)0xfe00028c)
+#define CSR_FIQ_SOFT           ((volatile unsigned long *)0xfe000290)
+
+#define CSR_TIMER1_LOAD                ((volatile unsigned long *)0xfe000300)
+#define CSR_TIMER1_VALUE       ((volatile unsigned long *)0xfe000304)
+#define CSR_TIMER1_CNTL                ((volatile unsigned long *)0xfe000308)
+#define CSR_TIMER1_CLR         ((volatile unsigned long *)0xfe00030c)
+
+#define CSR_TIMER2_LOAD                ((volatile unsigned long *)0xfe000320)
+#define CSR_TIMER2_VALUE       ((volatile unsigned long *)0xfe000324)
+#define CSR_TIMER2_CNTL                ((volatile unsigned long *)0xfe000328)
+#define CSR_TIMER2_CLR         ((volatile unsigned long *)0xfe00032c)
+
+#define CSR_TIMER3_LOAD                ((volatile unsigned long *)0xfe000340)
+#define CSR_TIMER3_VALUE       ((volatile unsigned long *)0xfe000344)
+#define CSR_TIMER3_CNTL                ((volatile unsigned long *)0xfe000348)
+#define CSR_TIMER3_CLR         ((volatile unsigned long *)0xfe00034c)
+
+#define CSR_TIMER4_LOAD                ((volatile unsigned long *)0xfe000360)
+#define CSR_TIMER4_VALUE       ((volatile unsigned long *)0xfe000364)
+#define CSR_TIMER4_CNTL                ((volatile unsigned long *)0xfe000368)
+#define CSR_TIMER4_CLR         ((volatile unsigned long *)0xfe00036c)
+
+
+#define TIMER_CNTL_ENABLE      (1 << 7)
+#define TIMER_CNTL_AUTORELOAD  (1 << 6)
+#define TIMER_CNTL_DIV1                (0)
+#define TIMER_CNTL_DIV16       (1 << 2)
+#define TIMER_CNTL_DIV256      (2 << 2)
+#define TIMER_CNTL_CNTEXT      (3 << 2)
+
+
+#define KERNTOPHYS(a)          ((unsigned long)(&a))
+
+#define PARAMS_OFFSET          0x0100
+#define PARAMS_BASE            (PAGE_OFFSET + PARAMS_OFFSET)
+
+#define SAFE_ADDR              0x50000000
+
diff --git a/include/asm-arm/arch-ebsa285/ide.h b/include/asm-arm/arch-ebsa285/ide.h
new file mode 100644 (file)
index 0000000..35eff5c
--- /dev/null
@@ -0,0 +1 @@
+/* no ide */
diff --git a/include/asm-arm/arch-ebsa285/io.h b/include/asm-arm/arch-ebsa285/io.h
new file mode 100644 (file)
index 0000000..5142e91
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/io.h
+ *
+ * Copyright (C) 1997,1998 Russell King
+ *
+ * Modifications:
+ *  06-Dec-1997        RMK     Created.
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+/*
+ * This architecture does not require any delayed IO, and
+ * has the constant-optimised IO
+ */
+#undef ARCH_IO_DELAY
+
+/*
+ * Dynamic IO functions - let the compiler
+ * optimize the expressions
+ */
+#define DECLARE_DYN_OUT(fnsuffix,instr,typ)                                    \
+extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port) \
+{                                                                              \
+       __asm__ __volatile__(                                                   \
+       "str" ##instr## "       %0, [%1, %2]"                                   \
+       :                                                                       \
+       : "r" (value), "r" (PCIO_BASE), typ (port));                            \
+}
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)                                  \
+extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)               \
+{                                                                              \
+       unsigned long value;                                                    \
+       __asm__ __volatile__(                                                   \
+       "ldr" ##instr## "       %0, [%1, %2]"                                   \
+       : "=&r" (value)                                                         \
+       : "r" (PCIO_BASE), typ (port));                                         \
+       return (unsigned sz)value;                                              \
+}
+
+extern __inline__ unsigned int __ioaddr (unsigned int port)                    \
+{                                                                              \
+       return (unsigned int)(PCIO_BASE + port);                                \
+}
+
+#define DECLARE_IO(sz,fnsuffix,instr,typ)      \
+       DECLARE_DYN_OUT(fnsuffix,instr,typ)     \
+       DECLARE_DYN_IN(sz,fnsuffix,instr,typ)
+
+DECLARE_IO(char,b,"b","Jr")
+DECLARE_IO(short,w,"h","r")
+DECLARE_IO(long,l,"","Jr")
+
+#undef DECLARE_IO
+#undef DECLARE_DYN_OUT
+#undef DECLARE_DYN_IN
+
+/*
+ * Constant address IO functions
+ *
+ * These have to be macros for the 'J' constraint to work -
+ * +/-4096 immediate operand.
+ */
+#define __outbc(value,port)                                                    \
+({                                                                             \
+       __asm__ __volatile__(                                                   \
+       "strb   %0, [%1, %2]"                                                   \
+       :                                                                       \
+       : "r" (value), "r" (PCIO_BASE), "Jr" (port));                           \
+})
+
+#define __inbc(port)                                                           \
+({                                                                             \
+       unsigned char result;                                                   \
+       __asm__ __volatile__(                                                   \
+       "ldrb   %0, [%1, %2]"                                                   \
+       : "=r" (result)                                                         \
+       : "r" (PCIO_BASE), "Jr" (port));                                        \
+       result;                                                                 \
+})
+
+#define __outwc(value,port)                                                    \
+({                                                                             \
+       __asm__ __volatile__(                                                   \
+       "strh   %0, [%1, %2]"                                                   \
+       :                                                                       \
+       : "r" (value), "r" (PCIO_BASE), "r" (port));                            \
+})
+
+#define __inwc(port)                                                           \
+({                                                                             \
+       unsigned short result;                                                  \
+       __asm__ __volatile__(                                                   \
+       "ldrh   %0, [%1, %2]"                                                   \
+       : "=r" (result)                                                         \
+       : "r" (PCIO_BASE), "r" (port));                                         \
+       result & 0xffff;                                                        \
+})
+
+#define __outlc(value,port)                                                    \
+({                                                                             \
+       __asm__ __volatile__(                                                   \
+       "str    %0, [%1, %2]"                                                   \
+       :                                                                       \
+       : "r" (value), "r" (PCIO_BASE), "Jr" (port));                           \
+})
+
+#define __inlc(port)                                                           \
+({                                                                             \
+       unsigned long result;                                                   \
+       __asm__ __volatile__(                                                   \
+       "ldr    %0, [%1, %2]"                                                   \
+       : "=r" (result)                                                         \
+       : "r" (PCIO_BASE), "Jr" (port));                                        \
+       result;                                                                 \
+})
+
+#define __ioaddrc(port)                                                                \
+({                                                                             \
+       unsigned long addr;                                                     \
+       addr = PCIO_BASE + port;                                                \
+       addr;                                                                   \
+})
+
+/*
+ * Translated address IO functions
+ *
+ * IO address has already been translated to a virtual address
+ */
+#define outb_t(v,p)                                                            \
+       (*(volatile unsigned char *)(p) = (v))
+
+#define inb_t(p)                                                               \
+       (*(volatile unsigned char *)(p))
+
+#define outl_t(v,p)                                                            \
+       (*(volatile unsigned long *)(p) = (v))
+
+#define inl_t(p)                                                               \
+       (*(volatile unsigned long *)(p))
+
+#endif
diff --git a/include/asm-arm/arch-ebsa285/irq.h b/include/asm-arm/arch-ebsa285/irq.h
new file mode 100644 (file)
index 0000000..ece9464
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * include/asm-arm/arch-ebsa110/irq.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+
+static __inline__ void mask_and_ack_irq(unsigned int irq)
+{
+       if (irq < 32)
+               *CSR_IRQ_DISABLE = 1 << irq;
+}
+
+static __inline__ void mask_irq(unsigned int irq)
+{
+       if (irq < 32)
+               *CSR_IRQ_DISABLE = 1 << irq;
+}
+
+static __inline__ void unmask_irq(unsigned int irq)
+{
+       if (irq < 32)
+               *CSR_IRQ_ENABLE = 1 << irq;
+}
+static __inline__ unsigned long get_enabled_irqs(void)
+{
+       return 0;
+}
+
+static __inline__ void irq_init_irq(void)
+{
+       *CSR_IRQ_DISABLE = -1;
+       *CSR_FIQ_DISABLE = -1;
+}
diff --git a/include/asm-arm/arch-ebsa285/irqs.h b/include/asm-arm/arch-ebsa285/irqs.h
new file mode 100644 (file)
index 0000000..1087676
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/irqs.h
+ *
+ * Copyright (C) 1998 Russell King
+ */
+
+#define NR_IRQS                        32
+
+/*
+ * This is a list of all interrupts that the 21285
+ * can generate
+ */
+#define IRQ_RESERVED           0
+#define IRQ_SOFTIRQ            1
+#define IRQ_CONRX              2
+#define IRQ_CONTX              3
+#define IRQ_TIMER1             4
+#define IRQ_TIMER2             5
+#define IRQ_TIMER3             6
+#define IRQ_TIMER4             7
+#define IRQ_IN0                        8
+#define IRQ_IN1                        9
+#define IRQ_IN2                        10
+#define IRQ_IN3                        11
+#define IRQ_XCS0               12
+#define IRQ_XCS1               13
+#define IRQ_XCS2               14
+#define IRQ_DOORBELLHOST       15
+#define IRQ_DMA1               16
+#define IRQ_DMA2               17
+#define IRQ_PCI                        18
+#define IRQ_BIST               22
+#define IRQ_SERR               23
+#define IRQ_SDRAMPARITY                24
+#define IRQ_I2OINPOST          25
+#define IRQ_DISCARDTIMER       27
+#define IRQ_PCIDATAPARITY      28
+#define IRQ_PCIMASTERABORT     29
+#define IRQ_PCITARGETABORT     30
+#define IRQ_PCIPARITY          31
+
+/*
+ * Now map them to the Linux interrupts
+ */
+#define IRQ_TIMER              IRQ_TIMER1
diff --git a/include/asm-arm/arch-ebsa285/keyboard.h b/include/asm-arm/arch-ebsa285/keyboard.h
new file mode 100644 (file)
index 0000000..92b29e3
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/keyboard.h
+ *
+ * Keyboard driver definitions for EBSA285 architecture
+ *
+ * (C) 1998 Russell King
+ */
+
+#include <asm/irq.h>
+
+#define NR_SCANCODES 128
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static unsigned char kbd_sysrq_xlate[NR_SCANCODES];
+#endif
+
+#define kbd_setkeycode(sc,kc)          (-EINVAL)
+#define kbd_getkeycode(sc)             (-EINVAL)
+
+/* Prototype: int kbd_pretranslate(scancode, raw_mode)
+ * Returns  : 0 to ignore scancode
+ */
+#define kbd_pretranslate(sc,rm)                (1)
+
+/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
+ * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
+ *            set to 0200 if scancode indicates release
+ */
+#define kbd_translate(sc, kcp, ufp, rm)        (1)
+#define kbd_unexpected_up(kc)          (0200)
+#define kbd_leds(leds)
+#define kbd_init_hw()
+//#define kbd_sysrq_xlate                      ps2kbd_sysrq_xlate
+#define kbd_disable_irq()
+#define kbd_enable_irq()
+
diff --git a/include/asm-arm/arch-ebsa285/mm-init.h b/include/asm-arm/arch-ebsa285/mm-init.h
new file mode 100644 (file)
index 0000000..c6937ab
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/mmap.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
diff --git a/include/asm-arm/arch-ebsa285/mmu.h b/include/asm-arm/arch-ebsa285/mmu.h
new file mode 100644 (file)
index 0000000..07006f8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/mmu.h
+ *
+ * Copyright (c) 1996,1997,1998 Russell King.
+ *
+ * Changelog:
+ *  20-10-1996 RMK     Created
+ *  31-12-1997 RMK     Fixed definitions to reduce warnings
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * On ebsa, the dram is contiguous
+ */
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)       __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)       __phys_to_virt(x)
+
+#endif
diff --git a/include/asm-arm/arch-ebsa285/oldlatches.h b/include/asm-arm/arch-ebsa285/oldlatches.h
new file mode 100644 (file)
index 0000000..8ff6ebd
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Dummy oldlatches.h
+ *
+ * Copyright (C) 1996 Russell King
+ */
+
+#ifdef __need_oldlatches
+#error "Old latches not present in this (rpc) machine"
+#endif
diff --git a/include/asm-arm/arch-ebsa285/processor.h b/include/asm-arm/arch-ebsa285/processor.h
new file mode 100644 (file)
index 0000000..732c914
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/processor.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+
+#ifndef __ASM_ARCH_PROCESSOR_H
+#define __ASM_ARCH_PROCESSOR_H
+
+/*
+ * Bus types
+ */
+#define EISA_bus 0
+#define EISA_bus__is_a_macro /* for versions in ksyms.c */
+#define MCA_bus 0
+#define MCA_bus__is_a_macro /* for versions in ksyms.c */
+
+/*
+ * User space: 3GB
+ */
+#define TASK_SIZE      (0xc0000000UL)
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
+
+#define INIT_MMAP \
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+
+#endif
diff --git a/include/asm-arm/arch-ebsa285/shmparam.h b/include/asm-arm/arch-ebsa285/shmparam.h
new file mode 100644 (file)
index 0000000..9c36489
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/shmparam.h
+ *
+ * Copyright (c) 1996 Russell King.
+ */
diff --git a/include/asm-arm/arch-ebsa285/system.h b/include/asm-arm/arch-ebsa285/system.h
new file mode 100644 (file)
index 0000000..a3fed31
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/system.h
+ *
+ * Copyright (c) 1996,1997,1998 Russell King.
+ */
+#include <asm/hardware.h>
+#include <asm/leds.h>
+
+/* To reboot, we set up the 21285 watchdog and enable it.
+ * We then wait for it to timeout.
+ */
+extern __inline__ void arch_hard_reset (void)
+{
+       cli();
+       *CSR_TIMER4_LOAD = 0x8000;
+       *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
+       *CSR_SA110_CNTL |= 1 << 13;
+       while(1);
+}
+
+#define ARCH_IDLE_OK
+
+#define arch_start_idle()      leds_event(led_idle_start)
+#define arch_end_idle()                leds_event(led_idle_end)
diff --git a/include/asm-arm/arch-ebsa285/time.h b/include/asm-arm/arch-ebsa285/time.h
new file mode 100644 (file)
index 0000000..cbc5329
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/time.h
+ *
+ * Copyright (c) 1998 Russell King.
+ *
+ * No real time clock on the evalulation board!
+ *
+ * Changelog:
+ *  21-Mar-1998        RMK     Created
+ */
+
+#include <asm/leds.h>
+
+extern __inline__ unsigned long gettimeoffset (void)
+{
+       return 0;
+}
+
+extern __inline__ int reset_timer (void)
+{
+       static unsigned int count = 50;
+       static int last_pid;
+
+       *CSR_TIMER1_CLR = 0;
+
+       if (current->pid != last_pid) {
+               last_pid = current->pid;
+               if (last_pid)
+                       leds_event(led_idle_end);
+               else
+                       leds_event(led_idle_start);
+       }
+
+       if (--count == 0) {
+               count = 50;
+               leds_event(led_timer);
+       }
+
+       return 1;
+}
+
+/*
+ * We don't have a RTC to update!
+ */
+#define update_rtc()
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+extern __inline__ unsigned long setup_timer (void)
+{
+       *CSR_TIMER1_CLR  = 0;
+       *CSR_TIMER1_LOAD = LATCH;
+       *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
+
+       return mktime(1970, 1, 1, 0, 0, 0);
+}
diff --git a/include/asm-arm/arch-ebsa285/timex.h b/include/asm-arm/arch-ebsa285/timex.h
new file mode 100644 (file)
index 0000000..0a730a7
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/timex.h
+ *
+ * EBSA285 architecture timex specifications
+ *
+ * Copyright (C) 1998 Russell King
+ */
+
+/*
+ * On the EBSA, the clock ticks at weird rates.
+ * This is therefore not used to calculate the
+ * divisor.
+ */
+#define CLOCK_TICK_RATE                (50000000 / 16)
diff --git a/include/asm-arm/arch-ebsa285/uncompress.h b/include/asm-arm/arch-ebsa285/uncompress.h
new file mode 100644 (file)
index 0000000..d5260b0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+
+/*
+ * This does not append a newline
+ */
+static void puts(const char *s)
+{
+       __asm__ __volatile__("
+       ldrb    %0, [%2], #1
+       teq     %0, #0
+       beq     3f
+1:     strb    %0, [%3]
+2:     ldrb    %1, [%3, #0x14]
+       and     %1, %1, #0x60
+       teq     %1, #0x60
+       bne     2b
+       teq     %0, #'\n'
+       moveq   %0, #'\r'
+       beq     1b
+       ldrb    %0, [%2], #1
+       teq     %0, #0
+       bne     1b
+3:     " : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
index b8e2780740a8f6f6fe677425e7d26cbb21a17b07..ad8369c4e2aa5a30bd4129a2677a6c3eab9a69f7 100644 (file)
@@ -8,7 +8,7 @@
 #define __ASM_ARCH_A_OUT_H
 
 #ifdef __KERNEL__
-#define STACK_TOP              (0xc0000000)
+#define STACK_TOP              ((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
 #define LIBRARY_START_TEXT     (0x00c00000)
 #endif
 
index 73340527ac626446a025913f5a539b219bfc2367..9b181743c0f055a1a5f4e107a9b693128c8a13e4 100644 (file)
 /*
- * linux/include/asm-arm/arch-ebsa110/dma.h
+ * linux/include/asm-arm/arch-nexuspci/dma.h
  *
- * Architecture DMA routes
+ * Architecture DMA routines
  *
- * Copyright (C) 1997.1998 Russell King
+ * Copyright (C) 1998 Philip Blundell
  */
+
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    printk (dma_str, "disable_dma", dmanr);
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-    printk (dma_str, "clear_dma_ff", dmanr);
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
+/* NexusPCI has no DMA */
 
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
+#warning No DMA on this platform
 
 #endif /* _ASM_ARCH_DMA_H */
 
index 154bce9df89be52be6c2ef2ffc7e9103b17d0a2f..c1534ade697c5a69d351836c3afa6aa60f932fad 100644 (file)
@@ -30,6 +30,7 @@
 #define MAPTOPHYS(a)           ((unsigned long)(a) - PAGE_OFFSET + RAM_BASE)
 #define KERNTOPHYS(a)          ((unsigned long)(&a))
 #define KERNEL_BASE            (0xc0008000)
+#define SAFE_ADDR              0x40000000
 
 #else
 
index 661af14a1f6c00d7a003449fcd6e372cb9535d17..054d0675b7c9d3a4efcb6c2a9235247fa471d09d 100644 (file)
@@ -5,10 +5,12 @@
  */
 
 #define IRQ_DUART              0
-#define IRQ_TIMER0             0       /* timer is part of the DUART */
 #define IRQ_PLX                1
 #define IRQ_PCI_D              2
 #define IRQ_PCI_C              3
 #define IRQ_PCI_B              4
 #define IRQ_PCI_A              5
-#define IRQ_SYSERR             6       /* must ask JB about this one */
+#define IRQ_SYSERR             6
+
+/* timer is part of the DUART */
+#define IRQ_TIMER              IRQ_DUART
diff --git a/include/asm-arm/arch-nexuspci/mm-init.h b/include/asm-arm/arch-nexuspci/mm-init.h
new file mode 100644 (file)
index 0000000..93887c9
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * linux/include/asm-arm/arch-nexuspci/mmap.h
+ *
+ * Copyright (C) 1998 Philip Blundell
+ */
diff --git a/include/asm-arm/arch-nexuspci/mmap.h b/include/asm-arm/arch-nexuspci/mmap.h
deleted file mode 100644 (file)
index 2ba0c2a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR      0x40000000
index b54085946904f5a4be9b510198b168524a5832a9..46bf157a492aac7dd62419899f29c80ef7dd0696 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/processor.h
+ *  from linux/include/asm-arm/arch-ebsa110/processor.h
  *
  * Copyright (C) 1996,1997,1998 Russell King
  */
@@ -26,6 +27,6 @@
 #define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
 
 #define INIT_MMAP \
-{ &init_mm, 0xc0000000, 0xc2000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+{ &init_mm, 00, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff --git a/include/asm-arm/arch-nexuspci/serial.h b/include/asm-arm/arch-nexuspci/serial.h
deleted file mode 100644 (file)
index 1d41a7c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/serial.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  15-10-1996 RMK     Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define RS_UARTS \
-       { 0, BASE_BAUD, 0x3F8,  1, STD_COM_FLAGS },     /* ttyS0 */     \
-       { 0, BASE_BAUD, 0x2F8,  2, STD_COM_FLAGS },     /* ttyS1 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS2 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS3 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS12 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS13 */
-
-#endif
-
index 16daee5b99617f9fd0f255c227ad1a6f822eac39..4332c4a94f4fe188c7c08479ed7e775e96d336c0 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ * linux/include/asm-arm/arch-nexuspci/uncompress.h
+ *  from linux/include/asm-arm/arch-ebsa110/uncompress.h
  *
  * Copyright (C) 1996,1997,1998 Russell King
  */
index c9a1d0413ec5b00dcd24fd392fa55f7a389bc829..6b55ee0764d3eb108660fa76754592e9f6980363 100644 (file)
@@ -8,7 +8,7 @@
 #define __ASM_ARCH_A_OUT_H
 
 #ifdef __KERNEL__
-#define STACK_TOP              (0xc0000000)
+#define STACK_TOP              ((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
 #define LIBRARY_START_TEXT     (0x00c00000)
 #endif
 
index 540ac46f1d61fa454419cd6e426b955bed52936f..0f556e8564b8ce0989064e95ae9072f6fa67c1a7 100644 (file)
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-#define MAX_DMA_ADDRESS                0xd0000000
-
-#ifdef KERNEL_ARCH_DMA
-
-static unsigned char arch_dma_setup;
-unsigned char arch_dma_ctrl[8];
-unsigned long arch_dma_addr[8];
-unsigned long arch_dma_cnt[8];
-
-static inline void arch_enable_dma(int dmanr)
-{
-  if (!(arch_dma_setup & (1 << dmanr))) {
-    arch_dma_setup |= 1 << dmanr;
-/*    dma_interrupt (16 + dmanr);*/
-  }
-  arch_dma_ctrl[dmanr] |= DMA_CR_E;
-  switch (dmanr) {
-    case 0: outb (arch_dma_ctrl[0], IOMD_IO0CR); break;
-    case 1: outb (arch_dma_ctrl[1], IOMD_IO1CR); break;
-    case 2: outb (arch_dma_ctrl[2], IOMD_IO2CR); break;
-    case 3: outb (arch_dma_ctrl[3], IOMD_IO3CR); break;
-    case 4: outb (arch_dma_ctrl[4], IOMD_SD0CR); break;
-    case 5: outb (arch_dma_ctrl[5], IOMD_SD1CR); break;
-  }
-}
-
-static inline void arch_disable_dma(int dmanr)
-{
-  arch_dma_ctrl[dmanr] &= ~DMA_CR_E;
-  switch (dmanr) {
-    case 0: outb (arch_dma_ctrl[0], IOMD_IO0CR); break;
-    case 1: outb (arch_dma_ctrl[1], IOMD_IO1CR); break;
-    case 2: outb (arch_dma_ctrl[2], IOMD_IO2CR); break;
-    case 3: outb (arch_dma_ctrl[3], IOMD_IO3CR); break;
-    case 4: outb (arch_dma_ctrl[4], IOMD_SD0CR); break;
-    case 5: outb (arch_dma_ctrl[5], IOMD_SD1CR); break;
-  }
-}
-
-static inline void arch_set_dma_addr(int dmanr, unsigned int addr)
-{
-  arch_dma_setup &= ~dmanr;
-  arch_dma_addr[dmanr] = addr;
-}
-
-static inline void arch_set_dma_count(int dmanr, unsigned int count)
-{
-  arch_dma_setup &= ~dmanr;
-  arch_dma_cnt[dmanr] = count;
-}
-
-static inline void arch_set_dma_mode(int dmanr, char mode)
-{
-  switch (mode) {
-  case DMA_MODE_READ:
-    arch_dma_ctrl[dmanr] |= DMA_CR_D;
-    break;
-  case DMA_MODE_WRITE:
-    arch_dma_ctrl[dmanr] &= ~DMA_CR_D;
-    break;
-  }
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-  return arch_dma_cnt[dmanr];
-}
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    switch(dmanr) {
-       case 1:  break;
-       case 2:  disable_irq(64); break;
-       default: printk(dma_str, "disable_dma", dmanr); break;
-    }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-#define clear_dma_ff(dmanr)
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
  */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
+#define MAX_DMA_ADDRESS                0xd0000000
 
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
+/*
+ * DMA modes - we have two, IN and OUT
  */
-extern int get_dma_residue(unsigned int dmanr);
+typedef enum {
+       DMA_MODE_READ,
+       DMA_MODE_WRITE
+} dmamode_t;
+
+#define MAX_DMA_CHANNELS       8
+
+#define DMA_0                  0
+#define DMA_1                  1
+#define DMA_2                  2
+#define DMA_3                  3
+#define DMA_S0                 4
+#define DMA_S1                 5
+#define DMA_VIRTUAL_FLOPPY     6
+#define DMA_VIRTUAL_SOUND      7
+
+#define DMA_FLOPPY             DMA_VIRTUAL_FLOPPY
 
 #endif /* _ASM_ARCH_DMA_H */
 
index 2bdd96c6f62639c1c0e425f2941c39520f2b79f4..75e112e9861afe3403e9bcbdbacb04bb1ce06c68 100644 (file)
@@ -85,6 +85,7 @@
 #define KERNEL_BASE            (PAGE_OFFSET + KERNEL_OFFSET)
 #define PARAMS_BASE            (PAGE_OFFSET + PARAMS_OFFSET)
 #define Z_PARAMS_BASE          (RAM_START + PARAMS_OFFSET)
+#define SAFE_ADDR              0x00000000      /* ROM */
 
 #else
 
index b78483cc8c05fb9be3494de8e7facbcfd985aa6b..43d787b9656729d3d94b7fcbdbfb377e9923d661 100644 (file)
@@ -9,16 +9,6 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x) ((unsigned long)(x))
-#define bus_to_virt(x) ((void *)(x))
-
 /*
  * This architecture does not require any delayed IO, and
  * has the constant-optimised IO
@@ -174,14 +164,7 @@ DECLARE_IO(long,l,"")
 })
 
 #define __ioaddrc(port)                                                                \
-({                                                                             \
-       unsigned long addr;                                                     \
-       if (__PORT_PCIO((port)))                                                \
-               addr = PCIO_BASE + ((port) << 2);                               \
-       else                                                                    \
-               addr = IO_BASE + ((port) << 2);                                 \
-       addr;                                                                   \
-})
+       (__PORT_PCIO((port)) ? PCIO_BASE + ((port) << 2) : IO_BASE + ((port) << 2))
 
 /*
  * Translated address IO functions
index 750f5c905296fb81121fe8b22523e37e395c0aa5..9ef1bacc7291614dfab9f279d8c95c1d04ee5914 100644 (file)
@@ -131,8 +131,4 @@ static __inline__ void irq_init_irq(void)
        outb(0, IOMD_IRQMASKB);
        outb(0, IOMD_FIQMASK);
        outb(0, IOMD_DMAMASK);
-       outb(0, IOMD_IO0CR);
-       outb(0, IOMD_IO1CR);
-       outb(0, IOMD_IO2CR);
-       outb(0, IOMD_IO3CR);
 }
index b7188fb8e0133bd84bbd351259618c9a342f7ca4..9adbc9c616dd0cc1f7bdee04db5f33245c97ccd7 100644 (file)
 #define IRQ_KEYBOARDTX         14
 #define IRQ_KEYBOARDRX         15
 
+#define IRQ_DMA0               16
+#define IRQ_DMA1               17
+#define IRQ_DMA2               18
+#define IRQ_DMA3               19
+#define IRQ_DMAS0              20
+#define IRQ_DMAS1              21
+
 #define FIQ_FLOPPYDATA         0
 #define FIQ_ECONET             2
 #define FIQ_SERIALPORT         4
 #define FIQ_EXPANSIONCARD      6
 #define FIQ_FORCE              7
+
+#define IRQ_TIMER              IRQ_TIMER0
diff --git a/include/asm-arm/arch-rpc/keyboard.h b/include/asm-arm/arch-rpc/keyboard.h
new file mode 100644 (file)
index 0000000..60d3f0b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * linux/include/asm-arm/arch-rpc/keyboard.h
+ *
+ * Keyboard driver definitions for RiscPC architecture
+ *
+ * (C) 1998 Russell King
+ */
+
+#include <asm/irq.h>
+
+#define NR_SCANCODES 128
+
+extern int ps2kbd_pretranslate(unsigned char scancode);
+extern int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
+extern void ps2kbd_leds(unsigned char leds);
+extern void ps2kbd_init_hw(void);
+extern unsigned char ps2kbd_sysrq_xlate[NR_SCANCODES];
+
+#define kbd_setkeycode(sc,kc)          (-EINVAL)
+#define kbd_getkeycode(sc)             (-EINVAL)
+
+/* Prototype: int kbd_pretranslate(scancode, raw_mode)
+ * Returns  : 0 to ignore scancode
+ */
+#define kbd_pretranslate(sc,rm)                ps2kbd_pretranslate(sc)
+
+/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
+ * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
+ *            set to 0200 if scancode indicates release
+ */
+#define kbd_translate(sc, kcp, ufp, rm)        ps2kbd_translate(sc, kcp, ufp)
+#define kbd_unexpected_up(kc)          (0200)
+#define kbd_leds(leds)                 ps2kbd_leds(leds)
+#define kbd_init_hw()                  ps2kbd_init_hw()
+#define kbd_sysrq_xlate                        ps2kbd_sysrq_xlate
+#define kbd_disable_irq()              disable_irq(IRQ_KEYBOARDRX)
+#define kbd_enable_irq()               enable_irq(IRQ_KEYBOARDRX)
+
diff --git a/include/asm-arm/arch-rpc/mm-init.h b/include/asm-arm/arch-rpc/mm-init.h
new file mode 100644 (file)
index 0000000..81de91a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * linux/include/asm-arm/arch-rpc/mmap.h
+ *
+ * Copyright (C) 1996 Russell King
+ */
+
+#define HAVE_MAP_VID_MEM
+
+unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
+{
+       static int updated = 0;
+       unsigned long address;
+       pgd_t *pgd;
+
+       if (updated)
+               return 0;
+       updated = update;
+
+       address = SCREEN_START | PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
+       pgd = swapper_pg_dir + (SCREEN2_BASE >> PGDIR_SHIFT);
+       pgd_val(pgd[0]) = address;
+       pgd_val(pgd[1]) = address + (1 << PGDIR_SHIFT);
+
+       if (update) {
+               unsigned long pgtable = PAGE_ALIGN(kmem), *p;
+               int i;
+
+               memzero ((void *)pgtable, 4096);
+               
+               pgd_val(pgd[-2]) = __virt_to_phys(pgtable) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
+               pgd_val(pgd[-1]) = __virt_to_phys(pgtable + PTRS_PER_PTE*4) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
+               p = (unsigned long *)pgtable;
+
+               i = PTRS_PER_PTE * 2 - ((SCREEN1_END - log_start) >> PAGE_SHIFT);
+               address = SCREEN_START | PTE_TYPE_SMALL | PTE_AP_WRITE;
+
+               while (i < PTRS_PER_PTE * 2) {
+                       p[i++] = address;
+                       address += PAGE_SIZE;
+               }
+
+               flush_page_to_ram(pgtable);
+
+               kmem = pgtable + PAGE_SIZE;
+       }
+       return kmem;
+}
diff --git a/include/asm-arm/arch-rpc/mmap.h b/include/asm-arm/arch-rpc/mmap.h
deleted file mode 100644 (file)
index 4a1cdea..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/mmap.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define HAVE_MAP_VID_MEM
-#define SAFE_ADDR 0x00000000   /* ROM */
-
-unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
-{
-       static int updated = 0;
-       unsigned long address;
-       pgd_t *pgd;
-
-       if (updated)
-               return 0;
-       updated = update;
-
-       address = SCREEN_START | PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
-       pgd = swapper_pg_dir + (SCREEN2_BASE >> PGDIR_SHIFT);
-       pgd_val(pgd[0]) = address;
-       pgd_val(pgd[1]) = address + (1 << PGDIR_SHIFT);
-
-       if (update) {
-               unsigned long pgtable = PAGE_ALIGN(kmem), *p;
-               int i;
-
-               memzero ((void *)pgtable, 4096);
-               
-               pgd_val(pgd[-2]) = virt_to_phys(pgtable) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-               pgd_val(pgd[-1]) = virt_to_phys(pgtable + PTRS_PER_PTE*4) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-               p = (unsigned long *)pgtable;
-
-               i = PTRS_PER_PTE * 2 - ((SCREEN1_END - log_start) >> PAGE_SHIFT);
-               address = SCREEN_START | PTE_TYPE_SMALL | PTE_AP_WRITE;
-
-               while (i < PTRS_PER_PTE * 2) {
-                       p[i++] = address;
-                       address += PAGE_SIZE;
-               }
-
-               flush_page_to_ram(pgtable);
-
-               kmem = pgtable + PAGE_SIZE;
-       }
-       return kmem;
-}
index fbd403d3670f40e811d9efaf726ec0922eafb589..7fca09aaa3e34c50b3fe2c1952d76d5a3226a856 100644 (file)
@@ -7,6 +7,7 @@
  *  20-10-1996 RMK     Created
  *  31-12-1997 RMK     Fixed definitions to reduce warnings
  *  11-01-1998 RMK     Uninlined to reduce hits on cache
+ *  08-02-1998 RMK     Added __virt_to_bus and __bus_to_virt
  */
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 extern unsigned long __virt_to_phys(unsigned long vpage);
 extern unsigned long __phys_to_virt(unsigned long ppage);
 
+/*
+ * These are exactly the same on the RiscPC as the
+ * physical memory view.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x) __phys_to_virt(x)
+
 #endif
index d5c47873785c4e301eb304df3bd6908f5704c993..61ab21538c480e66a5e695ee8d14e765038be474 100644 (file)
@@ -29,6 +29,6 @@
 #define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
 
 #define INIT_MMAP \
-{ &init_mm, 0xc0000000, 0xc2000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+{ &init_mm, 00, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
index de645f76dc60e4b43db783b2012e3ad44dc5e3b6..577d18d1ed7ce9116dcdc3e0bf83d695488c456d 100644 (file)
@@ -77,7 +77,7 @@ static void puts(const char *s)
                        }
                } else {
                        ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h);
-                       ll_write_char(ptr, c|(white<<8));
+                       ll_write_char(ptr, c|(white<<16));
                        if ( ++x >= video_num_columns ) {
                                x = 0;
                                if ( ++y >= video_num_lines ) {
index 718fbb2b81305904e3f48ed00c2526ba4a634f7b..d8b9f1d3a2b1d5e5d3dc6691802031a943c44604 100644 (file)
 #ifndef __ASM_ARM_DMA_H
 #define __ASM_ARM_DMA_H
 
-#include <asm/irq.h>
+typedef unsigned int dmach_t;
 
-#define MAX_DMA_CHANNELS       14
-#define DMA_0                  8
-#define DMA_1                  9
-#define DMA_2                  10
-#define DMA_3                  11
-#define DMA_S0                 12
-#define DMA_S1                 13
+#include <asm/irq.h>
+#include <asm/arch/dma.h>
 
-#define DMA_MODE_READ          0x44
-#define DMA_MODE_WRITE         0x48
+typedef struct {
+       unsigned long address;
+       unsigned long length;
+} dmasg_t;
 
 extern const char dma_str[];
 
-#include <asm/arch/dma.h>
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ *
+ * NOTE: This is an architecture specific function, and should
+ *       be hidden from the drivers.
+ */
+#define clear_dma_ff(channel)
 
-/* These are in kernel/dma.c: */
-/* reserve a DMA channel */
-extern int request_dma(unsigned int dmanr, const char * device_id);
-/* release it again */
-extern void free_dma(unsigned int dmanr);
+/* Set only the page register bits of the transfer address.
+ *
+ * NOTE: This is an architecture specific function, and should
+ *       be hidden from the drivers
+ */
+static __inline__ void set_dma_page(dmach_t channel, char pagenr)
+{
+       printk(dma_str, "set_dma_page", channel);
+}
 
-#endif /* _ARM_DMA_H */
+/* Request a DMA channel
+ *
+ * Some architectures may need to do allocate an interrupt
+ */
+extern int  request_dma(dmach_t channel, const char * device_id);
+
+/* Free a DMA channel
+ *
+ * Some architectures may need to do free an interrupt
+ */
+extern void free_dma(dmach_t channel);
+
+/* Enable DMA for this channel
+ *
+ * On some architectures, this may have other side effects like
+ * enabling an interrupt and setting the DMA registers.
+ */
+extern void enable_dma(dmach_t channel);
+
+/* Disable DMA for this channel
+ *
+ * On some architectures, this may have other side effects like
+ * disabling an interrupt or whatever.
+ */
+extern void disable_dma(dmach_t channel);
 
+/* Set the DMA scatter gather list for this channel
+ *
+ * This should not be called if a DMA channel is enabled,
+ * especially since some DMA architectures don't update the
+ * DMA address immediately, but defer it to the enable_dma().
+ */
+extern void set_dma_sg(dmach_t channel, dmasg_t *sg, int nr_sg);
+
+/* Set the DMA address for this channel
+ *
+ * This should not be called if a DMA channel is enabled,
+ * especially since some DMA architectures don't update the
+ * DMA address immediately, but defer it to the enable_dma().
+ */
+extern void set_dma_addr(dmach_t channel, unsigned long physaddr);
+
+/* Set the DMA byte count for this channel
+ *
+ * This should not be called if a DMA channel is enabled,
+ * especially since some DMA architectures don't update the
+ * DMA count immediately, but defer it to the enable_dma().
+ */
+extern void set_dma_count(dmach_t channel, unsigned long count);
+
+/* Set the transfer direction for this channel
+ *
+ * This should not be called if a DMA channel is enabled,
+ * especially since some DMA architectures don't update the
+ * DMA transfer direction immediately, but defer it to the
+ * enable_dma().
+ */
+extern void set_dma_mode(dmach_t channel, dmamode_t mode);
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ */
+extern int  get_dma_residue(dmach_t channel);
+
+#ifndef NO_DMA
+#define NO_DMA 255
+#endif
+
+#endif /* _ARM_DMA_H */
index 3ca8cf1fb1f599609e7989ff58f84d5a6948eaa6..fed84980d0c3e781e85f9dd7431552ac79de9bb6 100644 (file)
@@ -16,7 +16,8 @@
 #define __ASM_ECARD_H
 
 /*
- * Currently understood cards
+ * Currently understood cards (but not necessarily
+ * supported):
  *                        Manufacturer  Product ID
  */
 #define MANU_ACORN             0x0000
@@ -60,6 +61,8 @@
 #define MANU_MCS               0x0063
 #define PROD_MCS_CONNECT32             0x0125
 
+#define MANU_EESOX             0x0064
+#define PROD_EESOX_SCSI2               0x008c
 
 
 #ifdef ECARD_C
@@ -72,8 +75,9 @@
 
 /* Type of card's address space */
 typedef enum {
-       ECARD_IOC  = 0,
-       ECARD_MEMC = 1
+       ECARD_IOC,
+       ECARD_MEMC,
+       ECARD_DEBI
 } card_type_t;
 
 /* Speed of card for ECARD_IOC address space */
@@ -124,10 +128,12 @@ struct expansion_card {
        unsigned char           irqmask;        /* IRQ mask                     */
        unsigned char           fiqmask;        /* FIQ mask                     */
        unsigned char           claimed;        /* Card claimed?                */
+
        CONST unsigned char     slot_no;        /* Slot number                  */
+       CONST unsigned char     dma;            /* DMA number (for request_dma) */
        CONST unsigned char     irq;            /* IRQ number (for request_irq) */
        CONST unsigned char     fiq;            /* FIQ number (for request_irq) */
-       CONST unsigned short    unused;
+
        CONST struct in_ecld    cld;            /* Card Identification          */
        void                    *irq_data;      /* Data for use for IRQ by card */
        void                    *fiq_data;      /* Data for use for FIQ by card */
index cf49fbfa110ed24a04b22dee6ca68163e7f35136..139481831ebfe5f4dbed065fd79c6ded4899dfb8 100644 (file)
@@ -38,6 +38,23 @@ typedef struct { void *null; } elf_fpregset_t;
 
 #define ELF_ET_DYN_BASE        (2 * TASK_SIZE / 3)
 
+/* This yields a mask that user programs can use to figure out what
+   instruction set this cpu supports.  This could be done in userspace,
+   but it's not easy, and we've already done it here.  */
+
+#define ELF_HWCAP      (0)
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo. */
+
+#define ELF_PLATFORM   (NULL)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex,ibcs2) \
+       current->personality = PER_LINUX_32BIT
+#endif
+
 #define R_ARM_NONE     (0)
 #define R_ARM_32       (1)     /* => ld 32 */
 #define R_ARM_PC26     (2)     /* => ld b/bl branches */
index 0e38fc8900eecd5ba69bcfab813b0cd14328e250..bd25d1838a92ae6774f6f61f4d1e8edf33fa8547 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/tasks.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
 
 #ifndef __SMP__
 
index 6b3cbfaba68e96068c13c6eba658deac56a102cf..c21abeed3bec3191dbbf708a47f3a50c2b259156 100644 (file)
@@ -140,6 +140,11 @@ do {                                                               \
 #define IOMD_ECTCR     __IOMD(0x0C8)
 #define IOMD_DMAEXT    __IOMD(0x0CC)
 
+#define DMA_EXT_IO0    1
+#define DMA_EXT_IO1    2
+#define DMA_EXT_IO2    4
+#define DMA_EXT_IO3    8
+
 #define IOMD_IO0CURA   __IOMD(0x100)
 #define IOMD_IO0ENDA   __IOMD(0x104)
 #define IOMD_IO0CURB   __IOMD(0x108)
@@ -195,6 +200,9 @@ do {                                                                \
 #define IOMD_DMAREQ    __IOMD(0x1F4)
 #define IOMD_DMAMASK   __IOMD(0x1F8)
 
+#define DMA_END_S      (1 << 31)
+#define DMA_END_L      (1 << 30)
+
 #define DMA_CR_C       0x80
 #define DMA_CR_D       0x40
 #define DMA_CR_E       0x20
index 8703c920af64be7dedec56be5ec2b1aaede431b2..2451663e34c266fb23fb5c749fdd6b745950afe9 100644 (file)
 #include <asm/arch/io.h>
 
 /* unsigned long virt_to_phys(void *x) */
-#define virt_to_phys(x)                __virt_to_phys((unsigned long)(x))
+#define virt_to_phys(x)                (__virt_to_phys((unsigned long)(x)))
 
 /* void *phys_to_virt(unsigned long x) */
 #define phys_to_virt(x)                ((void *)(__phys_to_virt((unsigned long)(x))))
 
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+#define virt_to_bus(x) (__virt_to_bus((unsigned long)(x)))
+#define bus_to_virt(x) ((void *)(__bus_to_virt(x)))
+
 /*
  * These macros actually build the multi-value IO function prototypes
  */
diff --git a/include/asm-arm/irq-no.h b/include/asm-arm/irq-no.h
deleted file mode 100644 (file)
index 7d599cb..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * linux/include/asm-arm/irq-no.h
- *
- * Machine independent interrupt numbers
- */
-
-#include <asm/arch/irqs.h>
-
-#ifndef NR_IRQS
-#define NR_IRQS                128
-#endif
index f7a7a8934b1ce0ed214d6a48af2b7d4f9c9e2232..99b949ddb27ace852a305feac7a12042d0dabd86 100644 (file)
@@ -1,7 +1,19 @@
 #ifndef __ASM_ARM_IRQ_H
 #define __ASM_ARM_IRQ_H
 
-#include <asm/irq-no.h>
+#include <asm/arch/irqs.h>
+
+#ifndef NR_IRQS
+#define NR_IRQS        128
+#endif
+
+/*
+ * Use this value to indicate lack of interrupt
+ * capability
+ */
+#ifndef NO_IRQ
+#define NO_IRQ 255
+#endif
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff --git a/include/asm-arm/keyboard.h b/include/asm-arm/keyboard.h
new file mode 100644 (file)
index 0000000..6b64ec6
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * linux/include/asm-arm/keyboard.h
+ *
+ * Keyboard driver definitions for ARM
+ *
+ * (C) 1998 Russell King
+ */
+#ifndef __ASM_ARM_KEYBOARD_H
+#define __ASM_ARM_KEYBOARD_H
+
+/*
+ * We provide a unified keyboard interface when in VC_MEDIUMRAW
+ * mode.  This means that all keycodes must be common between
+ * all supported keyboards.  This unfortunately puts us at odds
+ * with the PC keyboard interface chip... but we can't do anything
+ * about that now.
+ */
+#ifdef __KERNEL__
+
+#include <asm/arch/keyboard.h>
+
+#define SYSRQ_KEY 13
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_ARM_KEYBOARD_H */
diff --git a/include/asm-arm/leds.h b/include/asm-arm/leds.h
new file mode 100644 (file)
index 0000000..d253e2a
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * include/asm-arm/leds.h
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * Event-driven interface for LEDs on machines
+ */
+#ifndef ASM_ARM_LEDS_H
+#define ASM_ARM_LEDS_H
+
+typedef enum {
+       led_idle_start,
+       led_idle_end,
+       led_timer
+} led_event_t;
+
+/* Use this routine to handle LEDs */
+extern void leds_event(led_event_t);
+
+#endif
index 0da437ff7be1ecd22a006fa7e588e7887e910b8e..f76b404c5e1b1267d678342be997ad76120cb88e 100644 (file)
@@ -113,6 +113,15 @@ extern __inline__ void copy_thread_css (struct context_save_struct *save)
        flush_tlb_mm(current->mm);                                      \
 })
 
+/* Allocation and freeing of basic task resources. */
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+       ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
+#define free_task_struct(p)    free_pages((unsigned long)(p),1)
+
+
 #endif
 
 #endif
index 0ffb05a1624ea8faa41fb557e7facc0bfa5578c6..287779258fd3a4a880309bc1e7d7d869daf41954 100644 (file)
  *
  * We set it up using the section page table entries.
  */
-
-#include <asm/arch/mmap.h>
 #include <asm/pgtable.h>
  
-#define V2P(x) virt_to_phys(x)
 #define PTE_SIZE (PTRS_PER_PTE * 4)
 
-#define PMD_SECT       (PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_CACHEABLE)
+extern unsigned long setup_io_pagetables(unsigned long start_mem);
 
-static inline void setup_swapper_dir (int index, unsigned long entry)
+/*
+ * Add a SECTION mapping between VIRT and PHYS in domain DOMAIN with protection PROT
+ */
+static inline void
+alloc_init_section(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
 {
-       pmd_t pmd;
+       pgd_t *pgdp;
+       pmd_t *pmdp;
 
-       pmd_val(pmd) = entry;
-       set_pmd (pmd_offset (swapper_pg_dir + index, 0), pmd);
+       pgdp = pgd_offset_k(virt);
+       pmdp = pmd_offset(pgdp, virt);
+
+       pmd_val(*pmdp) = phys | PMD_TYPE_SECT | PMD_DOMAIN(domain) | prot;
 }
 
-static inline unsigned long setup_pagetables(unsigned long start_mem, unsigned long end_mem)
+/*
+ * Clear any mapping
+ */
+static inline void
+free_init_section(unsigned long virt)
 {
-       unsigned long address;
-       unsigned int spi;
-       union { unsigned long l; unsigned long *p; } u;
-
-       /* map in zero page */
-       u.l = ((start_mem + (PTE_SIZE-1)) & ~(PTE_SIZE-1));
-       start_mem = u.l + PTE_SIZE;
-       memzero (u.p, PTE_SIZE);
-       *u.p = V2P(PAGE_OFFSET) | PTE_CACHEABLE | PTE_TYPE_SMALL;
-       setup_swapper_dir (0, V2P(u.l) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER));
-
-       for (spi = 1; spi < (PAGE_OFFSET >> PGDIR_SHIFT); spi++)
-               pgd_val(swapper_pg_dir[spi]) = 0;
-
-       /* map in physical ram & kernel */
-       address = PAGE_OFFSET;
-       while (spi < end_mem >> PGDIR_SHIFT) {
-               setup_swapper_dir (spi++,
-                               V2P(address) | PMD_SECT |
-                               PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
-               address += PGDIR_SIZE;
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+
+       pgdp = pgd_offset_k(virt);
+       pmdp = pmd_offset(pgdp, virt);
+
+       pmd_clear(pmdp);
+}
+
+/*
+ * Add a PAGE mapping between VIRT and PHYS in domain DOMAIN with protection PROT
+ */
+static inline void
+alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
+{
+       pgd_t *pgdp;
+       pmd_t *pmdp;
+       pte_t *ptep;
+
+       pgdp = pgd_offset_k(virt);
+       pmdp = pmd_offset(pgdp, virt);
+
+       if (pmd_none(*pmdp)) {
+               unsigned long memory = *mem;
+
+               memory = (memory + PTE_SIZE - 1) & ~(PTE_SIZE - 1);
+
+               ptep = (pte_t *)memory;
+               memzero(ptep, PTE_SIZE);
+
+               pmd_val(*pmdp) = __virt_to_phys(memory) | PMD_TYPE_TABLE | PMD_DOMAIN(domain);
+
+               *mem = memory + PTE_SIZE;
        }
-       while (spi < PTRS_PER_PGD)
-               pgd_val(swapper_pg_dir[spi++]) = 0;
+
+       ptep = pte_offset(pmdp, virt);
+
+       pte_val(*ptep) = phys | prot | PTE_TYPE_SMALL;
+}
+
+static inline unsigned long
+setup_pagetables(unsigned long start_mem, unsigned long end_mem)
+{
+       unsigned long address;
+
+       /*
+        * map in zero page
+        */
+       alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET), DOMAIN_USER, PTE_CACHEABLE);
+
+       /*
+        * ensure no mappings in user space
+        */
+       for (address = PGDIR_SIZE; address < PAGE_OFFSET; address += PGDIR_SIZE)
+               free_init_section(address);
+
+       /*
+        * map in physical ram & kernel
+        */
+       for (address = PAGE_OFFSET; address < end_mem; address += PGDIR_SIZE)
+               alloc_init_section(&start_mem, address, __virt_to_phys(address), DOMAIN_KERNEL,
+                                  PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
+
+       /*
+        * unmap everything else
+        */
+       for (address = end_mem; address; address += PGDIR_SIZE)
+               free_init_section(address);
 
        /*
         * An area to invalidate the cache
         */
-       setup_swapper_dir (0xdf0, SAFE_ADDR | PMD_SECT | PMD_SECT_AP_READ);
-
-       /* map in IO */
-       address = IO_START;
-       spi = IO_BASE >> PGDIR_SHIFT;
-       pgd_val(swapper_pg_dir[spi-1]) = 0xc0000000 | PMD_TYPE_SECT |
-                                        PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
-       while (address < IO_START + IO_SIZE && address) {
-               pgd_val(swapper_pg_dir[spi++]) = address |
-                                               PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_IO) |
-                                               PMD_SECT_AP_WRITE;
-               address += PGDIR_SIZE;
-       }
+       alloc_init_section(&start_mem, 0xdf000000, SAFE_ADDR, DOMAIN_KERNEL,
+                          PMD_SECT_CACHEABLE | PMD_SECT_AP_READ);
 
-#ifdef HAVE_MAP_VID_MEM
-       map_screen_mem(0, 0, 0);
-#endif
+       /*
+        * Now set up our IO mappings
+        */
+       start_mem = setup_io_pagetables(start_mem);
 
        flush_cache_all();
+
        return start_mem;
 }
 
-static inline void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
+static inline
+void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
 {
        unsigned long smem;
 
index 20778c1931c87c78b990e1f08da15c10a58c82ac..288e4043a5d05a6aacadb2ff6753e06f313b5ae5 100644 (file)
 
 /*
  * We define the bits in the page tables as follows:
- *  PTE_BUFFERABLE     page is dirty
- *  PTE_AP_WRITE       page is writable
+ *  PTE_BUFFERABLE     page is writable
+ *  PTE_AP_WRITE       page is dirty
  *  PTE_AP_READ                page is a young (unsetting this causes faults for any access)
  *
  * Any page that is mapped in is assumed to be readable...
  */
-#define PAGE_NONE       __pgprot(PTE_TYPE_SMALL)
-#define PAGE_SHARED     __pgprot(PTE_TYPE_SMALL | PTE_CACHEABLE | PTE_AP_READ | PTE_AP_WRITE)
-#define PAGE_COPY       __pgprot(PTE_TYPE_SMALL | PTE_CACHEABLE | PTE_AP_READ)
-#define PAGE_READONLY   __pgprot(PTE_TYPE_SMALL | PTE_CACHEABLE | PTE_AP_READ)
-#define PAGE_KERNEL     __pgprot(PTE_TYPE_SMALL | PTE_CACHEABLE | PTE_BUFFERABLE | PTE_AP_WRITE)
+#if 0
+#define _PTE_YOUNG     PTE_AP_READ
+#define _PTE_DIRTY     PTE_AP_WRITE
+#define _PTE_READ      PTE_CACHEABLE
+#define _PTE_WRITE     PTE_BUFFERABLE
+#else
+#define _PTE_YOUNG     PTE_CACHEABLE
+#define _PTE_DIRTY     PTE_BUFFERABLE
+#define _PTE_READ      PTE_AP_READ
+#define _PTE_WRITE     PTE_AP_WRITE
+#endif
+
+#define PAGE_NONE       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG)
+#define PAGE_SHARED     __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ | _PTE_WRITE)
+#define PAGE_COPY       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
+#define PAGE_READONLY   __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
+#define PAGE_KERNEL     __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_DIRTY | _PTE_WRITE)
 
 #define _PAGE_USER_TABLE       (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
 #define _PAGE_KERNEL_TABLE     (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
@@ -249,7 +261,7 @@ extern unsigned long *empty_zero_page;
 /* to set the page-dir */
 #define SET_PAGE_DIR(tsk,pgdir)                                        \
 do {                                                           \
-       tsk->tss.memmap = __virt_to_phys(pgdir);                \
+       tsk->tss.memmap = __virt_to_phys((unsigned long)pgdir); \
        if ((tsk) == current)                                   \
                __asm__ __volatile__(                           \
                "mcr%?  p15, 0, %0, c2, c0, 0\n"                \
@@ -276,7 +288,7 @@ extern __inline__ int pte_present(pte_t pte)
                return 0;
        }
 #else
-       return ((pte_val(pmd) + 1) & PMD_TYPE_MASK);
+       return ((pte_val(pte) + 1) & 2);
 #endif
 }
 
@@ -300,18 +312,24 @@ extern __inline__ int pmd_bad(pmd_t pmd)
                return 1;
        }
 #else
-       return (pmd_val(pmd) & PMD_TYPE_SECT);
+       return pmd_val(pmd) & 2;
 #endif
 }
 
 extern __inline__ int pmd_present(pmd_t pmd)
 {
+#if 0
+       /* This is what it really does, the else
+          part is just to make it easier for the compiler */
        switch (pmd_val(pmd) & PMD_TYPE_MASK) {
        case PMD_TYPE_TABLE:
                return 1;
        default:
                return 0;
        }
+#else
+       return ((pmd_val(pmd) + 1) & 2);
+#endif
 }
 
 /*
@@ -336,19 +354,14 @@ extern __inline__ int pte_write(pte_t pte)
        return pte_val(pte) & PTE_AP_WRITE;
 }
 
-extern __inline__ int pte_cacheable(pte_t pte)
-{
-       return pte_val(pte) & PTE_CACHEABLE;
-}
-
 extern __inline__ int pte_dirty(pte_t pte)
 {
-       return pte_val(pte) & PTE_BUFFERABLE;
+       return pte_val(pte) & _PTE_DIRTY;
 }
 
 extern __inline__ int pte_young(pte_t pte)
 {
-       return pte_val(pte) & PTE_AP_READ;
+       return pte_val(pte) & _PTE_YOUNG;
 }
 
 extern __inline__ pte_t pte_wrprotect(pte_t pte)
@@ -455,7 +468,7 @@ extern __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
 
 extern __inline__ unsigned long pte_page(pte_t pte)
 {
-       return (unsigned long)phys_to_virt(pte_val(pte) & PAGE_MASK);
+       return __phys_to_virt(pte_val(pte) & PAGE_MASK);
 }
 
 extern __inline__ pmd_t mk_user_pmd(pte_t *ptep)
@@ -484,7 +497,7 @@ extern __inline__ void set_pmd(pmd_t *pmdp, pmd_t pmd)
 
 extern __inline__ unsigned long pmd_page(pmd_t pmd)
 {
-       return (unsigned long)phys_to_virt(pmd_val(pmd) & 0xfffffc00);
+       return __phys_to_virt(pmd_val(pmd) & 0xfffffc00);
 }
 
 /* to find an entry in a kernel page-table-directory */
@@ -513,13 +526,14 @@ extern void free_small_page(unsigned long page);
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
+
 #ifndef __SMP__
 extern struct pgtable_cache_struct {
        unsigned long *pgd_cache;
        unsigned long *pte_cache;
        unsigned long pgtable_cache_sz;
 } quicklists;
+
 #define pgd_quicklist (quicklists.pgd_cache)
 #define pmd_quicklist ((unsigned long *)0)
 #define pte_quicklist (quicklists.pte_cache)
@@ -596,8 +610,8 @@ extern __inline__ void free_pmd_slow(pmd_t *pmd)
 {
 }
 
-extern void __bad_pte(pmd_t *pmd);
-extern void __bad_pte_kernel(pmd_t *pmd);
+extern void __bad_pmd(pmd_t *pmd);
+extern void __bad_pmd_kernel(pmd_t *pmd);
 
 #define pte_free_kernel(pte)   free_pte_fast(pte)
 #define pte_free(pte)          free_pte_fast(pte)
@@ -616,7 +630,7 @@ extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
                return page + address;
        }
        if (pmd_bad(*pmd)) {
-               __bad_pte_kernel(pmd);
+               __bad_pmd_kernel(pmd);
                return NULL;
        }
        return (pte_t *) pmd_page(*pmd) + address;
@@ -628,14 +642,14 @@ extern __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 
        if (pmd_none(*pmd)) {
                pte_t *page = (pte_t *) get_pte_fast();
-               
+
                if (!page)
                        return get_pte_slow(pmd, address);
-               set_pmd(pmd, mk_user_pmd(page);
+               set_pmd(pmd, mk_user_pmd(page));
                return page + address;
        }
        if (pmd_bad(*pmd)) {
-               __bad_pte(pmd);
+               __bad_pmd(pmd);
                return NULL;
        }
        return (pte_t *) pmd_page(*pmd) + address;
@@ -654,9 +668,10 @@ extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
        return (pmd_t *) pgd;
 }
 
-#define pmd_free_kernel         pmd_free
-#define pmd_alloc_kernel        pmd_alloc
+#define pmd_free_kernel                pmd_free
+#define pmd_alloc_kernel       pmd_alloc
 
+#if 0
 extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
 {
        struct task_struct * p;
@@ -672,6 +687,7 @@ extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
        for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
                pgd[address >> PGDIR_SHIFT] = entry;
 }
+#endif
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
@@ -689,4 +705,3 @@ extern __inline__ void update_mmu_cache(struct vm_area_struct * vma,
 #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
 
 #endif /* __ASM_PROC_PAGE_H */
-
index acb22e191d4109edef3730c6d0a26f8d54cec9f4..294dead681e88df664d215ec1ba079063befc48d 100644 (file)
@@ -82,7 +82,10 @@ extern __inline__ void copy_thread_css (struct context_save_struct *save)
        unsigned long *stack = (unsigned long *)sp;                     \
        set_fs(USER_DS);                                                \
        memzero(regs->uregs, sizeof(regs->uregs));                      \
-       regs->ARM_cpsr = sp <= 0x04000000 ? USR26_MODE : USR_MODE;      \
+       if (current->personality == PER_LINUX_32BIT)                    \
+               regs->ARM_cpsr = USR_MODE;                              \
+       else                                                            \
+               regs->ARM_cpsr = USR26_MODE;                            \
        regs->ARM_pc = pc;              /* pc */                        \
        regs->ARM_sp = sp;              /* sp */                        \
        regs->ARM_r2 = stack[2];        /* r2 (envp) */                 \
index 6a1f38de08795da89ddec6914a693d0d8230a1d1..0ef12de11dd4592f23c9a605dd2e7fdfbdef515e 100644 (file)
@@ -33,16 +33,13 @@ extern __inline__ void proc_hard_reset(void)
 /*
  * We can wait for an interrupt...
  */
-#if 0
 #define proc_idle()                    \
        do {                            \
        __asm__ __volatile__(           \
 "      mcr     p15, 0, %0, c15, c8, 2" \
          : : "r" (0));                 \
        } while (0)
-#else
-#define proc_idle()
-#endif
+
 /*
  * A couple of speedups for the ARM
  */
index 888933936c2ff3f9196391c832114fcaf76272ef..adcc91c057a61beb918443753b2d69386daa0b0d 100644 (file)
@@ -3,5 +3,10 @@
 
 #ifdef __SMP__
 #error SMP not supported
+#else
+
+#define cpu_logical_map(cpu) (cpu)
+
 #endif
+
 #endif
index 312aef936d21a2cda87db6cc4af736db48756b98..91de70e6ec988d84c63d29b9463c902db542da54 100644 (file)
 #define SO_RCVTIMEO    20
 #define SO_SNDTIMEO    21
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
+#define SO_SECURITY_ENCRYPTION_NETWORK         24
+
 #define SO_BINDTODEVICE 25
 
 #endif /* _ASM_SOCKET_H */
index a9208b42170068ae547e23c05f604133e9b9b11a..ba99f96f640bc168443e5766d60830cd54e83d97 100644 (file)
@@ -4,6 +4,9 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
+extern unsigned int local_bh_count[NR_CPUS];
+#define in_bh()                        (local_bh_count[smp_processor_id()] != 0)
+
 #define get_active_bhs()       (bh_mask & bh_active)
 #define clear_active_bhs(x)    atomic_clear_mask((int)(x),&bh_active)
 
@@ -25,44 +28,44 @@ extern inline void mark_bh(int nr)
        set_bit(nr, &bh_active);
 }
 
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
-       bh_mask &= ~(1 << nr);
-       bh_mask_count[nr]++;
-}
-
-extern inline void enable_bh(int nr)
-{
-       if (!--bh_mask_count[nr])
-               bh_mask |= 1 << nr;
-}
-
 #ifdef __SMP__
 #error SMP not supported
 #else
 
-extern int __arm_bh_counter;
-
 extern inline void start_bh_atomic(void)
 {
-       __arm_bh_counter++;
+       local_bh_count[smp_processor_id()]++;
        barrier();
 }
 
 extern inline void end_bh_atomic(void)
 {
        barrier();
-       __arm_bh_counter--;
+       local_bh_count[smp_processor_id()]--;
 }
 
 /* These are for the irq's testing the lock */
-#define softirq_trylock()      (__arm_bh_counter ? 0 : (__arm_bh_counter=1))
-#define softirq_endlock()      (__arm_bh_counter = 0)
+#define softirq_trylock(cpu)   (in_bh() ? 0 : (local_bh_count[smp_processor_id()]=1))
+#define softirq_endlock(cpu)   (local_bh_count[smp_processor_id()] = 0)
+#define synchronize_bh()       do { } while (0)
 
 #endif /* SMP */
 
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+       bh_mask &= ~(1 << nr);
+       bh_mask_count[nr]++;
+       synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+       if (!--bh_mask_count[nr])
+               bh_mask |= 1 << nr;
+}
+
 #endif /* __ASM_SOFTIRQ_H */
index 38ea298552670bb9609ac85035c4497e6583ef7a..a1e76285adac7b1dedf4951021bfb7df3fc51873 100644 (file)
@@ -39,6 +39,8 @@ typedef unsigned int u32;
 typedef signed long long s64;
 typedef unsigned long long u64;
 
+#define BITS_PER_LONG 32
+
 #endif /* __KERNEL__ */
 
 #endif
index a19d724764e26f94aebbf0af346ed5569b54657b..336eae8f50707c1c496012f4f2080e42735bdd4f 100644 (file)
@@ -138,8 +138,8 @@ __asm__("movw %%dx,%0\n\t" \
         "d" (limit) \
        :"dx")
 
-#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
-#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
+#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
+#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
 
 static inline unsigned long _get_base(char * addr)
 {
index bddb6706762be936b6a66e22fe3d741170a9790e..f5ef3f250bacbaf33aecfe9a6dfff9dfc476ca4e 100644 (file)
@@ -1,11 +1,21 @@
-/* $Revision: 2.1 $$Date: 1997/10/24 16:03:00 $
+/* $Revision: 2.3 $$Date: 1998/03/16 18:01:12 $
  * linux/include/linux/cyclades.h
  *
- * This file is maintained by Marcio Saito <marcio@cyclades.com> and
+ * This file is maintained by Ivan Passos <ivan@cyclades.com>, 
+ * Marcio Saito <marcio@cyclades.com> and
  * Randolph Bentson <bentson@grieg.seaslug.org>.
  *
  * This file contains the general definitions for the cyclades.c driver
  *$Log: cyclades.h,v $
+ *Revision 2.3  1998/03/16 18:01:12  ivan
+ *changes in the cyclades_port structure to get it closer to the 
+ *standard serial port structure;
+ *added constants for new ioctls;
+ *Revision 2.2  1998/02/17 16:50:00  ivan
+ *changes in the cyclades_port structure (addition of shutdown_wait and 
+ *chip_rev variables);
+ *added constants for new ioctls and for CD1400 rev. numbers.
+ *
  *Revision 2.1 1997/10/24 16:03:00  ivan
  *added rflow (which allows enabling the CD1400 special flow control 
  *feature) and rtsdtr_inv (which allows DTR/RTS pin inversion) to 
@@ -58,10 +68,14 @@ struct cyclades_monitor {
 #define CYGETDEFTIMEOUT         0x435908
 #define CYSETDEFTIMEOUT         0x435909
 #define CYSETRFLOW             0x43590a
-#define CYRESETRFLOW           0x43590b
+#define CYGETRFLOW             0x43590b
 #define CYSETRTSDTR_INV                0x43590c
-#define CYRESETRTSDTR_INV      0x43590d
+#define CYGETRTSDTR_INV                0x43590d
 #define CYZPOLLCYCLE           0x43590e
+#define CYGETCD1400VER         0x43590f
+#define CYGETCARDINFO          0x435910
+#define        CYSETWAIT               0x435911
+#define        CYGETWAIT               0x435912
 
 /*************** CYCLOM-Z ADDITIONS ***************/
 
@@ -78,6 +92,8 @@ struct cyclades_monitor {
 #define MAX_PORT        128     /* Max number of ports per board */
 #define MAX_DEV         256     /* Max number of ports total */
 
+#define        CYZ_FIFO_SIZE   16
+
 #define CYZ_BOOT_NWORDS 0x100
 struct CYZ_BOOT_CTRL {
         unsigned short  nboard;
@@ -473,12 +489,13 @@ struct cyclades_chip {
 
 struct cyclades_port {
        int                     magic;
-       int                     type;
        int                     card;
        int                     line;
        int                     flags;          /* defined in tty.h */
+       int                     type;           /* UART type */
        struct tty_struct       *tty;
        int                     read_status_mask;
+       int                     ignore_status_mask;
        int                     timeout;
        int                     xmit_fifo_size;
        int                     cor1,cor2,cor3,cor4,cor5;
@@ -486,13 +503,15 @@ struct cyclades_port {
        int                     baud;
        int                     rflow;
        int                     rtsdtr_inv;
-       int                     ignore_status_mask;
+       int                     chip_rev;
+       int                     custom_divisor;
+       int                     x_char; /* to be pushed out ASAP */
        int                     close_delay;
-       int                     IER;    /* Interrupt Enable Register */
-       int                     event;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
        unsigned long           last_active;
        int                     count;  /* # of fd on device */
-       int                     x_char; /* to be pushed out ASAP */
        int                     x_break;
        int                     blocked_open; /* # of blocked opens */
        long                    session; /* Session of opening process */
@@ -508,6 +527,7 @@ struct cyclades_port {
        struct termios          callout_termios;
        struct wait_queue       *open_wait;
        struct wait_queue       *close_wait;
+       struct wait_queue       *shutdown_wait;
         struct cyclades_monitor mon;
        unsigned long           jiffies[3];
        unsigned long           rflush_count;
@@ -517,13 +537,14 @@ struct cyclades_port {
  * Events are used to schedule things to happen at timer-interrupt
  * time, instead of at cy interrupt time.
  */
-#define Cy_EVENT_READ_PROCESS  0
-#define Cy_EVENT_WRITE_WAKEUP  1
-#define Cy_EVENT_HANGUP                2
-#define Cy_EVENT_BREAK         3
-#define Cy_EVENT_OPEN_WAKEUP   4
-
+#define Cy_EVENT_READ_PROCESS          0
+#define Cy_EVENT_WRITE_WAKEUP          1
+#define Cy_EVENT_HANGUP                        2
+#define Cy_EVENT_BREAK                 3
+#define Cy_EVENT_OPEN_WAKEUP           4
+#define Cy_EVENT_SHUTDOWN_WAKEUP       5
 
+#define        CLOSING_WAIT_DELAY      30
 
 #define CyMAX_CHIPS_PER_CARD   8
 #define CyMAX_CHAR_FIFO                12
@@ -538,10 +559,13 @@ struct cyclades_port {
 
 /**** CD1400 registers ****/
 
-#define CyRegSize  0x0400
-#define Cy_HwReset 0x1400
-#define Cy_ClrIntr 0x1800
-#define Cy_EpldRev 0x1e00
+#define CD1400_REV_G   0x46
+#define CD1400_REV_J   0x48
+
+#define CyRegSize      0x0400
+#define Cy_HwReset     0x1400
+#define Cy_ClrIntr     0x1800
+#define Cy_EpldRev     0x1e00
 
 /* Global Registers */
 
index 8183b8e94879243c278d94dd7eff99b68f49830a..31bab91a41041b43af83e9598f3264252dc01432 100644 (file)
@@ -64,6 +64,7 @@
 #define ARPHRD_PIMREG  779             /* PIMSM register interface     */
 #define ARPHRD_HIPPI   780             /* High Performance Parallel Interface */
 #define ARPHRD_ASH     781             /* Nexus 64Mbps Ash             */
+#define ARPHRD_ECONET  782             /* Acorn Econet                 */
 
 /* ARP protocol opcodes. */
 #define        ARPOP_REQUEST   1               /* ARP request                  */
index 35b7fbb5a215cd3adbc53e527a35816622f25fd9..b2b0f76aebc6b551f7f102fb85163ed24ea05bf4 100644 (file)
@@ -14,6 +14,7 @@
 #define PARPORT_IRQ_AUTO  -2
 #define PARPORT_DMA_AUTO  -2
 #define PARPORT_DISABLE   -2
+#define PARPORT_IRQ_PROBEONLY -3
 
 #define PARPORT_CONTROL_STROBE    0x1
 #define PARPORT_CONTROL_AUTOFD    0x2
@@ -291,6 +292,7 @@ extern __inline__ unsigned int parport_yield_blocking(struct pardevice *dev)
 
 #define PARPORT_FLAG_COMA              1
 
+extern void parport_parse_irqs(int, const char *, int irqval[]);
 extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
 extern int parport_wait_peripheral(struct parport *, unsigned char, unsigned
                                   char);
index 1819cb353b1ade52cf028a5397cdb48ece411f45..fac49e39670611f147130507ff36bb721b144b14 100644 (file)
 #define PCI_DEVICE_ID_KTI_ET32P2       0x3000
 
 #define PCI_VENDOR_ID_ADAPTEC          0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810     0x1078
 #define PCI_DEVICE_ID_ADAPTEC_7850     0x5078
 #define PCI_DEVICE_ID_ADAPTEC_7855     0x5578
 #define PCI_DEVICE_ID_ADAPTEC_5800     0x5800
index 4ca38d08197176e953a3c3cb8d393e297833ca8c..1c688de702f2e2ed0c57861c9349911a4503fbfd 100644 (file)
@@ -150,6 +150,7 @@ struct ucred {
 #define AF_ROUTE       AF_NETLINK /* Alias to emulate 4.4BSD */
 #define AF_PACKET      17      /* Packet family                */
 #define AF_ASH         18      /* Ash                          */
+#define AF_ECONET      19      /* Acorn Econet                 */
 #define AF_MAX         32      /* For now.. */
 
 /* Protocol families, same as address families. */
index 53b265f49ec60c09ece5e06374b1e409ef3ee464..2df16d607bac1e4e752e0504fa3e33640b5d1916 100644 (file)
@@ -153,6 +153,7 @@ enum
        NET_IPV4_TCP_TIMESTAMPS,
        NET_IPV4_TCP_WINDOW_SCALING,
        NET_IPV4_TCP_SACK,
+       NET_IPV4_TCP_RETRANS_COLLAPSE,
        NET_IPV4_DEFAULT_TTL,
        NET_IPV4_AUTOCONFIG,
        NET_IPV4_NO_PMTU_DISC,
index 594b3108a27b18df1153d3c369f9b11745f5d5f1..eae70d9186c7b0567d5b52e1fb972862f9842818 100644 (file)
@@ -65,9 +65,14 @@ enum {
   TCP_CLOSE_WAIT,
   TCP_LAST_ACK,
   TCP_LISTEN,
-  TCP_CLOSING  /* now a valid state */
+  TCP_CLOSING,  /* now a valid state */
+
+  TCP_MAX_STATES /* Leave at the end! */
 };
 
+#define TCP_STATE_MASK 0xF
+#define TCP_ACTION_FIN 1 << 7
+
 enum {
   TCPF_ESTABLISHED = (1 << 1),
   TCPF_SYN_SENT  = (1 << 2),
index 52f09384e056ae165cc9544334fba51b8c34cee4..2152e388bc03744b526cf8754f1ae97f2f770d1a 100644 (file)
@@ -34,7 +34,7 @@ struct ipxhdr
 #define IPX_TYPE_UNKNOWN       0x00
 #define IPX_TYPE_RIP           0x01    /* may also be 0 */
 #define IPX_TYPE_SAP           0x04    /* may also be 0 */
-#define IPX_TYPE_SPX           0x05    /* Not yet implemented */
+#define IPX_TYPE_SPX           0x05    /* SPX protocol */
 #define IPX_TYPE_NCP           0x11    /* $lots for docs on this (SPIT) */
 #define IPX_TYPE_PPROP         0x14    /* complicated flood fill brdcast [Not supported] */
        ipx_address     ipx_dest __attribute__ ((packed));
@@ -76,4 +76,7 @@ typedef struct ipx_route {
 #define IPX_MIN_EPHEMERAL_SOCKET       0x4000
 #define IPX_MAX_EPHEMERAL_SOCKET       0x7fff
 
+extern int ipx_register_spx(struct proto_ops **, struct net_proto_family *);
+extern int ipx_unregister_spx(void);
+
 #endif /* def _NET_INET_IPX_H_ */
index cc9fc842c0ac71b168a99f719916dd76af270627..356a7d2708283a34b57b5f96a48a3001408c9722 100644 (file)
@@ -126,6 +126,11 @@ extern int  nr_init(struct device *);
 /* nr_in.c */
 extern int  nr_process_rx_frame(struct sock *, struct sk_buff *);
 
+/* nr_loopback.c */
+extern void nr_loopback_init(void);
+extern void nr_loopback_clear(void);
+extern int  nr_loopback_queue(struct sk_buff *);
+
 /* nr_out.c */
 extern void nr_output(struct sock *, struct sk_buff *);
 extern void nr_send_nak_frame(struct sock *);
@@ -153,7 +158,7 @@ extern void nr_requeue_frames(struct sock *);
 extern int  nr_validate_nr(struct sock *, unsigned short);
 extern int  nr_in_rx_window(struct sock *, unsigned short);
 extern void nr_write_internal(struct sock *, int);
-extern void nr_transmit_dm(struct sk_buff *);
+extern void nr_transmit_refusal(struct sk_buff *, int);
 extern void nr_disconnect(struct sock *, int);
 
 /* nr_timer.c */
index 8e86c14573d63b26755681cfb72eae599c8a4d9c..366168287e8a12f3ed1215a7542970c30ec9935b 100644 (file)
@@ -87,6 +87,7 @@ struct rose_neigh {
        unsigned int            number;
        char                    restarted;
        char                    dce_mode;
+       char                    loopback;
        struct sk_buff_head     queue;
        struct timer_list       t0timer;
        struct timer_list       ftimer;
@@ -97,6 +98,7 @@ struct rose_node {
        rose_address            address;
        unsigned short          mask;
        unsigned char           count;
+       char                    loopback;
        struct rose_neigh       *neighbour[3];
 };
 
@@ -179,11 +181,21 @@ extern void rose_transmit_diagnostic(struct rose_neigh *, unsigned char);
 extern void rose_transmit_clear_request(struct rose_neigh *, unsigned int, unsigned char, unsigned char);
 extern void rose_transmit_link(struct sk_buff *, struct rose_neigh *);
 
+/* rose_loopback.c */
+extern void rose_loopback_init(void);
+extern void rose_loopback_clear(void);
+extern int  rose_loopback_queue(struct sk_buff *, struct rose_neigh *);
+
 /* rose_out.c */
 extern void rose_kick(struct sock *);
 extern void rose_enquiry_response(struct sock *);
 
 /* rose_route.c */
+extern struct rose_neigh *rose_loopback_neigh;
+
+extern int  rose_add_loopback_neigh(void);
+extern int  rose_add_loopback_node(rose_address *);
+extern void rose_del_loopback_node(rose_address *);
 extern void rose_rt_device_down(struct device *);
 extern void rose_link_device_down(struct device *);
 extern struct device *rose_dev_first(void);
index 271018a77ba89ef31bf390ac0819c01a82235de5..afd00efff8a12d82ba9ddffc135f804437900c57 100644 (file)
 #endif
 
 #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE)
+#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE)
+#include <net/spx.h>
+#else
 #include <net/ipx.h>
-#endif
+#endif /* CONFIG_SPX */
+#endif /* CONFIG_IPX */
 
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
 #include <linux/atalk.h>
@@ -413,7 +417,11 @@ struct sock {
 #endif
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
                struct raw6_opt         tp_raw;
-#endif
+#endif /* CONFIG_IPV6 */
+#if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
+               struct spx_opt          af_spx;
+#endif /* CONFIG_SPX */
+
        } tp_pinfo;
 
        int                     err, err_soft;  /* Soft holds errors that don't
index 3e9b1d1850574b40fbf40004f08e46feac7a2def..a449b891bec77c851525acccf46f8d401d145ac6 100644 (file)
@@ -1,38 +1,93 @@
 #ifndef __NET_SPX_H
 #define __NET_SPX_H
 
-/*
- *     Internal definitions for the SPX protocol.
- */
-/*
- *     The SPX header following an IPX header.
- */
+#include <net/ipx.h>
+
 struct spxhdr
-{
-       __u8 cctl;      
-#define CCTL_SPXII_XHD 0x01    /* SPX2 extended header */
-#define CCTL_SPX_UNKNOWN 0x02  /* Unknown (unused ??) */
-#define CCTL_SPXII_NEG 0x04    /* Negotiate size */
-#define CCTL_SPXII     0x08    /* Set for SPX2 */
-#define CCTL_EOM       0x10    /* End of message marker */
-#define CCTL_URG       0x20    /* Urgent marker in SPP (not used in SPX?) */
-#define CCTL_ACK       0x40    /* Send me an ACK */
-#define CCTL_CTL       0x80    /* Control message */
-       __u8 dtype;
+{      __u8    cctl;   
+       __u8    dtype;
 #define SPX_DTYPE_ECONN        0xFE    /* Finished */
 #define SPX_DTYPE_ECACK        0xFF    /* Ok */
-       __u16 sconn;    /* Connection ID */
-       __u16 dconn;    /* Connection ID */
-       __u16 sequence;
-       __u16 ackseq;
-       __u16 allocseq;
+       __u16   sconn;  /* Connection ID */
+       __u16   dconn;  /* Connection ID */
+       __u16   sequence;
+       __u16   ackseq;
+       __u16   allocseq;
 };
 
-#define IPXTYPE_SPX    5
+struct ipxspxhdr
+{      struct ipxhdr   ipx;
+       struct spxhdr   spx;
+};
+
+#define        SPX_SYS_PKT_LEN (sizeof(struct ipxspxhdr))
+
+#ifdef __KERNEL__
+struct spx_opt
+{      int     state;
+       int     sndbuf;
+       int     retries;        /* Number of WD retries */
+       int     retransmits;    /* Number of retransmits */
+       int     max_retries;
+       int     wd_interval;
+       void    *owner;
+       __u16   dest_connid;    /* Net order */
+       __u16   source_connid;  /* Net order */
+       __u16   sequence;       /* Host order - our current pkt # */
+       __u16   alloc;          /* Host order - max seq we can rcv now */
+       __u16   rmt_ack;        /* Host order - last pkt ACKd by remote */
+       __u16   rmt_seq;
+       __u16   acknowledge;
+       __u16   rmt_alloc;      /* Host order - max seq remote can handle now */
+       ipx_address     dest_addr;
+       ipx_address     source_addr;
+       struct timer_list       watchdog;       /* Idle watch */
+       struct timer_list       retransmit;     /* Retransmit timer */
+       struct sk_buff_head     rcv_queue;
+       struct sk_buff_head     transmit_queue;
+       struct sk_buff_head     retransmit_queue;
+};
+
+/* Packet connectino control defines */
+#define CCTL_SPXII_XHD  0x01    /* SPX2 extended header */
+#define CCTL_SPX_UNKNOWN 0x02   /* Unknown (unused ??) */
+#define CCTL_SPXII_NEG  0x04    /* Negotiate size */
+#define CCTL_SPXII      0x08    /* Set for SPX2 */
+#define CCTL_EOM        0x10    /* End of message marker */
+#define CCTL_URG        0x20    /* Urgent marker in SPP (not used in SPX?) */
+#define CCTL_ACK        0x40    /* Send me an ACK */
+#define CCTL_CTL        0x80    /* Control message */
+#define CCTL_SYS        CCTL_CTL        /* Spec uses CCTL_SYS */
+
+/* Connection state defines */
+#define SPX_CLOSED     7
+#define        SPX_CONNECTING  8
+#define SPX_CONNECTED  9
+
+/* Packet transmit types - Internal */
+#define DATA   0       /* Data */
+#define ACK    1       /* Data ACK */
+#define WDACK  2       /* WD ACK */
+#define CONACK 3       /* Connection Request ACK */
+#define        CONREQ  4       /* Connection Request */
+#define WDREQ  5       /* WD Request */
+#define        DISCON  6       /* Informed Disconnect */
+#define        DISACK  7       /* Informed Disconnect ACK */
+#define RETRAN 8       /* Int. Retransmit of packet */
+#define TQUEUE 9       /* Int. Transmit of a queued packet */
+
+/*
+ * These are good canidates for IOcontrol calls
+ */
+
+/* Watchdog defines */
+#define VERIFY_TIMEOUT  3 * HZ
+#define ABORT_TIMEOUT   30 * HZ
+
+/* Packet retransmit defines */
+#define RETRY_COUNT     10
+#define RETRY_TIME      1 * HZ
+#define MAX_RETRY_DELAY 5 * HZ
 
-       
-       
-       
-#endif
+#endif /* __KERNEL__ */
+#endif /* def __NET_SPX_H */
diff --git a/include/net/spxcall.h b/include/net/spxcall.h
new file mode 100644 (file)
index 0000000..0461fbb
--- /dev/null
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void spx_proto_init(struct net_proto *pro);
index 88d3b2901e15381e4bac9d276c2f16182a191800..7d4b7008215f3bfd816cd3ce028af18f6a6c6652 100644 (file)
@@ -218,17 +218,6 @@ extern kmem_cache_t *tcp_timewait_cachep;
         !ipv6_addr_cmp(&(__sk)->net_pinfo.af_inet6.rcv_saddr, (__daddr))       && \
         (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
 
-/* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6
- * because the v6 tcp code to intialize a connection needs to interoperate
- * with the v4 code using the same variables.
- * FIXME: It would be better to rewrite the connection code to be
- * address family independent and just leave one copy in the ipv4 section.
- * This would also clean up some code duplication. -- erics
- */
-extern int sysctl_tcp_timestamps;
-extern int sysctl_tcp_window_scaling;
-extern int sysctl_tcp_sack;
-
 /* These can have wildcards, don't try too hard. */
 static __inline__ int tcp_lhashfn(unsigned short num)
 {
@@ -718,9 +707,9 @@ struct tcp_skb_cb {
 #define TCP_CWND_SHIFT 1
 
 /* This determines how many packets are "in the network" to the best
- * or our knowledge.  In many cases it is conservative, but where
+ * of our knowledge.  In many cases it is conservative, but where
  * detailed information is available from the receiver (via SACK
- * blocks etc.) we can make more agressive calculations.
+ * blocks etc.) we can make more aggressive calculations.
  *
  * Use this for decisions involving congestion control, use just
  * tp->packets_out to determine if the send queue is empty or not.
@@ -809,7 +798,6 @@ static char *statename[]={
 
 static __inline__ void tcp_set_state(struct sock *sk, int state)
 {
-       struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
        int oldstate = sk->state;
 
        sk->state = state;
@@ -825,10 +813,13 @@ static __inline__ void tcp_set_state(struct sock *sk, int state)
                break;
 
        case TCP_CLOSE:
+           {
+               struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
                /* Should be about 2 rtt's */
                net_reset_timer(sk, TIME_DONE, min(tp->srtt * 2, TCP_DONE_TIME));
                sk->prot->unhash(sk);
                /* fall through */
+           }
        default:
                if (oldstate==TCP_ESTABLISHED)
                        tcp_statistics.TcpCurrEstab--;
@@ -941,9 +932,6 @@ extern __inline__ void tcp_select_initial_window(__u32 space, __u16 mss,
        (*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp);
 }
 
-/* Do new listen semantics */
-#define TCP_NEW_LISTEN
-
 extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, struct open_request *prev)
 {
        if(!req->dl_next)
index ff6cfbe93bdb77ee0bdaf523ea52fba913ef16ee..44c7dd051e66a91826612798bc6498eabb36bebe 100644 (file)
@@ -30,6 +30,12 @@ struct sg_header
 #define SG_SET_TIMEOUT 0x2201  /* set timeout *(int *)arg==timeout */
 #define SG_GET_TIMEOUT 0x2202  /* get timeout return timeout */
 
+#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */
+
+/* Used to configure SCSI command transformation layer for ATAPI devices */
+#define SG_SET_TRANSFORM 0x2204
+#define SG_GET_TRANSFORM 0x2205
+
 #define SG_DEFAULT_TIMEOUT (60*HZ) /* 1 minute timeout */
 #define SG_DEFAULT_RETRIES 1
 
index 107f481d639b93e0dfa1b2d90e1c0ec1195d21df..d8160d1eca2d649b81e9a95147a0218071b5898a 100644 (file)
@@ -1622,7 +1622,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
 
        cli();
 
-       len += sprintf(buffer, "dest_addr src_addr   dev  st  vs  vr  va    t1     t2     t3      idle   n2  rtt wnd paclen   Snd-Q Rcv-Q\n");
+       len += sprintf(buffer, "dest_addr src_addr   dev  st  vs  vr  va    t1     t2     t3      idle   n2  rtt wnd paclen   Snd-Q Rcv-Q inode\n");
 
        for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
                if (ax25->ax25_dev == NULL)
@@ -1658,9 +1658,10 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
                        ax25->paclen);
 
                if (ax25->sk != NULL) {
-                       len += sprintf(buffer + len, " %5d %5d\n",
+                       len += sprintf(buffer + len, " %5d %5d %ld\n",
                                atomic_read(&ax25->sk->wmem_alloc),
-                               atomic_read(&ax25->sk->rmem_alloc));
+                               atomic_read(&ax25->sk->rmem_alloc),
+                               ax25->sk->socket != NULL ? ax25->sk->socket->inode->i_ino : 0L);
                } else {
                        len += sprintf(buffer + len, "\n");
                }
index 71eb5cfc35687c4cb3a143da9a1c05c3d7750a29..8e330af2316536e2be366e551d6582b58c1e5da9 100644 (file)
@@ -362,7 +362,7 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
 
        ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 
-       skb->dev      = ax25->ax25_dev->dev;
+       skb->dev = ax25->ax25_dev->dev;
 
        ax25_queue_xmit(skb);
 }
index 5b684a48f246b5e7724395ada93fc5393c8d909e..67f7a6f2b899441062416185c142bea2516b932f 100644 (file)
@@ -29,7 +29,8 @@
 #include <net/checksum.h>
 
 /*
- *     Verify iovec
+ *     Verify iovec. The caller must ensure that the iovec is big enough
+ *     to hold the message iovec.
  *
  *     Save time not doing verify_area. copy_*_user will make this work
  *     in any case.
@@ -37,8 +38,7 @@
 
 int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
 {
-       int size = m->msg_iovlen * sizeof(struct iovec);
-       int err, ct;
+       int size, err, ct;
        
        if(m->msg_namelen)
        {
@@ -53,28 +53,16 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
        } else
                m->msg_name = NULL;
 
-       if (m->msg_iovlen > UIO_FASTIOV)
-       {
-               err = -ENOMEM;
-               iov = kmalloc(size, GFP_KERNEL);
-               if (!iov)
-                       goto out;
-       }
-       
+       err = -EFAULT;
+       size = m->msg_iovlen * sizeof(struct iovec);
        if (copy_from_user(iov, m->msg_iov, size))
-               goto out_free;
+               goto out;
        m->msg_iov=iov;
 
        for (err = 0, ct = 0; ct < m->msg_iovlen; ct++)
                err += iov[ct].iov_len;
 out:
        return err;
-
-out_free:
-       err = -EFAULT;
-       if (m->msg_iovlen > UIO_FASTIOV)
-               kfree(iov);
-       goto out;
 }
 
 /*
index 7707c70d01e6c2578fdda74957f9c059c4214c9b..b9ab1d2a853f639aafdc682c780562c08377a7b3 100644 (file)
@@ -589,38 +589,37 @@ void sock_kfree_s(struct sock *sk, void *mem, int size)
  */
 unsigned long sock_rspace(struct sock *sk)
 {
-       int amt;
+       int amt = 0;
 
        if (sk != NULL) {
-               /* This used to have some bizzare complications that
+               /* This used to have some bizarre complications that
                 * to attempt to reserve some amount of space. This doesn't
                 * make sense, since the number returned here does not
                 * actually reflect allocated space, but rather the amount
                 * of space we committed to. We gamble that we won't
                 * run out of memory, and returning a smaller number does
-                * not change the gamble. If we loose the gamble tcp still
+                * not change the gamble. If we lose the gamble tcp still
                 * works, it may just slow down for retransmissions.
                 */
                amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc);
                if (amt < 0) 
-                       return(0);
-               return(amt);
+                       amt = 0;
        }
-       return(0);
+       return amt;
 }
 
 
 /* FIXME: this is also insane. See above comment */
 unsigned long sock_wspace(struct sock *sk)
 {
-       if (sk != NULL) {
-               if (sk->shutdown & SEND_SHUTDOWN)
-                       return(0);
-               if (atomic_read(&sk->wmem_alloc) >= sk->sndbuf) 
-                       return(0);
-               return sk->sndbuf - atomic_read(&sk->wmem_alloc);
+       int amt = 0;
+
+       if (sk != NULL && !(sk->shutdown & SEND_SHUTDOWN)) {
+               amt = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+               if (amt < 0) 
+                       amt = 0;
        }
-       return(0);
+       return amt;
 }
 
 /* It is almost wait_for_tcp_memory minus release_sock/lock_sock.
@@ -653,13 +652,17 @@ static void sock_wait_for_wmem(struct sock * sk)
  *     Generic send/receive buffer handlers
  */
 
-struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigned long fallback, int noblock, int *errcode)
+struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, 
+                       unsigned long fallback, int noblock, int *errcode)
 {
        int err;
        struct sk_buff *skb;
 
-       do {
-               if ((err = xchg(&sk->err,0)) != 0)
+       while (1) {
+               unsigned long try_size = size;
+
+               err = sock_error(sk);
+               if (err != 0)
                        goto failure;
 
                /*
@@ -676,33 +679,32 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigne
                if (sk->shutdown&SEND_SHUTDOWN)
                        goto failure;
 
-               if (!fallback)
-                       skb = sock_wmalloc(sk, size, 0, sk->allocation);
-               else {
-                       /* The buffer get won't block, or use the atomic queue. It does
-                          produce annoying no free page messages still.... */
+               if (fallback) {
+                       /* The buffer get won't block, or use the atomic queue.
+                        * It does produce annoying no free page messages still.
+                        */
                        skb = sock_wmalloc(sk, size, 0, GFP_BUFFER);
-                       if (!skb)
-                               skb=sock_wmalloc(sk, fallback, 0, sk->allocation);
+                       if (skb)
+                               break;
+                       try_size = fallback;
                }
+               skb = sock_wmalloc(sk, try_size, 0, sk->allocation);
+               if (skb)
+                       break;
 
                /*
                 *      This means we have too many buffers for this socket already.
                 */
 
-               /* The following code is stolen "as is" from tcp.c */
-
-               if (skb==NULL) {
-                       sk->socket->flags |= SO_NOSPACE;
-                       err = -EAGAIN;
-                       if (noblock)
-                               goto failure;
-                       err = -ERESTARTSYS;
-                       if (signal_pending(current))
-                               goto failure;
-                       sock_wait_for_wmem(sk);
-               }
-       } while (skb==NULL);
+               sk->socket->flags |= SO_NOSPACE;
+               err = -EAGAIN;
+               if (noblock)
+                       goto failure;
+               err = -ERESTARTSYS;
+               if (signal_pending(current))
+                       goto failure;
+               sock_wait_for_wmem(sk);
+       }
 
        return skb;
 
index 854c5cc5f1de423e32413228e16c162fa7431f61..a9c47a20b963fd9a44fd9c173138ad490b90394e 100644 (file)
@@ -3,7 +3,7 @@
  *     
  *             Alan Cox, <alan@cymru.net>
  *
- *     Version: $Id: icmp.c,v 1.39 1998/03/08 05:56:19 davem Exp $
+ *     Version: $Id: icmp.c,v 1.40 1998/04/11 09:38:24 freitag Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -1026,7 +1026,6 @@ static unsigned long dummy;
  *     dst_entry gets expired too early. The same should happen when
  *     the cache grows too big.
  */
-int sysctl_icmp_sourcequench_time = 1*HZ; 
 int sysctl_icmp_destunreach_time = 1*HZ;
 int sysctl_icmp_timeexceed_time = 1*HZ;
 int sysctl_icmp_paramprob_time = 1*HZ;
@@ -1044,7 +1043,7 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
 /* DEST UNREACH (3) */
  { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1, &sysctl_icmp_destunreach_time },
 /* SOURCE QUENCH (4) */
- { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, &sysctl_icmp_sourcequench_time },
+ { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, },
 /* REDIRECT (5) */
  { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1, },
  { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
index 3e282a54b86c762bb1f205cc2e3dc20d82859053..65bc5f0fc55c748479a27b307403f86e92808b56 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.32 1998/04/03 09:49:47 freitag Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.34 1998/04/11 09:38:26 freitag Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -48,6 +48,7 @@ extern int sysctl_tcp_hoe_retransmits;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_sack;
+extern int sysctl_tcp_retrans_collapse;
 extern int sysctl_tcp_keepalive_time;
 extern int sysctl_tcp_keepalive_probes;
 extern int sysctl_tcp_max_ka_probes;
@@ -62,7 +63,6 @@ extern int sysctl_tcp_syn_taildrop;
 extern int sysctl_max_syn_backlog; 
 
 /* From icmp.c */
-extern int sysctl_icmp_sourcequench_time; 
 extern int sysctl_icmp_destunreach_time;
 extern int sysctl_icmp_timeexceed_time;
 extern int sysctl_icmp_paramprob_time;
@@ -105,6 +105,9 @@ ctl_table ipv4_table[] = {
         {NET_IPV4_TCP_SACK, "tcp_sack",
          &sysctl_tcp_sack, sizeof(int), 0644, NULL,
          &proc_dointvec},
+        {NET_IPV4_TCP_RETRANS_COLLAPSE, "tcp_retrans_collapse",
+         &sysctl_tcp_retrans_collapse, sizeof(int), 0644, NULL,
+         &proc_dointvec},
         {NET_IPV4_FORWARD, "ip_forward",
          &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
          &ipv4_sysctl_forward},
@@ -166,8 +169,6 @@ ctl_table ipv4_table[] = {
        {NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, "icmp_echo_ignore_broadcasts",
         &sysctl_icmp_echo_ignore_broadcasts, sizeof(int), 0644, NULL,
         &proc_dointvec},
-       {NET_IPV4_ICMP_SOURCEQUENCH_RATE, "icmp_sourcequench_rate",
-        &sysctl_icmp_sourcequench_time, sizeof(int), 0644, NULL, &proc_dointvec},
        {NET_IPV4_ICMP_DESTUNREACH_RATE, "icmp_destunreach_rate",
         &sysctl_icmp_destunreach_time, sizeof(int), 0644, NULL, &proc_dointvec},
        {NET_IPV4_ICMP_TIMEEXCEED_RATE, "icmp_timeexceed_rate",
index 12e0362474d678a8308196e80109f43ccb169d72..373c7774192fe0118f341028201e3b5014c4160e 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.110 1998/04/03 09:49:51 freitag Exp $
+ * Version:    $Id: tcp.c,v 1.111 1998/04/06 16:09:05 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *     Stefan Magdalinski      :       adjusted tcp_readable() to fix FIONREAD
  *     Willy Konynenberg       :       Transparent proxying support.
  *     Mike McLagan            :       Routing by source
- *             Keith Owens     :       Do proper meging with partial SKB's in
+ *             Keith Owens     :       Do proper merging with partial SKB's in
  *                                     tcp_do_sendmsg to avoid burstiness.
  *             Eric Schenk     :       Fix fast close down bug with
  *                                     shutdown() followed by close().
@@ -450,35 +450,6 @@ static struct open_request *tcp_find_established(struct tcp_opt *tp,
        return req;
 }
 
-/*
- *     This routine closes sockets which have been at least partially
- *     opened, but not yet accepted. Currently it is only called by
- *     tcp_close, and timeout mirrors the value there.
- */
-
-static void tcp_close_pending (struct sock *sk)
-{
-       struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-       struct open_request *req = tp->syn_wait_queue;
-
-       while(req) {
-               struct open_request *iter;
-               
-               if (req->sk)
-                       tcp_close(req->sk, 0);
-
-               iter = req;
-               req = req->dl_next;
-               
-               (*iter->class->destructor)(iter);
-               tcp_dec_slow_timer(TCP_SLT_SYNACK);
-               sk->ack_backlog--;
-               tcp_openreq_free(iter);
-       }
-
-       tcp_synq_init(tp);
-}
-
 /*
  *     Walk down the receive queue counting readable data.
  *
@@ -513,14 +484,12 @@ static int tcp_readable(struct sock *sk)
                 * avoid overlaps.
                 */
                sum = skb->len - (counted - TCP_SKB_CB(skb)->seq);
-               if (skb->h.th->syn)
-                       sum++;
-               if (sum > 0) {
+               if (sum >= 0) {
                        /* Add it up, move on. */
                        amount += sum;
-                       if (skb->h.th->syn)
-                               amount--;
                        counted += sum;
+                       if (skb->h.th->syn)
+                               counted++;
                }
 
                /* Don't count urg data ... but do it in the right place!
@@ -608,7 +577,7 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
                /* More than half of the socket queue free? */
                space = atomic_read(&sk->wmem_alloc) / 2;
 #endif
-               /* Always wake the user up when an error occured */
+               /* Always wake the user up when an error occurred */
                if (sock_wspace(sk) >= space || sk->err)
                        mask |= POLLOUT | POLLWRNORM;
                if (tp->urg_data)
@@ -619,44 +588,41 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
 
 int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
+       int answ;
+
        switch(cmd) {
-               case TIOCINQ:
+       case TIOCINQ:
 #ifdef FIXME   /* FIXME: */
-               case FIONREAD:
+       case FIONREAD:
 #endif
-               {
-                       unsigned long amount;
-
-                       if (sk->state == TCP_LISTEN)
-                               return(-EINVAL);
-
-                       lock_sock(sk);
-                       amount = tcp_readable(sk);
-                       release_sock(sk);
-                       return put_user(amount, (int *)arg);
-               }
-               case SIOCATMARK:
+               if (sk->state == TCP_LISTEN)
+                       return(-EINVAL);
+               lock_sock(sk);
+               answ = tcp_readable(sk);
+               release_sock(sk);
+               break;
+       case SIOCATMARK:
                {
                        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-                       int answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
-                       return put_user(answ,(int *) arg);
-               }
-               case TIOCOUTQ:
-               {
-                       unsigned long amount;
-
-                       if (sk->state == TCP_LISTEN)
-                               return(-EINVAL);
-                       amount = sock_wspace(sk);
-                       return put_user(amount, (int *)arg);
+                       answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
+                       break;
                }
-               default:
-                       return(-ENOIOCTLCMD);
+       case TIOCOUTQ:
+               if (sk->state == TCP_LISTEN)
+                       return(-EINVAL);
+               answ = sock_wspace(sk);
+               break;
+       default:
+               return(-ENOIOCTLCMD);
        };
+
+       return put_user(answ, (int *)arg);
 }
 
 /*
  *     Wait for a socket to get into the connected state
+ *
+ *     Note: must be called with the socket locked.
  */
 static int wait_for_tcp_connect(struct sock * sk, int flags)
 {
@@ -729,6 +695,8 @@ static void wait_for_tcp_memory(struct sock * sk)
 /*
  *     This routine copies from a user buffer into a socket,
  *     and starts the transmit system.
+ *
+ *     Note: must be called with the socket locked.
  */
 
 int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
@@ -738,6 +706,10 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
        int err = 0;
        int copied  = 0;
 
+       /* Verify that the socket is locked */
+       if (!sk->sock_readers)
+               printk("tcp_do_sendmsg: socket not locked!\n");
+
        /* Wait for a connection to finish. */
        if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
                if((err = wait_for_tcp_connect(sk, flags)) != 0)
@@ -951,7 +923,6 @@ static int tcp_recv_urg(struct sock * sk, int nonblock,
                        struct msghdr *msg, int len, int flags, 
                        int *addr_len)
 {
-       int err=0; 
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
        /* No URG data to read. */
@@ -961,22 +932,19 @@ static int tcp_recv_urg(struct sock * sk, int nonblock,
        if (sk->err)
                return sock_error(sk);
 
-       if (sk->state == TCP_CLOSE || sk->done) {
-               if (!sk->done) {
-                       sk->done = 1;
-                       return 0;
-               }
+       if (sk->done)
                return -ENOTCONN;
-       }
 
-       if (sk->shutdown & RCV_SHUTDOWN) {
+       if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN)) {
                sk->done = 1;
                return 0;
        }
 
        lock_sock(sk);
        if (tp->urg_data & URG_VALID) {
+               int err = 0; 
                char c = tp->urg_data;
+
                if (!(flags & MSG_PEEK))
                        tp->urg_data = URG_READ;
                        
@@ -994,11 +962,13 @@ static int tcp_recv_urg(struct sock * sk, int nonblock,
                if(len>0)
                {
                        err = memcpy_toiovec(msg->msg_iov, &c, 1);
+                       /* N.B. already set above ... */
                        msg->msg_flags|=MSG_OOB;
                }
                else
                        msg->msg_flags|=MSG_TRUNC;
                        
+               /* N.B. Is this right?? If len == 0 we didn't read any data */ 
                return err ? -EFAULT : 1;
        }
        release_sock(sk);
@@ -1285,6 +1255,15 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
        return copied;
 }
 
+/*
+ * Check whether to renew the timer.
+ */
+static inline void tcp_check_fin_timer(struct sock *sk)
+{
+       if (sk->state == TCP_FIN_WAIT2 && !sk->timer.prev)
+               tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+}
+
 /*
  *     State processing on a close. This implements the state shift for
  *     sending our FIN frame. Note that we only send a FIN for some
@@ -1292,37 +1271,28 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
  *     closed.
  */
 
+static unsigned char new_state[16] = {
+  /* current state:        new state:      action:     */
+  /* (Invalid)         */ TCP_CLOSE,
+  /* TCP_ESTABLISHED   */ TCP_FIN_WAIT1 | TCP_ACTION_FIN,
+  /* TCP_SYN_SENT      */ TCP_CLOSE,
+  /* TCP_SYN_RECV      */ TCP_FIN_WAIT1 | TCP_ACTION_FIN,
+  /* TCP_FIN_WAIT1     */ TCP_FIN_WAIT1,
+  /* TCP_FIN_WAIT2     */ TCP_FIN_WAIT2,
+  /* TCP_TIME_WAIT     */ TCP_CLOSE,
+  /* TCP_CLOSE         */ TCP_CLOSE,
+  /* TCP_CLOSE_WAIT    */ TCP_LAST_ACK  | TCP_ACTION_FIN,
+  /* TCP_LAST_ACK      */ TCP_LAST_ACK,
+  /* TCP_LISTEN                */ TCP_CLOSE,
+  /* TCP_CLOSING       */ TCP_CLOSING,
+};
+
 static int tcp_close_state(struct sock *sk, int dead)
 {
-       int ns=TCP_CLOSE;
-       int send_fin=0;
-       switch(sk->state) {
-               case TCP_SYN_SENT:      /* No SYN back, no FIN needed */
-                       break;
-               case TCP_SYN_RECV:
-               case TCP_ESTABLISHED:   /* Closedown begin */
-                       ns=TCP_FIN_WAIT1;
-                       send_fin=1;
-                       break;
-               case TCP_FIN_WAIT1:     /* Already closing, or FIN sent: no change */
-               case TCP_FIN_WAIT2:
-               case TCP_CLOSING:
-                       ns=sk->state;
-                       break;
-               case TCP_CLOSE:
-               case TCP_LISTEN:
-                       break;
-               case TCP_LAST_ACK:      /* Could have shutdown() then close()
-                                        * (but don't do send_fin again!) */
-                       ns=TCP_LAST_ACK;
-                       break;
-               case TCP_CLOSE_WAIT:    /* They have FIN'd us. We send our FIN and
-                                          wait only for the ACK */
-                       ns=TCP_LAST_ACK;
-                       send_fin=1;
-       };
+       int next = (int) new_state[sk->state];
+       int ns = (next & TCP_STATE_MASK);
 
-       tcp_set_state(sk,ns);
+       tcp_set_state(sk, ns);
 
        /*      This is a (useful) BSD violating of the RFC. There is a
         *      problem with TCP as specified in that the other end could
@@ -1332,10 +1302,10 @@ static int tcp_close_state(struct sock *sk, int dead)
         *      that we won't make the old 4*rto = almost no time - whoops
         *      reset mistake.
         */
-       if(dead && ns == TCP_FIN_WAIT2 && !sk->timer.prev)
-               tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+       if (dead)
+               tcp_check_fin_timer(sk);
 
-       return send_fin;
+       return (next & TCP_ACTION_FIN);
 }
 
 /*
@@ -1378,12 +1348,47 @@ static inline int closing(struct sock * sk)
        return ((1 << sk->state) & (TCPF_FIN_WAIT1|TCPF_CLOSING|TCPF_LAST_ACK));
 }
 
+/*
+ *     This routine closes sockets which have been at least partially
+ *     opened, but not yet accepted. Currently it is only called by
+ *     tcp_close, and timeout mirrors the value there.
+ */
+
+static void tcp_close_pending (struct sock *sk)
+{
+       struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+       struct open_request *req = tp->syn_wait_queue;
+
+       while(req) {
+               struct open_request *iter;
+               
+               if (req->sk)
+                       tcp_close(req->sk, 0);
+
+               iter = req;
+               req = req->dl_next;
+               
+               (*iter->class->destructor)(iter);
+               tcp_dec_slow_timer(TCP_SLT_SYNACK);
+               sk->ack_backlog--;
+               tcp_openreq_free(iter);
+       }
+
+       tcp_synq_init(tp);
+}
 
 void tcp_close(struct sock *sk, unsigned long timeout)
 {
        struct sk_buff *skb;
        int data_was_unread = 0;
 
+       /*
+        * Check whether the socket is locked ... supposedly
+        * it's impossible to tcp_close() a locked socket.
+        */
+       if (sk->sock_readers)
+               printk("tcp_close: socket already locked!\n");
+
        /* We need to grab some memory, and put together a FIN,
         * and then put it into the queue to be sent.
         */
@@ -1436,12 +1441,14 @@ void tcp_close(struct sock *sk, unsigned long timeout)
                struct task_struct *tsk = current;
                struct wait_queue wait = { tsk, NULL };
 
-               tsk->state = TASK_INTERRUPTIBLE;
                tsk->timeout = timeout;
                add_wait_queue(sk->sleep, &wait);
                release_sock(sk);
 
-               while (closing(sk)) {
+               while (1) {
+                       tsk->state = TASK_INTERRUPTIBLE;
+                       if (!closing(sk))
+                               break;
                        schedule();
                        if (signal_pending(tsk) || !tsk->timeout)
                                break;
@@ -1457,8 +1464,7 @@ void tcp_close(struct sock *sk, unsigned long timeout)
        /* Now that the socket is dead, if we are in the FIN_WAIT2 state
         * we may need to set up a timer.
          */
-       if (sk->state == TCP_FIN_WAIT2 && !sk->timer.prev)
-               tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+       tcp_check_fin_timer(sk);
 
        sk->dead = 1;
        release_sock(sk);
@@ -1472,7 +1478,7 @@ static struct open_request * wait_for_connect(struct sock * sk,
                                              struct open_request **pprev)
 {
        struct wait_queue wait = { current, NULL };
-       struct open_request *req = NULL;
+       struct open_request *req;
 
        add_wait_queue(sk->sleep, &wait);
        for (;;) {
@@ -1486,6 +1492,7 @@ static struct open_request * wait_for_connect(struct sock * sk,
                if (signal_pending(current))
                        break;
        }
+       current->state = TASK_RUNNING;
        remove_wait_queue(sk->sleep, &wait);
        return req;
 }
@@ -1515,14 +1522,14 @@ struct sock *tcp_accept(struct sock *sk, int flags)
        /* Find already established connection */
        req = tcp_find_established(tp, &prev);
        if (!req) {
-           /* If this is a non blocking socket don't sleep */
-           error = EAGAIN;
-           if (flags & O_NONBLOCK)
+               /* If this is a non blocking socket don't sleep */
+               error = EAGAIN;
+               if (flags & O_NONBLOCK)
                        goto out;
            
-           error = ERESTARTSYS;
-           req = wait_for_connect(sk, &prev);
-           if (!req) 
+               error = ERESTARTSYS;
+               req = wait_for_connect(sk, &prev);
+               if (!req) 
                        goto out;
        }
 
index deffa0667a16a13987c3ba732e69707e360a2c6f..e53204a13d5c784676c68547f8d327f30ed051e6 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.104 1998/04/01 07:41:24 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.106 1998/04/10 23:56:19 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Andi Kleen      :       Moved open_request checking here
  *                                     and process RSTs for open_requests.
  *             Andi Kleen      :       Better prune_queue, and other fixes.
+ *             Andrey Savochkin:       Fix RTT measurements in the presnce of
+ *                                     timestamps.
+ *             Andrey Savochkin:       Check sequence numbers correctly when
+ *                                     removing SACKs due to in sequence incoming
+ *                                     data segments.
  */
 
 #include <linux/config.h>
@@ -667,7 +672,20 @@ static void tcp_ack_probe(struct sock *sk, __u32 ack)
 static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
                               u32 seq, u32 ack, int flag)
 {
-       __u32 seq_rtt = (jiffies-tp->rcv_tsecr);
+       __u32 seq_rtt;
+
+       /* RTTM Rule: A TSecr value received in a segment is used to
+        * update the averaged RTT measurement only if the segment
+        * acknowledges some new data, i.e., only if it advances the
+        * left edge of the send window.
+        *
+        * See draft-ietf-tcplw-high-performance-00, section 3.3.
+        * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
+        */
+       if (!(flag & FLAG_DATA_ACKED))
+               return;
+
+       seq_rtt = jiffies-tp->rcv_tsecr;
        tcp_rtt_estimator(tp, seq_rtt);
        if (tp->retransmits) {
                if (tp->packets_out == 0) {
@@ -683,8 +701,7 @@ static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
                }
        } else {
                tcp_set_rto(tp);
-               if (flag & FLAG_DATA_ACKED)
-                       tcp_cong_avoid(tp, seq, ack, seq_rtt);
+               tcp_cong_avoid(tp, seq, ack, seq_rtt);
        }
        /* NOTE: safe here so long as cong_ctl doesn't use rto */
        tcp_bound_rto(tp);
@@ -1224,7 +1241,8 @@ static void tcp_sack_remove_skb(struct tcp_opt *tp, struct sk_buff *skb)
         * from the front of a SACK.
         */
        for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) {
-               if(!after(sp->start_seq, TCP_SKB_CB(skb)->seq) &&
+               /* Check if the start of the sack is covered by skb. */
+               if(!before(sp->start_seq, TCP_SKB_CB(skb)->seq) &&
                   before(sp->start_seq, TCP_SKB_CB(skb)->end_seq))
                        break;
        }
index 3396d3aa493939b48cab78ad972e78dd81c52cf0..7220fad7cc03b93678b5aaa972de6ed1cc1384d7 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.131 1998/04/03 10:52:04 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.133 1998/04/06 08:42:28 davem Exp $
  *
  *             IPv4 specific functions
  *
  *                                     open_request handling and moved
  *                                     most of it into the af independent code.
  *                                     Added tail drop and some other bugfixes.
- *                                     Added new listen sematics (ifdefed by
- *                                     TCP_NEW_LISTEN for now)
+ *                                     Added new listen sematics.
  *             Mike McLagan    :       Routing by source
  *     Juan Jose Ciarlante:            ip_dynaddr bits
  *             Andi Kleen:             various fixes.
  *     Vitaly E. Lavrov        :       Transparent proxy revived after year coma.
- *     Andi Kleen              :       Fix TCP_NEW_LISTEN and make it the default.
+ *     Andi Kleen              :       Fix new listen.
  */
 
 #include <linux/config.h>
@@ -337,9 +336,6 @@ static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int d
        return result;
 }
 
-/* Until this is verified... -DaveM */
-/* #define USE_QUICKSYNS */
-
 /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
  * It is assumed that this code only gets called from within NET_BH.
@@ -354,12 +350,6 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
        struct sock *sk;
        int hash;
 
-#ifdef USE_QUICKSYNS
-       /* Incomming connection short-cut. */
-       if (th && th->syn == 1 && th->ack == 0)
-               goto listener_shortcut;
-#endif
-
        /* Check TCP register quick cache first. */
        sk = TCP_RHASH(sport);
        if(sk && TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
@@ -380,9 +370,6 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
        for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
                if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
                        goto hit;
-#ifdef USE_QUICKSYNS
-listener_shortcut:
-#endif
        sk = tcp_v4_lookup_listener(daddr, hnum, dif);
 hit:
        return sk;
@@ -813,11 +800,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
                if (req->sk) {  /* not yet accept()ed */
                        sk = req->sk; /* report error in accept */
                } else {
-#ifdef TCP_NEW_LISTEN
                        tp->syn_backlog--;
-#else
-                       sk->ack_backlog--;
-#endif
                        tcp_synq_unlink(tp, req, prev);
                        req->class->destructor(req);
                        tcp_openreq_free(req);
@@ -1030,13 +1013,8 @@ struct or_calltable or_ipv4 = {
        tcp_v4_send_reset
 };
 
-#ifdef TCP_NEW_LISTEN
 #define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */
 #define BACKLOGMAX(sk) sysctl_max_syn_backlog
-#else
-#define BACKLOG(sk) ((sk)->ack_backlog)
-#define BACKLOGMAX(sk) ((sk)->max_ack_backlog)
-#endif
 
 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, 
                                                __u32 isn)
@@ -1068,10 +1046,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
        } else { 
                if (isn == 0)
                        isn = tcp_v4_init_sequence(sk, skb);
+               BACKLOG(sk)++;
        }
 
-       BACKLOG(sk)++;
-
        req = tcp_openreq_alloc();
        if (req == NULL) {
                goto dropbacklog;
@@ -1289,10 +1266,8 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        int snd_mss;
        int mtu;
 
-#ifdef TCP_NEW_LISTEN
        if (sk->ack_backlog > sk->max_ack_backlog)
                goto exit; /* head drop */
-#endif
        if (dst == NULL) { 
                struct rtable *rt;
                
@@ -1303,10 +1278,8 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                dst = &rt->u.dst;
        }
 
-#ifdef TCP_NEW_LISTEN
        sk->tp_pinfo.af_tcp.syn_backlog--;
        sk->ack_backlog++;
-#endif
 
        mtu = dst->pmtu;
        if (mtu < 68)
@@ -1353,11 +1326,7 @@ static void tcp_v4_rst_req(struct sock *sk, struct sk_buff *skb)
            after(TCP_SKB_CB(skb)->seq, req->snt_isn+1))
                return;
        tcp_synq_unlink(tp, req, prev);
-#ifdef TCP_NEW_LISTEN
        (req->sk ? sk->ack_backlog : tp->syn_backlog)--;
-#else
-       sk->ack_backlog--;
-#endif
        req->class->destructor(req);
        tcp_openreq_free(req); 
 }
@@ -1483,7 +1452,7 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
                skb->csum = csum_partial((char *)th, len, 0);
        case CHECKSUM_HW:
                if (tcp_v4_check(th,len,skb->nh.iph->saddr,skb->nh.iph->daddr,skb->csum)) {
-                       printk(KERN_DEBUG "TCPv4 bad checksum from %ld.%ld.%ld.%ld:%04x to %ld.%ld.%ld.%ld:%04x, "
+                       printk(KERN_DEBUG "TCPv4 bad checksum from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, "
                               "len=%d/%d/%d\n",
                               NIPQUAD(ntohl(skb->nh.iph->saddr)),
                               ntohs(th->source), 
index 7f0853cf1227c253cf6b6e7680cd3b7d20f40104..d615e6c6e350e2c77c2ae6d431027092b5659ccd 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_output.c,v 1.83 1998/04/03 08:10:45 davem Exp $
+ * Version:    $Id: tcp_output.c,v 1.84 1998/04/06 08:48:29 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
+extern int sysctl_tcp_sack;
+
+/* People can turn this off for buggy TCP's found in printers etc. */
+int sysctl_tcp_retrans_collapse = 1;
 
 /* Get rid of any delayed acks, we sent one already.. */
 static __inline__ void clear_delayed_acks(struct sock * sk)
@@ -494,7 +498,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&
           (skb->len < (current_mss >> 1)) &&
           (skb->next != tp->send_head) &&
-          (skb->next != (struct sk_buff *)&sk->write_queue))
+          (skb->next != (struct sk_buff *)&sk->write_queue) &&
+          (sysctl_tcp_retrans_collapse != 0))
                tcp_retrans_try_collapse(sk, skb, current_mss);
 
        if(tp->af_specific->rebuild_header(sk))
index f57f678b4f3d2450fc0b500584e668b5e619fb0f..8f478fac803e4280c1affb37ca2fbb46f3a4b36f 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_timer.c,v 1.47 1998/04/03 10:52:05 davem Exp $
+ * Version:    $Id: tcp_timer.c,v 1.48 1998/04/06 08:42:30 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -460,11 +460,7 @@ static void tcp_syn_recv_timer(unsigned long data)
 #endif
                                                (*conn->class->destructor)(conn);
                                                tcp_dec_slow_timer(TCP_SLT_SYNACK);
-#ifdef TCP_NEW_LISTEN
-                                       tp->syn_backlog--;
-#else
-                                       sk->ack_backlog--;
-#endif
+                                               tp->syn_backlog--;
                                                tcp_openreq_free(conn);
 
                                                if (!tp->syn_wait_queue)
index c2f811d7b36b326cf2d9fa45ace5d10bc97ace5c..52e02ef2d44e6e201d80d5099edd640dbbbebf63 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.74 1998/04/03 09:50:01 freitag Exp $
+ *     $Id: tcp_ipv6.c,v 1.76 1998/04/06 08:42:34 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
@@ -42,6 +42,8 @@
 
 #include <asm/uaccess.h>
 
+extern int sysctl_max_syn_backlog;
+
 static void    tcp_v6_send_reset(struct sk_buff *skb);
 static void    tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len, 
                                  struct sk_buff *skb);
@@ -225,9 +227,6 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor
        return result;
 }
 
-/* Until this is verified... -DaveM */
-/* #define USE_QUICKSYNS */
-
 /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
  * It is assumed that this code only gets called from within NET_BH.
@@ -242,12 +241,6 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
        __u32 ports = TCP_COMBINED_PORTS(sport, hnum);
        int hash;
 
-#ifdef USE_QUICKSYNS
-       /* Incomming connection short-cut. */
-       if (th && th->syn == 1 && th->ack == 0)
-               goto listener_shortcut;
-#endif
-
        /* Check TCP register quick cache first. */
        sk = TCP_RHASH(sport);
        if(sk && TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif))
@@ -276,9 +269,6 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
                                goto hit;
                }
        }
-#ifdef USE_QUICKSYNS
-listener_shortcut:
-#endif
        sk = tcp_v6_lookup_listener(daddr, hnum, dif);
 hit:
        return sk;
@@ -638,6 +628,7 @@ void tcp_v6_err(struct sk_buff *skb, int type, int code, unsigned char *header,
                if (req->sk) {
                        sk = req->sk; /* report error in accept */
                } else {
+                       tp->syn_backlog--;
                        tcp_synq_unlink(tp, req, prev);
                        req->class->destructor(req);
                        tcp_openreq_free(req);
@@ -717,6 +708,9 @@ static struct or_calltable or_ipv6 = {
        tcp_v6_send_reset
 };
 
+#define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */
+#define BACKLOGMAX(sk) sysctl_max_syn_backlog
+
 /* FIXME: this is substantially similar to the ipv4 code.
  * Can some kind of merge be done? -- erics
  */
@@ -742,9 +736,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
        /*
         *      There are no SYN attacks on IPv6, yet...
         */
-       if (sk->ack_backlog >= sk->max_ack_backlog) {
+       if (BACKLOG(sk) >= BACKLOGMAX(sk)) {
                printk(KERN_DEBUG "droping syn ack:%d max:%d\n",
-                      sk->ack_backlog, sk->max_ack_backlog);
+                      BACKLOG(sk), BACKLOGMAX(sk));
                goto drop;              
        }
 
@@ -753,7 +747,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
                goto drop;
        }
 
-       sk->ack_backlog++;
+       BACKLOG(sk)++;
 
        req->rcv_wnd = 0;               /* So that tcp_send_synack() knows! */
 
@@ -820,7 +814,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        struct tcp_opt *newtp;
        struct sock *newsk;
        int mss;
-
+      
        if (skb->protocol == __constant_htons(ETH_P_IP)) {
                /*
                 *      v6 mapped
@@ -848,6 +842,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        }
 
 
+       if (sk->ack_backlog > sk->max_ack_backlog)
+               return NULL; 
+
        if (dst == NULL) {
                /*
                 *      options / mss / route cache
@@ -866,6 +863,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        if (dst->error || dst->pmtu < 576)
                goto out;
        
+       sk->tp_pinfo.af_tcp.syn_backlog--;
+       sk->ack_backlog++;
 
        mss = dst->pmtu - sizeof(struct ipv6hdr);
 #if 0
@@ -1005,6 +1004,10 @@ static void tcp_v6_rst_req(struct sock *sk, struct sk_buff *skb)
        if (before(TCP_SKB_CB(skb)->seq, req->snt_isn) ||
            after(TCP_SKB_CB(skb)->seq, req->snt_isn+1))
                return;
+       if(req->sk)
+               sk->ack_backlog--;
+       else
+               tp->syn_backlog--;
        tcp_synq_unlink(tp, req, prev);
        req->class->destructor(req);
        tcp_openreq_free(req); 
index d35afbac0a823ba7bcd1f723a7d38e352f27715b..17080b0c65247fab1f0f223dfbd8d237cb240015 100644 (file)
@@ -2,5 +2,7 @@
 # IPX configuration
 #
 
-comment 'IPX options'
-bool 'Full internal IPX network' CONFIG_IPX_INTERN
+bool 'IPX: Full internal IPX network' CONFIG_IPX_INTERN
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  dep_tristate 'IPX: SPX networking (EXPERIMENTAL)' CONFIG_SPX $CONFIG_IPX
+fi
index b9d337a8a5e9147fa7492ef2b4a3ac1cdebea289..39639c6dc8ebb982d4fb2472dbab7dc5a29385ac 100644 (file)
@@ -17,6 +17,14 @@ ifeq ($(CONFIG_SYSCTL),y)
   O_OBJS += sysctl_net_ipx.o
 endif
 
+ifeq ($(CONFIG_SPX),y)
+OX_OBJS += af_spx.o
+else
+  ifeq ($(CONFIG_SPX),m)
+  MX_OBJS += af_spx.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 tar:
index 904fa1174952e1773fe5739b48aad6209062aebd..32fadd36652f5b6a43165762e2e061e360eda10c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     Implements an IPX socket layer (badly - but I'm working on it).
+ *     Implements an IPX socket layer.
  *
  *     This code is derived from work by
  *             Ross Biro       :       Writing the original IP stack
@@ -47,6 +47,7 @@
  *     Revision 0.36:  Internal bump up for 2.1
  *     Revision 0.37:  Began adding POSIXisms.
  *     Revision 0.38:  Asynchronous socket stuff made current.
+ *     Revision 0.39:  SPX interfaces
  *
  *     Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT
  *     pair. Also, now usage count is managed this way
@@ -111,6 +112,8 @@ static struct datalink_proto        *pSNAP_datalink = NULL;
 
 static struct proto_ops ipx_dgram_ops;
 
+static struct net_proto_family *spx_family_ops;
+
 static ipx_route       *ipx_routes = NULL;
 static ipx_interface   *ipx_interfaces = NULL;
 static ipx_interface   *ipx_primary_net = NULL;
@@ -163,7 +166,7 @@ static int ipxcfg_get_config_data(ipx_config_data *arg)
  *     use this facility.
  */
 
-static void ipx_remove_socket(struct sock *sk)
+void ipx_remove_socket(struct sock *sk)
 {
        struct sock     *s;
        ipx_interface   *intrfc;
@@ -762,8 +765,8 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
                                        if (call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)==FW_ACCEPT)
                                        {
                                                skb2 = skb_clone(skb, GFP_ATOMIC);
-                                       ipxrtr_route_skb(skb2);
-                               }
+                                               ipxrtr_route_skb(skb2);
+                                       }
                                }
                        }
                        /*
@@ -1264,6 +1267,9 @@ static __u16 ipx_set_checksum(struct ipxhdr *packet,int length)
         */
 
        __u32 i=length>>1;
+       char    hops = packet->ipx_tctrl;
+
+       packet->ipx_tctrl = 0;     /* hop count excluded from checksum calc */
 
        /*
         *      Loop through all complete words except the checksum field
@@ -1279,6 +1285,7 @@ static __u16 ipx_set_checksum(struct ipxhdr *packet,int length)
        if(packet->ipx_pktsize&htons(1))
                sum+=ntohs(0xff00)&*p;
 
+       packet->ipx_tctrl = hops;
        /*
         *      Do final fixup
         */
@@ -1713,19 +1720,24 @@ static int ipx_getsockopt(struct socket *sock, int level, int optname,
 static int ipx_create(struct socket *sock, int protocol)
 {
        struct sock *sk;
-       sk=sk_alloc(AF_IPX, GFP_KERNEL, 1);
-       if(sk==NULL)
-               return(-ENOMEM);
        switch(sock->type)
        {
                case SOCK_DGRAM:
+                       sk=sk_alloc(AF_IPX, GFP_KERNEL, 1);
+                       if(sk==NULL)
+                               return(-ENOMEM);
                         sock->ops = &ipx_dgram_ops;
                         break;
-               case SOCK_STREAM:       /* Allow higher levels to piggyback */
                case SOCK_SEQPACKET:
-                       printk(KERN_CRIT "IPX: _create-ing non_DGRAM socket\n");
+                       /*
+                        *      From this point on SPX sockets are handled
+                        *      by af_spx.c and the methods replaced.
+                        */
+                       if(spx_family_ops)
+                               return spx_family_ops->create(sock,protocol);
+                       /* Fall through if SPX is not loaded */                 
+               case SOCK_STREAM:       /* Allow higher levels to piggyback */
                default:
-                       sk_free(sk);
                        return(-ESOCKTNOSUPPORT);
        }
        sock_init_data(sock,sk);
@@ -2249,6 +2261,34 @@ static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
        return(0);
 }
 
+/*
+ *     SPX interface support
+ */
+
+int ipx_register_spx(struct proto_ops **p, struct net_proto_family *spx)
+{
+       if(spx_family_ops!=NULL)
+               return -EBUSY;
+       cli();
+       MOD_INC_USE_COUNT;
+       *p=&ipx_dgram_ops;
+       spx_family_ops=spx;
+       sti();
+       return 0;
+}
+
+int ipx_unregister_spx(void)
+{
+       spx_family_ops=NULL;
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+
+/*
+ *     Socket family declarations
+ */
 static struct net_proto_family ipx_family_ops = {
        AF_IPX,
        ipx_create
@@ -2256,7 +2296,6 @@ static struct net_proto_family ipx_family_ops = {
 
 static struct proto_ops ipx_dgram_ops = {
        AF_IPX,
-
        sock_no_dup,
        ipx_release,
        ipx_bind,
@@ -2280,7 +2319,7 @@ static struct proto_ops ipx_dgram_ops = {
 static struct packet_type ipx_8023_packet_type =
 
 {
-       0,      /* MUTTER ntohs(ETH_P_8023),*/
+       0,      /* MUTTER ntohs(ETH_P_802_3),*/
        NULL,           /* All devices */
        ipx_rcv,
        NULL,
@@ -2371,6 +2410,10 @@ int ipx_if_offset(unsigned long ipx_net_number)
 /* Export symbols for higher layers */
 EXPORT_SYMBOL(ipxrtr_route_skb);
 EXPORT_SYMBOL(ipx_if_offset);
+EXPORT_SYMBOL(ipx_remove_socket);
+EXPORT_SYMBOL(ipx_register_spx);
+EXPORT_SYMBOL(ipx_unregister_spx);
+
 
 #ifdef MODULE
 /* Note on MOD_{INC,DEC}_USE_COUNT:
@@ -2387,7 +2430,8 @@ EXPORT_SYMBOL(ipx_if_offset);
  */
 
 __initfunc(static void ipx_proto_finito(void))
-{      ipx_interface   *ifc;
+{
+       ipx_interface   *ifc;
 
        while (ipx_interfaces) {
                ifc = ipx_interfaces;
diff --git a/net/ipx/af_spx.c b/net/ipx/af_spx.c
new file mode 100644 (file)
index 0000000..a14ad0a
--- /dev/null
@@ -0,0 +1,872 @@
+/*
+ *     This module implements the (SPP-derived) Sequenced Packet eXchange
+ *     (SPX) protocol for Linux 2.1.X as specified in
+ *             NetWare SPX Services Specification, Semantics and API
+ *              Revision:       1.00
+ *              Revision Date:  February 9, 1993
+ *
+ *     Developers:
+ *      Jay Schulist    <Jay.Schulist@spacs.k12.wi.us>
+ *     Jim Freeman     <jfree@caldera.com>
+ *
+ *     Changes:
+ *     Alan Cox        :       Fixed an skb_unshare check for NULL
+ *                             that crashed it under load. Renamed and
+ *                             made static the ipx ops. Removed the hack
+ *                             ipx methods interface. Dropped AF_SPX - its
+ *                             the wrong abstraction.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ *     None of the authors or maintainers or their employers admit
+ *     liability nor provide warranty for any of this software.
+ *     This material is provided "as is" and at no charge.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE)
+#include <linux/module.h>
+#include <net/ipx.h>
+#include <net/spx.h>
+#include <net/sock.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+#include <linux/uio.h>
+#include <linux/unistd.h>
+#include <linux/firewall.h>
+
+static struct proto_ops *ipx_operations;
+static struct proto_ops spx_operations;
+static __u16  connids;
+
+/* Functions needed for SPX connection start up */
+static int spx_transmit(struct sock *sk,struct sk_buff *skb,int type,int len);
+static void spx_retransmit(unsigned long data);
+static void spx_watchdog(unsigned long data);
+void spx_rcv(struct sock *sk, int bytes);
+
+/* Create the SPX specific data */
+static int spx_sock_init(struct sock *sk)
+{
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+        pdata->state            = SPX_CLOSED;
+        pdata->sequence         = 0;
+       pdata->acknowledge      = 0;
+        pdata->source_connid    = htons(connids);
+       pdata->rmt_seq          = 0;
+        connids++;
+
+        pdata->owner            = (void *)sk;
+        pdata->sndbuf           = sk->sndbuf;
+
+        pdata->watchdog.function = spx_watchdog;
+        pdata->watchdog.data    = (unsigned long)sk;
+        pdata->wd_interval      = VERIFY_TIMEOUT;
+       pdata->retransmit.function = spx_retransmit;
+       pdata->retransmit.data  = (unsigned long)sk;
+       pdata->retransmits      = 0;
+        pdata->retries          = 0;
+        pdata->max_retries      = RETRY_COUNT;
+
+       skb_queue_head_init(&pdata->rcv_queue);
+       skb_queue_head_init(&pdata->transmit_queue);
+       skb_queue_head_init(&pdata->retransmit_queue);
+
+        return (0);
+}
+
+static int spx_create(struct socket *sock, int protocol)
+{
+       struct sock *sk;
+
+       sk = sk_alloc(AF_IPX, GFP_KERNEL, 1);
+       if(sk == NULL)
+                return (-ENOMEM);
+
+       switch(sock->type)
+        {
+                case SOCK_SEQPACKET:
+                       sock->ops = &spx_operations;
+                       break;
+               default:
+                       sk_free(sk);
+                        return (-ESOCKTNOSUPPORT);
+        }
+
+       sock_init_data(sock, sk);
+       spx_sock_init(sk);
+       sk->data_ready  = spx_rcv;
+       sk->destruct    = NULL;
+        sk->mtu        = IPX_MTU;
+        sk->no_check   = 1;
+
+        MOD_INC_USE_COUNT;
+
+       return (0);
+}
+
+static int spx_shutdown(struct socket *sk,int how)
+{
+        return (-EOPNOTSUPP);
+}
+
+void spx_close_socket(struct sock *sk)
+{
+       struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+       pdata->state    = SPX_CLOSED;
+       sk->state       = TCP_CLOSE;
+       del_timer(&pdata->retransmit);
+       del_timer(&pdata->watchdog);
+}
+
+void spx_destroy_socket(struct sock *sk)
+{
+       struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+       struct sk_buff *skb;
+
+        ipx_remove_socket(sk);
+        while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
+                kfree_skb(skb);
+       while((skb = skb_dequeue(&pdata->transmit_queue)) != NULL)
+                kfree_skb(skb);
+       while((skb = skb_dequeue(&pdata->retransmit_queue)) != NULL)
+               kfree_skb(skb);
+       while((skb = skb_dequeue(&pdata->rcv_queue)) != NULL)
+                kfree_skb(skb);
+
+        sk_free(sk);
+       MOD_DEC_USE_COUNT;
+}
+
+/* Release an SPX socket */
+static int spx_release(struct socket *sock, struct socket *peer)
+{
+       struct sock *sk = sock->sk;
+       struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+       if(sk == NULL)
+               return (0);
+       if(!sk->dead)
+                sk->state_change(sk);
+        sk->dead = 1;
+
+       if(pdata->state != SPX_CLOSED)
+       {
+               spx_transmit(sk, NULL, DISCON, 0);
+               spx_close_socket(sk);
+       }
+
+       sock->sk        = NULL;
+       sk->socket      = NULL;
+       spx_destroy_socket(sk);
+
+        return (0);
+}
+
+/* Move a socket into listening state. */
+static int spx_listen(struct socket *sock, int backlog)
+{
+        struct sock *sk = sock->sk;
+
+        if(sock->state != SS_UNCONNECTED)
+                return (-EINVAL);
+       if(sock->type != SOCK_SEQPACKET)
+               return (-EOPNOTSUPP);
+        if(sk->zapped != 0)
+                return (-EAGAIN);
+
+        if((unsigned) backlog == 0)     /* BSDism */
+                backlog = 1;
+        if((unsigned) backlog > SOMAXCONN)
+                backlog = SOMAXCONN;
+        sk->max_ack_backlog = backlog;
+        if(sk->state != TCP_LISTEN)
+        {
+                sk->ack_backlog = 0;
+                sk->state = TCP_LISTEN;
+        }
+        sk->socket->flags |= SO_ACCEPTCON;
+
+        return (0);
+}
+
+/* Accept a pending SPX connection */
+static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+        struct sock *sk;
+        struct sock *newsk;
+        struct sk_buff *skb;
+       int err;
+
+       if(newsock->sk != NULL)
+               spx_destroy_socket(newsock->sk);
+        newsock->sk = NULL;
+
+       if(sock->sk == NULL)
+               return (-EINVAL);
+       sk = sock->sk;
+
+        if((sock->state != SS_UNCONNECTED) || !(sock->flags & SO_ACCEPTCON))
+                return (-EINVAL);
+        if(sock->type != SOCK_SEQPACKET)
+               return (-EOPNOTSUPP);
+       if(sk->state != TCP_LISTEN)
+                return (-EINVAL);
+
+       cli();
+       do {
+               skb = skb_dequeue(&sk->receive_queue);
+               if(skb == NULL)
+               {
+                       if(flags & O_NONBLOCK)
+                       {
+                                sti();
+                                return (-EWOULDBLOCK);
+                        }
+                       interruptible_sleep_on(sk->sleep);
+                       if(signal_pending(current))
+                       {
+                               sti();
+                               return (-ERESTARTSYS);
+                       }
+               }
+       } while (skb == NULL);
+
+       newsk           = skb->sk;
+        newsk->pair    = NULL;
+       sti();
+
+       err = spx_transmit(newsk, skb, CONACK, 0);   /* Connection ACK */
+       if(err)
+               return (err);
+
+       /* Now attach up the new socket */
+       sock->sk        = NULL;
+        sk->ack_backlog--;
+        newsock->sk    = newsk;
+       newsk->state    = TCP_ESTABLISHED;
+       newsk->protinfo.af_ipx.dest_addr = newsk->tp_pinfo.af_spx.dest_addr;
+
+       return (0);
+}
+
+/* Build a connection to an SPX socket */
+static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
+                int addr_len, int flags)
+{
+       struct sock *sk = sock->sk;
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+        struct sockaddr_ipx src;
+       struct sk_buff *skb;
+       int size, err;
+
+       size = sizeof(src);
+       err  = ipx_operations->getname(sock, (struct sockaddr *)&src, &size, 0);
+       if(err)
+               return (err);
+
+        pdata->source_addr.net = src.sipx_network;
+        memcpy(pdata->source_addr.node, src.sipx_node, IPX_NODE_LEN);
+        pdata->source_addr.sock = (unsigned short)src.sipx_port;
+
+       err = ipx_operations->connect(sock, uaddr, addr_len, flags);
+        if(err)
+                return (err);
+
+        pdata->dest_addr = sk->protinfo.af_ipx.dest_addr;
+       pdata->state     = SPX_CONNECTING;
+       sock->state      = SS_CONNECTING;
+        sk->state       = TCP_SYN_SENT;
+
+        /* Send Connection request */
+       err = spx_transmit(sk, NULL, CONREQ, 0);
+        if(err)
+                return (err);
+
+       cli();
+        do {
+                skb = skb_dequeue(&sk->receive_queue);
+                if(skb == NULL)
+                {
+                        if(flags & O_NONBLOCK)
+                        {
+                                sti();
+                                return (-EWOULDBLOCK);
+                        }
+                        interruptible_sleep_on(sk->sleep);
+                        if(signal_pending(current))
+                        {
+                                sti();
+                                return (-ERESTARTSYS);
+                        }
+                }
+        } while (skb == NULL);
+
+        if(pdata->state == SPX_CLOSED)
+        {
+               sti();
+                del_timer(&pdata->watchdog);
+                return (-ETIMEDOUT);
+        }
+
+       sock->state     = SS_CONNECTED;
+       sk->state       = TCP_ESTABLISHED;
+       kfree_skb(skb);
+       sti();
+
+        return (0);
+}
+
+/*
+ * Calculate the timeout for a packet. Thankfully SPX has a large
+ * fudge factor (3/4 secs) and does not pay much attention to RTT.
+ * As we simply have a default retry time of 1*HZ and a max retry
+ * time of 5*HZ. Between those values we increase the timeout based
+ * on the number of retransmit tries.
+ */
+static inline unsigned long spx_calc_rtt(int tries)
+{
+        if(tries < 1)
+                return (RETRY_TIME);
+        if(tries > 5)
+                return (MAX_RETRY_DELAY);
+        return (tries * HZ);
+}
+
+static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type)
+{
+       struct sk_buff *skb2;
+       int err = 0;
+
+       skb = skb_unshare(skb, GFP_ATOMIC);
+       if(skb==NULL)
+               return -ENOBUFS;
+
+       switch(type)
+       {
+               case (DATA):
+                       if(!skb_queue_empty(&pdata->retransmit_queue))
+                       {
+                               skb_queue_tail(&pdata->transmit_queue, skb);
+                               return 0;
+                       }
+
+               case (TQUEUE):
+                       pdata->retransmit.expires = jiffies + spx_calc_rtt(0);
+                       add_timer(&pdata->retransmit);
+
+                       skb2 = skb_clone(skb, GFP_BUFFER);
+                       if(skb2 == NULL)
+                               return -ENOBUFS;
+                       skb_queue_tail(&pdata->retransmit_queue, skb2);
+
+               case (ACK):
+               case (CONREQ):
+               case (CONACK):
+               case (WDREQ):
+               case (WDACK):
+               case (DISCON):
+               case (DISACK):
+               case (RETRAN):
+               default:
+                       /* Send data */
+                       err = ipxrtr_route_skb(skb);
+                       if(err)
+                               kfree_skb(skb);
+       }
+
+       return (err);
+}
+
+/* SPX packet transmit engine */
+static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
+{
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+        struct ipxspxhdr *ipxh;
+       int flags, err;
+
+       if(skb == NULL)
+       {
+               int offset  = ipx_if_offset(pdata->dest_addr.net);
+               int size    = offset + sizeof(struct ipxspxhdr);
+
+               save_flags(flags);
+               cli();
+               skb = sock_alloc_send_skb(sk, size, 0, 0, &err);
+               if(skb == NULL)
+                       return (-ENOMEM);
+               skb_reserve(skb, offset);
+               skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
+               restore_flags(flags);
+       }
+
+       /* IPX header */
+       ipxh = (struct ipxspxhdr *)skb->nh.raw;
+       ipxh->ipx.ipx_checksum  = 0xFFFF;
+       ipxh->ipx.ipx_pktsize   = htons(SPX_SYS_PKT_LEN);
+        ipxh->ipx.ipx_tctrl     = 0;
+       ipxh->ipx.ipx_type      = IPX_TYPE_SPX;
+        ipxh->ipx.ipx_dest      = pdata->dest_addr;
+        ipxh->ipx.ipx_source    = pdata->source_addr;
+
+       /* SPX header */
+        ipxh->spx.dtype         = 0;
+       ipxh->spx.sequence      = htons(pdata->sequence);
+       ipxh->spx.ackseq        = htons(pdata->rmt_seq);
+       ipxh->spx.sconn         = pdata->source_connid;
+        ipxh->spx.dconn         = pdata->dest_connid;
+        ipxh->spx.allocseq      = htons(pdata->alloc);
+
+       /* Reset/Set WD timer */
+        del_timer(&pdata->watchdog);
+        pdata->watchdog.expires = jiffies + VERIFY_TIMEOUT;
+        add_timer(&pdata->watchdog);
+
+       switch(type)
+       {
+               case (DATA):    /* Data */
+                       ipxh->ipx.ipx_pktsize   = htons(SPX_SYS_PKT_LEN + len);
+                       ipxh->spx.cctl          = (CCTL_ACK | CCTL_EOM);
+                       pdata->sequence++;
+                       break;
+
+               case (ACK):     /* Connection/WD/Data ACK */
+                       pdata->rmt_seq++;
+               case (WDACK):
+               case (CONACK):
+                       ipxh->spx.cctl          = CCTL_SYS;
+                       ipxh->spx.ackseq        = htons(pdata->rmt_seq);
+                       break;
+
+               case (CONREQ):  /* Connection Request */
+                       del_timer(&pdata->watchdog);
+               case (WDREQ):   /* WD Request */
+                       pdata->source_connid    = htons(connids++);
+                       pdata->dest_connid      = 0xFFFF;
+                       pdata->alloc            = 3 + pdata->rmt_seq;
+                       ipxh->spx.cctl          = (CCTL_ACK | CCTL_SYS);
+                       ipxh->spx.sconn         = pdata->source_connid;
+                       ipxh->spx.dconn         = pdata->dest_connid;
+                       ipxh->spx.allocseq      = htons(pdata->alloc);
+                       break;
+
+               case (DISCON):  /* Informed Disconnect */
+                       ipxh->spx.cctl          = CCTL_ACK;
+                       ipxh->spx.dtype         = SPX_DTYPE_ECONN;
+                       break;
+
+               case (DISACK):  /* Informed Disconnect ACK */
+                       ipxh->spx.cctl          = 0;
+                       ipxh->spx.dtype         = SPX_DTYPE_ECACK;
+                       ipxh->spx.sequence      = 0;
+                       ipxh->spx.ackseq        = htons(pdata->rmt_seq++);
+                       break;
+
+               default:
+                       return (-EOPNOTSUPP);
+       }
+
+       /* Send data */
+       spx_route_skb(pdata, skb, type);
+
+        return (0);
+}
+
+/* Check the state of the connection and send a WD request if needed. */
+static void spx_watchdog(unsigned long data)
+{
+       struct sock *sk = (struct sock*)data;
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+        del_timer(&pdata->watchdog);
+       if(pdata->retries > pdata->max_retries)
+        {
+               spx_close_socket(sk);   /* Unilateral Abort */
+                return;
+        }
+
+        /* Send WD request */
+       spx_transmit(sk, NULL, WDREQ, 0);
+       pdata->retries++;
+
+        return;
+}
+
+static void spx_retransmit(unsigned long data)
+{
+       struct sock *sk = (struct sock*)data;
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+       struct sk_buff *skb;
+       int err;
+
+       del_timer(&pdata->retransmit);
+       if(pdata->retransmits > RETRY_COUNT)
+       {
+               spx_close_socket(sk);   /* Unilateral Abort */
+                return;
+        }
+
+       /* need to leave skb on the queue! */
+       skb = skb_peek(&pdata->retransmit_queue);
+       if(skb_cloned(skb))
+                skb = skb_copy(skb, GFP_ATOMIC);
+        else
+                skb = skb_clone(skb, GFP_ATOMIC);
+
+       pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);
+       add_timer(&pdata->retransmit);
+
+       err = spx_route_skb(pdata, skb, RETRAN);
+       pdata->retransmits++;
+
+       return;
+}
+
+/* SPX packet receive engine */
+void spx_rcv(struct sock *sk, int bytes)
+{
+       struct sk_buff *skb;
+       struct sk_buff *skb2;
+       struct ipxspxhdr *ipxh;
+       struct ipxspxhdr *ipxh2;
+       struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+       skb = skb_dequeue(&sk->receive_queue);
+       if(skb == NULL)
+               return;
+       ipxh = (struct ipxspxhdr *)skb->nh.raw;
+
+       /* Can't receive on a closed connection */
+        if((pdata->state == SPX_CLOSED) && (ipxh->spx.sequence != 0))
+               return;
+       if(ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN)
+               return;
+        if(ipxh->ipx.ipx_type != IPX_TYPE_SPX)
+               return;
+
+       /* insanity - rcv'd ACK of unsent data ?? */
+        if(ntohs(ipxh->spx.ackseq) > pdata->sequence)
+               return;
+
+       /* Reset WD timer on any received packet */
+       del_timer(&pdata->watchdog);
+       pdata->retries = 0;
+       pdata->watchdog.expires = jiffies + ABORT_TIMEOUT;
+        add_timer(&pdata->watchdog);
+
+       switch(ipxh->spx.cctl)
+       {
+               case (CCTL_SYS | CCTL_ACK):
+                       if((ipxh->spx.sequence == 0)    /* ConReq */
+                               && (ipxh->spx.ackseq == 0)
+                               && (ipxh->spx.dconn == 0xFFFF))
+                       {
+                               pdata->state            = SPX_CONNECTED;
+                               pdata->dest_addr        = ipxh->ipx.ipx_source;
+                               pdata->source_addr      = ipxh->ipx.ipx_dest;
+                               pdata->dest_connid      = ipxh->spx.sconn;
+                               pdata->alloc = 3 + ntohs(ipxh->spx.sequence);
+
+                               skb_queue_tail(&sk->receive_queue, skb);
+                               wake_up_interruptible(sk->sleep);
+                       }
+                       else    /* WD Request */
+                               spx_transmit(sk, skb, WDACK, 0);
+                       break;
+
+               case CCTL_SYS:  /* ACK */
+                       if((ipxh->spx.dtype == 0)       /* ConReq ACK */
+                                && (ipxh->spx.sconn != 0xFFFF)
+                                && (ipxh->spx.dconn != 0xFFFF)
+                                && (ipxh->spx.sequence == 0)
+                                && (ipxh->spx.ackseq == 0)
+                                && (pdata->state != SPX_CONNECTED))
+                        {
+                                pdata->state = SPX_CONNECTED;
+
+                                skb_queue_tail(&sk->receive_queue, skb);
+                                wake_up_interruptible(sk->sleep);
+                                break;
+                        }
+
+                       /* Check Data/ACK seq */
+                        skb2 = skb_dequeue(&pdata->retransmit_queue);
+                        if(skb2)
+                        {
+                               ipxh2 = (struct ipxspxhdr *)skb2->nh.raw;
+                                if((ntohs(ipxh2->spx.sequence)
+                                        == (ntohs(ipxh->spx.ackseq) - 1))
+                                       || (ntohs(ipxh2->spx.sequence) == 65535
+                                       && ntohs(ipxh->spx.ackseq) == 0))
+                                {
+                                       del_timer(&pdata->retransmit);
+                                       pdata->retransmits = 0;
+                                        kfree_skb(skb2);
+                                       if(skb_queue_empty(&pdata->retransmit_queue))
+                                       {
+                                               skb2 = skb_dequeue(&pdata->transmit_queue);
+                                               if(skb2 != NULL)
+                                                       spx_route_skb(pdata, skb2, TQUEUE);
+                                       }
+                                }
+                                else    /* Out of Seq - ERROR! */
+                               skb_queue_head(&pdata->retransmit_queue, skb2);
+                        }
+
+                       kfree_skb(skb);
+                       break;
+
+               case (CCTL_ACK):        /* Informed Disconnect */
+                       if(ipxh->spx.dtype == SPX_DTYPE_ECONN)
+                       {
+                               spx_transmit(sk, skb, DISACK, 0);
+                               spx_close_socket(sk);
+                       }
+                       break;
+
+               default:
+                       if(ntohs(ipxh->spx.sequence) == pdata->rmt_seq)
+                       {
+                               pdata->rmt_seq = ntohs(ipxh->spx.sequence);
+                               skb_queue_tail(&pdata->rcv_queue, skb);
+                               wake_up_interruptible(sk->sleep);
+                               spx_transmit(sk, NULL, ACK, 0);
+                               break;
+                       }
+
+                       /* Catch All */
+                       kfree_skb(skb);
+                       break;
+       }
+
+        return;
+}
+
+/* Get message/packet data from user-land */
+static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+                       struct scm_cookie *scm)
+{
+       struct sock *sk = sock->sk;
+       int flags = msg->msg_flags;
+       struct sk_buff *skb;
+       int err, offset, size;
+
+       if(len > 534)
+                return (-EMSGSIZE);
+        if(sk->zapped)
+                return (-ENOTCONN); /* Socket not bound */
+       if(flags&~MSG_DONTWAIT)
+                return (-EINVAL);
+
+       offset  = ipx_if_offset(sk->tp_pinfo.af_spx.dest_addr.net);
+        size   = offset + sizeof(struct ipxspxhdr) + len;
+        skb    = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err);
+        if(skb == NULL)
+                return (err);
+
+       skb->sk = sk;
+        skb_reserve(skb, offset);
+       skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
+
+       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+       if(err)
+        {
+                kfree_skb(skb);
+                return (-EFAULT);
+        }
+
+       err = spx_transmit(sk, skb, DATA, len);
+       if(err)
+               return (-EAGAIN);
+
+        return (len);
+}
+
+/* Send message/packet data to user-land */
+static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+                       int flags, struct scm_cookie *scm)
+{
+       struct sk_buff *skb;
+       struct ipxspxhdr *ispxh;
+       struct sock *sk = sock->sk;
+       struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+       struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
+       int copied, err;
+
+        if(sk->zapped)
+                return (-ENOTCONN); /* Socket not bound */
+
+       lock_sock(sk);
+restart:
+        while(skb_queue_empty(&pdata->rcv_queue))      /* No data */
+        {
+                /* Socket errors? */
+                err = sock_error(sk);
+                if(err)
+                       return (err);
+
+                /* Socket shut down? */
+                if(sk->shutdown & RCV_SHUTDOWN)
+                       return (-ESHUTDOWN);
+
+                /* handle signals */
+                if(signal_pending(current))
+                       return (-ERESTARTSYS);
+
+                /* User doesn't want to wait */
+                if(flags&MSG_DONTWAIT)
+                       return (-EAGAIN);
+
+               release_sock(sk);
+               save_flags(flags);
+               cli();
+               if(skb_peek(&pdata->rcv_queue) == NULL)
+                       interruptible_sleep_on(sk->sleep);
+               restore_flags(flags);
+               lock_sock(sk);
+        }
+
+        skb = skb_dequeue(&pdata->rcv_queue);
+        if(skb == NULL) 
+               goto restart;
+
+       ispxh   = (struct ipxspxhdr *)skb->nh.raw;
+       copied  = ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;
+        if(copied > size)
+       {
+                copied = size;
+                msg->msg_flags |= MSG_TRUNC;
+        }
+
+       err = memcpy_toiovec(msg->msg_iov, skb->nh.raw+SPX_SYS_PKT_LEN, copied);
+        if(err)
+                return (-EFAULT);
+
+       msg->msg_namelen = sizeof(*sipx);
+       if(sipx)
+       {
+               sipx->sipx_family       = AF_IPX;
+                sipx->sipx_port                = ispxh->ipx.ipx_source.sock;
+                memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN);
+                sipx->sipx_network     = ispxh->ipx.ipx_source.net;
+                sipx->sipx_type        = ispxh->ipx.ipx_type;
+        }
+       kfree_skb(skb);
+        release_sock(sk);
+
+       return (copied);
+}
+
+/*
+ * Functions which just wrap their IPX cousins
+ */
+
+static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+        int err;
+        err = ipx_operations->bind(sock, uaddr, addr_len);
+        return (err);
+}
+
+static int spx_getname (struct socket *sock, struct sockaddr *uaddr,
+                         int *usockaddr_len, int peer)
+{
+       int err;
+       err = ipx_operations->getname(sock, uaddr, usockaddr_len, peer);
+       return (err);
+}
+
+static int spx_ioctl (struct socket *sock, unsigned int cmd,
+                         unsigned long arg)
+{
+       int err;
+       err = ipx_operations->ioctl(sock, cmd, arg);
+       return (err);
+}
+
+static int spx_setsockopt(struct socket *sock, int level, int optname,
+                         char *optval, int optlen)
+{
+       int err;
+       err = ipx_operations->setsockopt(sock, level, optname, optval, optlen);
+       return (err);
+}
+
+static int spx_getsockopt(struct socket *sock, int level, int optname,
+                         char *optval, int *optlen)
+{
+       int err;
+       err = ipx_operations->getsockopt(sock, level, optname, optval, optlen);
+       return (err);
+}
+
+static struct proto_ops spx_operations = {
+        AF_IPX,
+        sock_no_dup,
+        spx_release,
+        spx_bind,
+        spx_connect,
+        sock_no_socketpair,
+        spx_accept,
+       spx_getname,
+        datagram_poll,  /* this does seqpacket too */
+       spx_ioctl,
+        spx_listen,
+        spx_shutdown,
+       spx_setsockopt,
+       spx_getsockopt,
+        sock_no_fcntl,
+        spx_sendmsg,
+        spx_recvmsg
+};
+
+static struct net_proto_family spx_family_ops=
+{
+       AF_IPX,
+       spx_create
+};
+
+
+void spx_proto_init(void)
+{
+       int error;
+
+       connids = (__u16)jiffies;       /* initalize random */
+
+       error = ipx_register_spx(&ipx_operations, &spx_family_ops);
+        if (error)
+                printk(KERN_ERR "SPX: unable to register with IPX.\n");
+
+       /* route socket(AF_IPX, SOCK_SEQPACKET) calls through spx_create() */
+
+       printk(KERN_INFO "Sequenced Packet eXchange (SPX) 0.01 for Linux NET3.037\n");
+       return;
+}
+
+void spx_proto_finito(void)
+{
+       ipx_unregister_spx();
+       return;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+        spx_proto_init();
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        spx_proto_finito();
+        return;
+}
+
+#endif /* MODULE */
+#endif /* CONFIG_SPX || CONFIG_SPX_MODULE */
index 4ac78639ba2fe164b8270fa81d9bd15957805b1e..1afcfd8e738dffd3fcdc816a1e4c3ce5507832a7 100644 (file)
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := netrom.o
-O_OBJS  := af_netrom.o nr_dev.o nr_in.o nr_out.o nr_route.o nr_subr.o nr_timer.o
+O_OBJS  := af_netrom.o nr_dev.o nr_in.o nr_loopback.o nr_out.o nr_route.o \
+           nr_subr.o nr_timer.o
 M_OBJS   := $(O_TARGET)
 
 ifeq ($(CONFIG_SYSCTL),y)
index 9d8a206da99c9cf6db56899c48cbceb604b1afe7..59d3dacfbe561cae292a43ee548ef89c6ae53057 100644 (file)
@@ -258,6 +258,28 @@ static struct sock *nr_find_peer(unsigned char index, unsigned char id)
        return NULL;
 }
 
+/*
+ *     Find next free circuit ID.
+ */
+static unsigned short nr_find_next_circuit(void)
+{
+       unsigned short id = circuit;
+       unsigned char i, j;
+
+       for (;;) {
+               i = id / 256;
+               j = id % 256;
+
+               if (i != 0 && j != 0)
+                       if (nr_find_socket(i, j) == NULL)
+                               break;
+
+               id++;
+       }
+
+       return id;
+}
+
 /*
  *     Deferred destroy.
  */
@@ -535,12 +557,12 @@ static int nr_release(struct socket *sock, struct socket *peer)
        switch (sk->protinfo.nr->state) {
 
                case NR_STATE_0:
+               case NR_STATE_1:
                case NR_STATE_2:
                        nr_disconnect(sk, 0);
                        nr_destroy_socket(sk);
                        break;
 
-               case NR_STATE_1:
                case NR_STATE_3:
                        nr_clear_queues(sk);
                        sk->protinfo.nr->n2count = 0;
@@ -670,8 +692,7 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
 
        sk->protinfo.nr->dest_addr = addr->sax25_call;
 
-       while (nr_find_socket((unsigned char)circuit / 256, (unsigned char)circuit % 256) != NULL)
-               circuit++;
+       circuit = nr_find_next_circuit();
 
        sk->protinfo.nr->my_index = circuit / 256;
        sk->protinfo.nr->my_id    = circuit % 256;
@@ -764,7 +785,6 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
        sti();
 
        /* Now attach up the new socket */
-       skb->sk = NULL;
        kfree_skb(skb);
        sk->ack_backlog--;
        newsock->sk = newsk;
@@ -802,7 +822,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
        struct sock *make;      
        ax25_address *src, *dest, *user;
        unsigned short circuit_index, circuit_id;
-       unsigned short frametype, window, timeout;
+       unsigned short peer_circuit_index, peer_circuit_id;
+       unsigned short frametype, flags, window, timeout;
 
        skb->sk = NULL;         /* Initially we don't know who it's for */
 
@@ -813,28 +834,46 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
        src  = (ax25_address *)(skb->data + 0);
        dest = (ax25_address *)(skb->data + 7);
 
-       circuit_index = skb->data[15];
-       circuit_id    = skb->data[16];
-       frametype     = skb->data[19] & 0x0F;
+       circuit_index      = skb->data[15];
+       circuit_id         = skb->data[16];
+       peer_circuit_index = skb->data[17];
+       peer_circuit_id    = skb->data[18];
+       frametype          = skb->data[19] & 0x0F;
+       flags              = skb->data[19] & 0xF0;
 
 #ifdef CONFIG_INET
        /*
         * Check for an incoming IP over NET/ROM frame.
         */
-        if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
+       if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
                skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
-               skb->h.raw = skb->data;
+               skb->h.raw = skb->data;
 
                return nr_rx_ip(skb, dev);
-        }
+       }
 #endif
 
        /*
         * Find an existing socket connection, based on circuit ID, if it's
         * a Connect Request base it on their circuit ID.
+        *
+        * Circuit ID 0/0 is not valid but it could still be a "reset" for a
+        * circuit that no longer exists at the other end ...
         */
-       if ((frametype != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
-           (frametype == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) {
+
+       sk = NULL;
+
+       if (circuit_index == 0 && circuit_id == 0) {
+               if (frametype == NR_CONNACK && flags == NR_CHOKE_FLAG)
+                       sk = nr_find_peer(peer_circuit_index, peer_circuit_id);
+       } else {
+               if (frametype == NR_CONNREQ)
+                       sk = nr_find_peer(circuit_index, circuit_id);
+               else
+                       sk = nr_find_socket(circuit_index, circuit_id);
+       }
+
+       if (sk != NULL) {
                skb->h.raw = skb->data;
 
                if (frametype == NR_CONNACK && skb->len == 22)
@@ -845,15 +884,17 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
                return nr_process_rx_frame(sk, skb);
        }
 
-       switch (frametype) {
-               case NR_CONNREQ:
-                       break;
-               case NR_DISCREQ:
-               case NR_DISCACK:
-                       return 0;
-               default:
-                       nr_transmit_dm(skb);
-                       return 0;
+       /*
+        * Now it should be a CONNREQ.
+        */
+       if (frametype != NR_CONNREQ) {
+               /*
+                * Never reply to a CONNACK/CHOKE.
+                */
+               if (frametype != NR_CONNACK || flags != NR_CHOKE_FLAG)
+                       nr_transmit_refusal(skb, 1);
+
+               return 0;
        }
 
        sk = nr_find_listener(dest);
@@ -861,7 +902,7 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
        user = (ax25_address *)(skb->data + 21);
 
        if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = nr_make_new(sk)) == NULL) {
-               nr_transmit_dm(skb);
+               nr_transmit_refusal(skb, 0);
                return 0;
        }
 
@@ -878,6 +919,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
        make->protinfo.nr->your_index  = circuit_index;
        make->protinfo.nr->your_id     = circuit_id;
 
+       circuit = nr_find_next_circuit();
+
        make->protinfo.nr->my_index    = circuit / 256;
        make->protinfo.nr->my_id       = circuit % 256;
 
@@ -1131,7 +1174,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
 
        cli();
 
-       len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2     t4      idle   n2  wnd Snd-Q Rcv-Q\n");
+       len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2     t4      idle   n2  wnd Snd-Q Rcv-Q inode\n");
 
        for (s = nr_list; s != NULL; s = s->next) {
                if ((dev = s->protinfo.nr->device) == NULL)
@@ -1143,7 +1186,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
                        ax2asc(&s->protinfo.nr->user_addr));
                len += sprintf(buffer + len, "%-9s ",
                        ax2asc(&s->protinfo.nr->dest_addr));
-               len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d\n",
+               len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n",
                        ax2asc(&s->protinfo.nr->source_addr),
                        devname,
                        s->protinfo.nr->my_index,
@@ -1166,7 +1209,8 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
                        s->protinfo.nr->n2,
                        s->protinfo.nr->window,
                        atomic_read(&s->wmem_alloc),
-                       atomic_read(&s->rmem_alloc));
+                       atomic_read(&s->rmem_alloc),
+                       s->socket != NULL ? s->socket->inode->i_ino : 0L);
 
                pos = begin + len;
 
@@ -1273,6 +1317,8 @@ __initfunc(void nr_proto_init(struct net_proto *pro))
        nr_register_sysctl();
 #endif
 
+       nr_loopback_init();
+
 #ifdef CONFIG_PROC_FS
        proc_net_register(&proc_net_nr);
        proc_net_register(&proc_net_nr_neigh);
@@ -1305,6 +1351,8 @@ void cleanup_module(void)
        proc_net_unregister(PROC_NET_NR_NEIGH);
        proc_net_unregister(PROC_NET_NR_NODES);
 #endif
+       nr_loopback_clear();
+
        nr_rt_free();
 
        ax25_protocol_release(AX25_P_NETROM);
index ac32cd704efca3f7267b19503d54996ced7dae38..fadf69de8c256f73c010287f43738359a786e132 100644 (file)
@@ -129,6 +129,10 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype
 {
        switch (frametype) {
 
+               case NR_CONNACK | NR_CHOKE_FLAG:
+                       nr_disconnect(sk, ECONNRESET);
+                       break;
+
                case NR_DISCREQ:
                        nr_write_internal(sk, NR_DISCACK);
 
@@ -170,6 +174,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
                        nr_disconnect(sk, 0);
                        break;
 
+               case NR_CONNACK | NR_CHOKE_FLAG:
                case NR_DISCACK:
                        nr_disconnect(sk, ECONNRESET);
                        break;
diff --git a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c
new file mode 100644 (file)
index 0000000..ba9644c
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *     NET/ROM release 007
+ *
+ *     This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *     This module:
+ *             This module is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ *     History
+ *     NET/ROM 007     Tomi(OH2BNS)    Created this file.
+ *
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/timer.h>
+#include <net/ax25.h>
+#include <linux/skbuff.h>
+#include <net/netrom.h>
+
+static struct sk_buff_head loopback_queue;
+static struct timer_list loopback_timer;
+
+static void nr_set_loopback_timer(void);
+
+void nr_loopback_init(void)
+{
+       skb_queue_head_init(&loopback_queue);
+
+       init_timer(&loopback_timer);
+}
+
+static int nr_loopback_running(void)
+{
+       return (loopback_timer.prev != NULL || loopback_timer.next != NULL);
+}
+
+int nr_loopback_queue(struct sk_buff *skb)
+{
+       struct sk_buff *skbn;
+
+       skbn = skb_clone(skb, GFP_ATOMIC);
+
+       kfree_skb(skb);
+
+       if (skbn != NULL) {
+               skb_queue_tail(&loopback_queue, skbn);
+
+               if (!nr_loopback_running())
+                       nr_set_loopback_timer();
+       }
+
+       return 1;
+}
+
+static void nr_loopback_timer(unsigned long);
+
+static void nr_set_loopback_timer(void)
+{
+       del_timer(&loopback_timer);
+
+       loopback_timer.data     = 0;
+       loopback_timer.function = &nr_loopback_timer;
+       loopback_timer.expires  = jiffies + 10;
+
+       add_timer(&loopback_timer);
+}
+
+static void nr_loopback_timer(unsigned long param)
+{
+       struct sk_buff *skb;
+       ax25_address *nr_dest;
+       struct device *dev;
+
+       while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+               nr_dest = (ax25_address *)(skb->data + 7);
+
+               if ((dev = nr_dev_get(nr_dest)) == NULL) {
+                       kfree_skb(skb);
+                       continue;
+               }
+
+               if (nr_rx_frame(skb, dev) == 0)
+                       kfree_skb(skb);
+       }
+}
+
+#ifdef MODULE
+
+void nr_loopback_clear(void)
+{
+       struct sk_buff *skb;
+
+       del_timer(&loopback_timer);
+
+       while ((skb = skb_dequeue(&loopback_queue)) != NULL)
+               kfree_skb(skb);
+}
+
+#endif
+
+#endif
index ffbb240c411af1c4829f1b3a85f74c9c996b14fd..26f5ac8ddf6497cde1d6017aa59b97397e940fff 100644 (file)
@@ -697,8 +697,12 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
                            ax25->ax25_dev->dev, 0, sysctl_netrom_obsolescence_count_initialiser);
 
-       if ((dev = nr_dev_get(nr_dest)) != NULL)        /* Its for me */
-               return nr_rx_frame(skb, dev);
+       if ((dev = nr_dev_get(nr_dest)) != NULL) {      /* Its for me */
+               if (ax25 == NULL)                       /* Its from me */
+                       return nr_loopback_queue(skb);
+               else
+                       return nr_rx_frame(skb, dev);
+       }
 
        if (!sysctl_netrom_routing_control && ax25 != NULL)
                return 0;
index 7ae69fe07236f1a3051b5c047b3fc78897bcc008..096ca3a8f5820269272bb427993e3d474e032d54 100644 (file)
@@ -229,7 +229,7 @@ void nr_write_internal(struct sock *sk, int frametype)
  * This routine is called when a Connect Acknowledge with the Choke Flag
  * set is needed to refuse a connection.
  */
-void nr_transmit_dm(struct sk_buff *skb)
+void nr_transmit_refusal(struct sk_buff *skb, int mine)
 {
        struct sk_buff *skbn;
        unsigned char *dptr;
@@ -258,10 +258,18 @@ void nr_transmit_dm(struct sk_buff *skb)
 
        *dptr++ = sysctl_netrom_network_ttl_initialiser;
 
-       *dptr++ = skb->data[15];
-       *dptr++ = skb->data[16];
-       *dptr++ = 0;
-       *dptr++ = 0;
+       if (mine) {
+               *dptr++ = 0;
+               *dptr++ = 0;
+               *dptr++ = skb->data[15];
+               *dptr++ = skb->data[16];
+       } else {
+               *dptr++ = skb->data[15];
+               *dptr++ = skb->data[16];
+               *dptr++ = 0;
+               *dptr++ = 0;
+       }
+
        *dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
        *dptr++ = 0;
 
index 4c469e2a2a5f234cf838ef31bdbe3f945d6fd519..abb56a4a0ba847153d3d7d01e4bcc6dba5ab3936 100644 (file)
@@ -64,12 +64,17 @@ extern struct datalink_proto   *make_EII_client(void);
 extern struct datalink_proto   *make_8023_client(void);
 extern void destroy_EII_client(struct datalink_proto *);
 extern void destroy_8023_client(struct datalink_proto *);
+#ifdef CONFIG_SYSCTL
+extern int sysctl_max_syn_backlog;
+#endif
 #endif
 
 #ifdef CONFIG_ATALK_MODULE
 #include <net/sock.h>
 #endif
 
+EXPORT_SYMBOL(dev_lockct);
+
 /* Skbuff symbols. */
 EXPORT_SYMBOL(skb_push_errstr);
 EXPORT_SYMBOL(skb_put_errstr);
@@ -177,17 +182,10 @@ EXPORT_SYMBOL(make_EII_client);
 EXPORT_SYMBOL(destroy_EII_client);
 #endif
 
-#ifdef CONFIG_ATALK_MODULE
 EXPORT_SYMBOL(sklist_destroy_socket);
-#endif
-
-#if defined(CONFIG_ATALK_MODULE) || defined(CONFIG_PACKET_MODULE)
 EXPORT_SYMBOL(sklist_insert_socket);
-#endif
 
-#ifdef CONFIG_SMB_FS_MODULE
 EXPORT_SYMBOL(scm_detach_fds);
-#endif
 
 #ifdef CONFIG_INET
 /* Internet layer registration */
@@ -211,6 +209,7 @@ EXPORT_SYMBOL(ip_mc_inc_group);
 EXPORT_SYMBOL(ip_mc_dec_group);
 EXPORT_SYMBOL(__ip_finish_output);
 EXPORT_SYMBOL(inet_dgram_ops);
+EXPORT_SYMBOL(__release_sock);
 
 /* needed for ip_gre -cw */
 EXPORT_SYMBOL(ip_statistics);
@@ -242,11 +241,8 @@ EXPORT_SYMBOL(destroy_sock);
 EXPORT_SYMBOL(ip_queue_xmit);
 EXPORT_SYMBOL(memcpy_fromiovecend);
 EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
-EXPORT_SYMBOL(__release_sock);
 EXPORT_SYMBOL(net_timer);
 /* UDP/TCP exported functions for TCPv6 */
-EXPORT_SYMBOL(sysctl_tcp_timestamps);
-EXPORT_SYMBOL(sysctl_tcp_window_scaling);
 EXPORT_SYMBOL(sock_rspace);
 EXPORT_SYMBOL(udp_ioctl);
 EXPORT_SYMBOL(udp_connect);
@@ -301,6 +297,9 @@ EXPORT_SYMBOL(tcp_write_xmit);
 EXPORT_SYMBOL(dev_loopback_xmit);
 EXPORT_SYMBOL(tcp_regs);
 
+#ifdef CONFIG_SYSCTL
+EXPORT_SYMBOL(sysctl_max_syn_backlog);
+#endif
 #endif
 
 #ifdef CONFIG_NETLINK
@@ -328,18 +327,16 @@ EXPORT_SYMBOL(neigh_add);
 EXPORT_SYMBOL(neigh_dump_info);
 #endif
 
-#ifdef CONFIG_PACKET_MODULE
 EXPORT_SYMBOL(dev_set_allmulti);
 EXPORT_SYMBOL(dev_set_promiscuity);
 EXPORT_SYMBOL(sklist_remove_socket);
 EXPORT_SYMBOL(rtnl_wait);
 EXPORT_SYMBOL(rtnl_rlockct);
-#endif
+EXPORT_SYMBOL(rtnl_lock);
+EXPORT_SYMBOL(rtnl_unlock);
 
-#if defined(CONFIG_IPV6_MODULE) || defined(CONFIG_PACKET_MODULE)
-EXPORT_SYMBOL(dev_lockct);
 EXPORT_SYMBOL(sock_wmalloc);
-#endif
+EXPORT_SYMBOL(sock_rmalloc);
 
 #if    defined(CONFIG_ULTRA)   ||      defined(CONFIG_WD80x3)          || \
        defined(CONFIG_EL2)     ||      defined(CONFIG_NE2000)          || \
@@ -425,9 +422,6 @@ EXPORT_SYMBOL(ip_rcv);
 EXPORT_SYMBOL(arp_rcv);
 EXPORT_SYMBOL(dev_mc_delete);
 
-EXPORT_SYMBOL(rtnl_lock);
-EXPORT_SYMBOL(rtnl_unlock);
-
 EXPORT_SYMBOL(if_port_text);
 
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) 
index 7eb55881ea7f1ea2378ed92112efc48d8a307be2..de3f1b25718496f258148ece45805d079ec07c3f 100644 (file)
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := rose.o
-O_OBJS  := af_rose.o rose_dev.o rose_in.o rose_link.o rose_out.o rose_route.o rose_subr.o rose_timer.o
+O_OBJS  := af_rose.o rose_dev.o rose_in.o rose_link.o rose_loopback.o \
+           rose_out.o rose_route.o rose_subr.o rose_timer.o
 M_OBJS   := $(O_TARGET)
 
 ifeq ($(CONFIG_SYSCTL),y)
index a575402c7febd0f0b2c49a4df9018243a2f5fa28..286a2aa6811c59fc3eae238efdb503f32a60649a 100644 (file)
@@ -1261,7 +1261,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
 
        cli();
 
-       len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q\n");
+       len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");
 
        for (s = rose_list; s != NULL; s = s->next) {
                if ((dev = s->protinfo.rose->device) == NULL)
@@ -1278,7 +1278,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
                else
                        callsign = ax2asc(&s->protinfo.rose->source_call);
 
-               len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d\n",
+               len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
                        rose2asc(&s->protinfo.rose->source_addr),
                        callsign,
                        devname, 
@@ -1295,7 +1295,8 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
                        ax25_display_timer(&s->protinfo.rose->idletimer) / (60 * HZ),
                        s->protinfo.rose->idle / (60 * HZ),
                        atomic_read(&s->wmem_alloc),
-                       atomic_read(&s->rmem_alloc));
+                       atomic_read(&s->rmem_alloc),
+                       s->socket != NULL ? s->socket->inode->i_ino : 0L);
 
                pos = begin + len;
 
@@ -1408,6 +1409,9 @@ __initfunc(void rose_proto_init(struct net_proto *pro))
 #ifdef CONFIG_SYSCTL
        rose_register_sysctl();
 #endif
+       rose_loopback_init();
+
+       rose_add_loopback_neigh();
 
 #ifdef CONFIG_PROC_FS
        proc_net_register(&proc_net_rose);
@@ -1443,6 +1447,8 @@ void cleanup_module(void)
        proc_net_unregister(PROC_NET_RS_NODES);
        proc_net_unregister(PROC_NET_RS_ROUTES);
 #endif
+       rose_loopback_clear();
+
        rose_rt_free();
 
        ax25_protocol_release(AX25_P_ROSE);
index 0cc81c46443ef51cd19a6bd27b6211927ee1ac2a..702a5593192120d652870acc5cc186629df711af 100644 (file)
@@ -134,11 +134,11 @@ static int rose_set_mac_address(struct device *dev, void *addr)
 {
        struct sockaddr *sa = addr;
 
-       ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
+       rose_del_loopback_node((rose_address *)dev->dev_addr);
 
        memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
 
-       ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
+       rose_add_loopback_node((rose_address *)dev->dev_addr);
 
        return 0;
 }
@@ -150,7 +150,7 @@ static int rose_open(struct device *dev)
 
        MOD_INC_USE_COUNT;
 
-       ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
+       rose_add_loopback_node((rose_address *)dev->dev_addr);
 
        return 0;
 }
@@ -162,7 +162,7 @@ static int rose_close(struct device *dev)
 
        MOD_DEC_USE_COUNT;
 
-       ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
+       rose_del_loopback_node((rose_address *)dev->dev_addr);
 
        return 0;
 }
index de412d3c453d1d1d3e933751c956770a96076495..be86c9e16725bfb7c5277fb13cc213fada370c3d 100644 (file)
@@ -141,10 +141,6 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
 
                case ROSE_RR:
                case ROSE_RNR:
-                       if (frametype == ROSE_RNR)
-                               sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
-                       else
-                               sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
                        if (!rose_validate_nr(sk, nr)) {
                                rose_write_internal(sk, ROSE_RESET_REQUEST);
                                sk->protinfo.rose->condition = 0x00;
@@ -157,8 +153,11 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                                rose_stop_idletimer(sk);
                        } else {
                                rose_frames_acked(sk, nr);
-                               if (frametype == ROSE_RNR)
-                                       rose_requeue_frames(sk);
+                               if (frametype == ROSE_RNR) {
+                                       sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
+                               } else {
+                                       sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
+                               }
                        }
                        break;
 
@@ -177,16 +176,26 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                                break;
                        }
                        rose_frames_acked(sk, nr);
-                       if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
-                               break;
                        if (ns == sk->protinfo.rose->vr) {
                                rose_start_idletimer(sk);
                                if (sock_queue_rcv_skb(sk, skb) == 0) {
                                        sk->protinfo.rose->vr = (sk->protinfo.rose->vr + 1) % ROSE_MODULUS;
                                        queued = 1;
                                } else {
-                                       sk->protinfo.rose->condition |= ROSE_COND_OWN_RX_BUSY;
+                                       /* Should never happen ! */
+                                       rose_write_internal(sk, ROSE_RESET_REQUEST);
+                                       sk->protinfo.rose->condition = 0x00;
+                                       sk->protinfo.rose->vs        = 0;
+                                       sk->protinfo.rose->vr        = 0;
+                                       sk->protinfo.rose->va        = 0;
+                                       sk->protinfo.rose->vl        = 0;
+                                       sk->protinfo.rose->state     = ROSE_STATE_4;
+                                       rose_start_t2timer(sk);
+                                       rose_stop_idletimer(sk);
+                                       break;
                                }
+                               if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
+                                       sk->protinfo.rose->condition |= ROSE_COND_OWN_RX_BUSY;
                        }
                        /*
                         * If the window is full, ack the frame, else start the
index c462fa6962f03137c70e61847f2957c8d1ff3359..33cc2f9909b6df4c7e61f0b9c7660aac8c06c78f 100644 (file)
@@ -113,7 +113,7 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
        else
                rose_call = &rose_callsign;
 
-       neigh->ax25 = ax25_send_frame(skb, 0, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+       neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 
        return (neigh->ax25 != NULL);
 }
@@ -296,6 +296,11 @@ void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
                return;
        }
 
+       if (neigh->loopback) {
+               rose_loopback_queue(skb, neigh);
+               return;
+       }
+
        if (!rose_link_up(neigh))
                neigh->restarted = 0;
 
diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c
new file mode 100644 (file)
index 0000000..ce66a99
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *     ROSE release 003
+ *
+ *     This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *     This module:
+ *             This module is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ *     History
+ *     ROSE 003        Jonathan(G4KLX) Created this file from nr_loopback.c.
+ *
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/timer.h>
+#include <net/ax25.h>
+#include <linux/skbuff.h>
+#include <net/rose.h>
+
+static struct sk_buff_head loopback_queue;
+static struct timer_list loopback_timer;
+
+static void rose_set_loopback_timer(void);
+
+void rose_loopback_init(void)
+{
+       skb_queue_head_init(&loopback_queue);
+
+       init_timer(&loopback_timer);
+}
+
+static int rose_loopback_running(void)
+{
+       return (loopback_timer.prev != NULL || loopback_timer.next != NULL);
+}
+
+int rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh)
+{
+       struct sk_buff *skbn;
+
+       skbn = skb_clone(skb, GFP_ATOMIC);
+
+       kfree_skb(skb);
+
+       if (skbn != NULL) {
+               skb_queue_tail(&loopback_queue, skbn);
+
+               if (!rose_loopback_running())
+                       rose_set_loopback_timer();
+       }
+
+       return 1;
+}
+
+static void rose_loopback_timer(unsigned long);
+
+static void rose_set_loopback_timer(void)
+{
+       del_timer(&loopback_timer);
+
+       loopback_timer.data     = 0;
+       loopback_timer.function = &rose_loopback_timer;
+       loopback_timer.expires  = jiffies + 10;
+
+       add_timer(&loopback_timer);
+}
+
+static void rose_loopback_timer(unsigned long param)
+{
+       struct sk_buff *skb;
+       struct device *dev;
+       rose_address *dest;
+       struct sock *sk;
+       unsigned short frametype;
+       unsigned int lci_i, lci_o;
+
+       while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+               lci_i     = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
+               frametype = skb->data[2];
+               dest      = (rose_address *)(skb->data + 4);
+               lci_o     = sysctl_rose_maximum_vcs - lci_i + 1;
+
+               skb->h.raw = skb->data;
+
+               if ((sk = rose_find_socket(lci_o, rose_loopback_neigh)) != NULL) {
+                       if (rose_process_rx_frame(sk, skb) == 0)
+                               kfree_skb(skb);
+                       continue;
+               }
+
+               if (frametype == ROSE_CALL_REQUEST) {
+                       if ((dev = rose_dev_get(dest)) != NULL) {
+                               if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0)
+                                       kfree_skb(skb);
+                       } else {
+                               kfree_skb(skb);
+                       }
+               } else {
+                       kfree_skb(skb);
+               }
+       }
+}
+
+#ifdef MODULE
+
+void rose_loopback_clear(void)
+{
+       struct sk_buff *skb;
+
+       del_timer(&loopback_timer);
+
+       while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+               skb->sk = NULL;
+               kfree_skb(skb);
+       }
+}
+
+#endif
+
+#endif
index 917846bf7a4f39603b9058e567de12e844b8d273..2d6d23230e29369156bf7e4b93a5ae2ca502fc97 100644 (file)
@@ -55,6 +55,8 @@ static struct rose_node  *rose_node_list  = NULL;
 static struct rose_neigh *rose_neigh_list = NULL;
 static struct rose_route *rose_route_list = NULL;
 
+struct rose_neigh *rose_loopback_neigh = NULL;
+
 static void rose_remove_neigh(struct rose_neigh *);
 
 /*
@@ -72,6 +74,9 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
                if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
                        break;
 
+       if (rose_node != NULL && rose_node->loopback)
+               return -EINVAL;
+
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
                if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
                        break;
@@ -87,6 +92,7 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
                rose_neigh->count     = 0;
                rose_neigh->use       = 0;
                rose_neigh->dce_mode  = 0;
+               rose_neigh->loopback  = 0;
                rose_neigh->number    = rose_neigh_no++;
                rose_neigh->restarted = 0;
 
@@ -123,6 +129,7 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
                rose_node->address      = rose_route->address;
                rose_node->mask         = rose_route->mask;
                rose_node->count        = 1;
+               rose_node->loopback     = 0;
                rose_node->neighbour[0] = rose_neigh;
 
                save_flags(flags); cli();
@@ -263,6 +270,8 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct device *de
 
        if (rose_node == NULL) return -EINVAL;
 
+       if (rose_node->loopback) return -EINVAL;
+
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
                if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
                        break;
@@ -298,6 +307,86 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct device *de
        return -EINVAL;
 }
 
+/*
+ *     Add the loopback neighbour.
+ */
+int rose_add_loopback_neigh(void)
+{
+       unsigned long flags;
+
+       if ((rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_ATOMIC)) == NULL)
+               return -ENOMEM;
+
+       rose_loopback_neigh->callsign  = null_ax25_address;
+       rose_loopback_neigh->digipeat  = NULL;
+       rose_loopback_neigh->ax25      = NULL;
+       rose_loopback_neigh->dev       = NULL;
+       rose_loopback_neigh->count     = 0;
+       rose_loopback_neigh->use       = 0;
+       rose_loopback_neigh->dce_mode  = 1;
+       rose_loopback_neigh->loopback  = 1;
+       rose_loopback_neigh->number    = rose_neigh_no++;
+       rose_loopback_neigh->restarted = 1;
+
+       save_flags(flags); cli();
+       rose_loopback_neigh->next = rose_neigh_list;
+       rose_neigh_list           = rose_loopback_neigh;
+       restore_flags(flags);
+
+       return 0;
+}
+
+/*
+ *     Add a loopback node.
+ */
+int rose_add_loopback_node(rose_address *address)
+{
+       struct rose_node *rose_node;
+       unsigned long flags;
+
+       for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
+               if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
+                       break;
+
+       if (rose_node != NULL) return 0;
+
+       if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
+               return -ENOMEM;
+
+       rose_node->address      = *address;
+       rose_node->mask         = 10;
+       rose_node->count        = 1;
+       rose_node->loopback     = 1;
+       rose_node->neighbour[0] = rose_loopback_neigh;
+
+       save_flags(flags); cli();
+       rose_node->next = rose_node_list;
+       rose_node_list  = rose_node;
+       restore_flags(flags);
+
+       rose_loopback_neigh->count++;
+
+       return 0;
+}
+
+/*
+ *     Delete a loopback node.
+ */
+void rose_del_loopback_node(rose_address *address)
+{
+       struct rose_node *rose_node;
+
+       for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
+               if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
+                       break;
+
+       if (rose_node == NULL) return;
+
+       rose_remove_node(rose_node);
+
+       rose_loopback_neigh->count--;
+}
+
 /*
  *     A device has been removed. Remove its routes and neighbours.
  */
@@ -723,16 +812,12 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                    rosecmp(src_addr, &rose_route->src_addr) == 0 &&
                    ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 &&
                    ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
-                       printk(KERN_DEBUG "ROSE: routing loop from %s\n", rose2asc(src_addr));
-                       printk(KERN_DEBUG "ROSE:                to %s\n", rose2asc(dest_addr));
                        rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
                        return 0;
                }
        }
 
        if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
-               if (cause == ROSE_NOT_OBTAINABLE)
-                       printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr));
                rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
                return 0;
        }
@@ -788,16 +873,22 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset,
        len += sprintf(buffer, "address    mask n neigh neigh neigh\n");
 
        for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) {
-               len += sprintf(buffer + len, "%-10s %04d %d",
-                       rose2asc(&rose_node->address),
-                       rose_node->mask,
-                       rose_node->count);                      
+               if (rose_node->loopback) {
+                       len += sprintf(buffer + len, "%-10s %04d 1 loopback\n",
+                               rose2asc(&rose_node->address),
+                               rose_node->mask);
+               } else {
+                       len += sprintf(buffer + len, "%-10s %04d %d",
+                               rose2asc(&rose_node->address),
+                               rose_node->mask,
+                               rose_node->count);
 
-               for (i = 0; i < rose_node->count; i++)
-                       len += sprintf(buffer + len, " %05d",
-                               rose_node->neighbour[i]->number);
+                       for (i = 0; i < rose_node->count; i++)
+                               len += sprintf(buffer + len, " %05d",
+                                       rose_node->neighbour[i]->number);
 
-               len += sprintf(buffer + len, "\n");
+                       len += sprintf(buffer + len, "\n");
+               }
 
                pos = begin + len;
 
@@ -834,33 +925,35 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset,
        len += sprintf(buffer, "addr  callsign  dev  count use mode restart  t0  tf digipeaters\n");
 
        for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
-               len += sprintf(buffer + len, "%05d %-9s %-4s   %3d %3d  %3s     %3s %3lu %3lu",
-                       rose_neigh->number,
-                       ax2asc(&rose_neigh->callsign),
-                       rose_neigh->dev ? rose_neigh->dev->name : "???",
-                       rose_neigh->count,
-                       rose_neigh->use,
-                       (rose_neigh->dce_mode) ? "DCE" : "DTE",
-                       (rose_neigh->restarted) ? "yes" : "no",
-                       ax25_display_timer(&rose_neigh->t0timer) / HZ,
-                       ax25_display_timer(&rose_neigh->ftimer)  / HZ);
-
-               if (rose_neigh->digipeat != NULL) {
-                       for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
-                               len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
-               }
+               if (!rose_neigh->loopback) {
+                       len += sprintf(buffer + len, "%05d %-9s %-4s   %3d %3d  %3s     %3s %3lu %3lu",
+                               rose_neigh->number,
+                               ax2asc(&rose_neigh->callsign),
+                               rose_neigh->dev ? rose_neigh->dev->name : "???",
+                               rose_neigh->count,
+                               rose_neigh->use,
+                               (rose_neigh->dce_mode) ? "DCE" : "DTE",
+                               (rose_neigh->restarted) ? "yes" : "no",
+                               ax25_display_timer(&rose_neigh->t0timer) / HZ,
+                               ax25_display_timer(&rose_neigh->ftimer)  / HZ);
+
+                       if (rose_neigh->digipeat != NULL) {
+                               for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
+                                       len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
+                       }
 
-               len += sprintf(buffer + len, "\n");
+                       len += sprintf(buffer + len, "\n");
 
-               pos = begin + len;
+                       pos = begin + len;
 
-               if (pos < offset) {
-                       len   = 0;
-                       begin = pos;
-               }
+                       if (pos < offset) {
+                               len   = 0;
+                               begin = pos;
+                       }
 
-               if (pos > offset + length)
-                       break;
+                       if (pos > offset + length)
+                               break;
+               }
        }
 
        sti();
index f95459b97a09511097de8910f7091e4eee633797..6a26240587cfead11d9e1708b14c4963f428b996 100644 (file)
@@ -547,20 +547,19 @@ int sock_wake_async(struct socket *sock, int how)
                return -1;
        switch (how)
        {
-               case 0:
-                       kill_fasync(sock->fasync_list, SIGIO);
+       case 1:
+               if (sock->flags & SO_WAITDATA)
                        break;
-               case 1:
-                       if (!(sock->flags & SO_WAITDATA))
-                               kill_fasync(sock->fasync_list, SIGIO);
-                       break;
-               case 2:
-                       if (sock->flags & SO_NOSPACE)
-                       {
-                               kill_fasync(sock->fasync_list, SIGIO);
-                               sock->flags &= ~SO_NOSPACE;
-                       }
+               goto call_kill;
+       case 2:
+               if (!(sock->flags & SO_NOSPACE))
                        break;
+               sock->flags &= ~SO_NOSPACE;
+               /* fall through */
+       case 0:
+       call_kill:
+               kill_fasync(sock->fasync_list, SIGIO);
+               break;
        }
        return 0;
 }
@@ -827,6 +826,7 @@ restart:
                        sys_close(err);
                        goto restart;
                }
+               /* N.B. Should check for errors here */
                move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
        }
 
@@ -912,13 +912,13 @@ asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockadd
 {
        struct socket *sock;
        char address[MAX_SOCK_ADDR];
-       int len;
-       int err;
+       int len, err;
 
        lock_kernel();
        if ((sock = sockfd_lookup(fd, &err))!=NULL)
        {
-               if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1))==0)
+               err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
+               if (!err)
                        err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
                sockfd_put(sock);
        }
@@ -940,28 +940,22 @@ asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags)
 
        lock_kernel();
        sock = sockfd_lookup(fd, &err);
-       if (!sock)
-               goto out;
-       err = -EINVAL;
-       if (len < 0)
-               goto out_put;
-
-       iov.iov_base=buff;
-       iov.iov_len=len;
-       msg.msg_name=NULL;
-       msg.msg_namelen=0;
-       msg.msg_iov=&iov;
-       msg.msg_iovlen=1;
-       msg.msg_control=NULL;
-       msg.msg_controllen=0;
-       if (sock->file->f_flags & O_NONBLOCK)
-               flags |= MSG_DONTWAIT;
-       msg.msg_flags = flags;
-       err = sock_sendmsg(sock, &msg, len);
+       if (sock) {
+               iov.iov_base=buff;
+               iov.iov_len=len;
+               msg.msg_name=NULL;
+               msg.msg_namelen=0;
+               msg.msg_iov=&iov;
+               msg.msg_iovlen=1;
+               msg.msg_control=NULL;
+               msg.msg_controllen=0;
+               if (sock->file->f_flags & O_NONBLOCK)
+                       flags |= MSG_DONTWAIT;
+               msg.msg_flags = flags;
+               err = sock_sendmsg(sock, &msg, len);
 
-out_put:
-       sockfd_put(sock);
-out:
+               sockfd_put(sock);
+       }
        unlock_kernel();
        return err;
 }
@@ -1140,11 +1134,11 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
 {
        struct socket *sock;
        char address[MAX_SOCK_ADDR];
-       struct iovec iov[UIO_FASTIOV];
+       struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
        unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */
        unsigned char *ctl_buf = ctl;
        struct msghdr msg_sys;
-       int err, ctl_len, total_len;
+       int err, ctl_len, iov_size, total_len;
        
        lock_kernel();
 
@@ -1152,20 +1146,29 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
        if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
                goto out; 
 
+       sock = sockfd_lookup(fd, &err);
+       if (!sock) 
+               goto out;
+
        /* do not move before msg_sys is valid */
        err = -EINVAL;
        if (msg_sys.msg_iovlen > UIO_MAXIOV)
-               goto out;
+               goto out_put;
+
+       /* Check whether to allocate the iovec area*/
+       err = -ENOMEM;
+       iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
+       if (msg_sys.msg_iovlen > 1 /* UIO_FASTIOV */) {
+               iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
+               if (!iov)
+                       goto out_put;
+       }
 
        /* This will also move the address data into kernel space */
        err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
        if (err < 0) 
-               goto out;
-       total_len=err;
-
-       sock = sockfd_lookup(fd, &err);
-       if (!sock) 
                goto out_freeiov;
+       total_len = err;
 
        ctl_len = msg_sys.msg_controllen; 
        if (ctl_len) 
@@ -1181,7 +1184,7 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
                        err = -ENOBUFS;
                        ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
                        if (ctl_buf == NULL) 
-                               goto out_put;
+                               goto out_freeiov;
                }
                err = -EFAULT;
                if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len))
@@ -1197,11 +1200,11 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
 out_freectl:
        if (ctl_buf != ctl)    
                sock_kfree_s(sock->sk, ctl_buf, ctl_len);
+out_freeiov:
+       if (iov != iovstack)
+               sock_kfree_s(sock->sk, iov, iov_size);
 out_put:
        sockfd_put(sock);
-out_freeiov:
-       if (msg_sys.msg_iov != iov)
-               kfree(msg_sys.msg_iov);
 out:       
        unlock_kernel();
        return err;
@@ -1218,9 +1221,7 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
        struct iovec *iov=iovstack;
        struct msghdr msg_sys;
        unsigned long cmsg_ptr;
-       int err;
-       int total_len;
-       int len = 0;
+       int err, iov_size, total_len, len;
 
        /* kernel mode address */
        char addr[MAX_SOCK_ADDR];
@@ -1234,10 +1235,23 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
        if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
                goto out;
 
-       err=-EINVAL;
-       if (msg_sys.msg_iovlen > UIO_MAXIOV)
+       sock = sockfd_lookup(fd, &err);
+       if (!sock)
                goto out;
+
+       err = -EINVAL;
+       if (msg_sys.msg_iovlen > UIO_MAXIOV)
+               goto out_put;
        
+       /* Check whether to allocate the iovec area*/
+       err = -ENOMEM;
+       iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
+       if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+               iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
+               if (!iov)
+                       goto out_put;
+       }
+
        /*
         *      Save the user-mode address (verify_iovec will change the
         *      kernel msghdr to use the kernel address space)
@@ -1245,41 +1259,43 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
         
        uaddr = msg_sys.msg_name;
        uaddr_len = &msg->msg_namelen;
-       err=verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
-       if (err<0)
-               goto out;
-
+       err = verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
+       if (err < 0)
+               goto out_freeiov;
        total_len=err;
 
        cmsg_ptr = (unsigned long)msg_sys.msg_control;
        msg_sys.msg_flags = 0;
        
-       if ((sock = sockfd_lookup(fd, &err))!=NULL)
-       {
-               if (sock->file->f_flags & O_NONBLOCK)
-                       flags |= MSG_DONTWAIT;
-               err=sock_recvmsg(sock, &msg_sys, total_len, flags);
-               if(err>=0)
-                       len=err;
-               sockfd_put(sock);
-       }
-       if (msg_sys.msg_iov != iov)
-               kfree(msg_sys.msg_iov);
+       if (sock->file->f_flags & O_NONBLOCK)
+               flags |= MSG_DONTWAIT;
+       err = sock_recvmsg(sock, &msg_sys, total_len, flags);
+       if (err < 0)
+               goto out_freeiov;
+       len = err;
 
-       if (uaddr != NULL && err>=0)
+       if (uaddr != NULL) {
                err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
-       if (err < 0)
-               goto out;
+               if (err < 0)
+                       goto out_freeiov;
+       }
        err = __put_user(msg_sys.msg_flags, &msg->msg_flags);
        if (err)
-               goto out;
+               goto out_freeiov;
        err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, 
                                                         &msg->msg_controllen);
+       if (err)
+               goto out_freeiov;
+       err = len;
+
+out_freeiov:
+       if (iov != iovstack)
+               sock_kfree_s(sock->sk, iov, iov_size);
+out_put:
+       sockfd_put(sock);
 out:
        unlock_kernel();
-       if(err<0)
-               return err;
-       return len;
+       return err;
 }
 
 
@@ -1462,10 +1478,13 @@ __initfunc(void sock_init(void))
         
        sk_init();
 
+#ifdef SLAB_SKB
        /*
         *      Initialize skbuff SLAB cache 
         */
        skb_init();
+#endif
+
 
        /*
         *      Wan router layer. 
index a85aeea5f73bb6f6244040f7ca80f20018fa8a82..16396040913e25987d18806dad27b80082706025 100644 (file)
@@ -1118,13 +1118,14 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        struct x25_facilities facilities;
                        if (copy_from_user(&facilities, (void *)arg, sizeof(facilities)))
                                return -EFAULT;
-                       if (sk->state != TCP_LISTEN)
+                       if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE)
                                return -EINVAL;
                        if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096)
                                return -EINVAL;
                        if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096)
                                return -EINVAL;
-                       if (sk->protinfo.x25->neighbour->extended) {
+                       if (sk->state == TCP_CLOSE || sk->protinfo.x25->neighbour->extended) 
+                       {
                                if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
                                        return -EINVAL;
                                if (facilities.winsize_out < 1 || facilities.winsize_out > 127)
@@ -1188,7 +1189,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length, in
 
        cli();
 
-       len += sprintf(buffer, "dest_addr  src_addr   dev   lci st vs vr va   t  t2 t21 t22 t23 Snd-Q Rcv-Q\n");
+       len += sprintf(buffer, "dest_addr  src_addr   dev   lci st vs vr va   t  t2 t21 t22 t23 Snd-Q Rcv-Q inode\n");
 
        for (s = x25_list; s != NULL; s = s->next) {
                if (s->protinfo.x25->neighbour == NULL || (dev = s->protinfo.x25->neighbour->dev) == NULL)
@@ -1196,7 +1197,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length, in
                else
                        devname = s->protinfo.x25->neighbour->dev->name;
 
-               len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %5d %5d\n",
+               len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %5d %5d %ld\n",
                        (s->protinfo.x25->dest_addr.x25_addr[0] == '\0')   ? "*" : s->protinfo.x25->dest_addr.x25_addr,
                        (s->protinfo.x25->source_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->source_addr.x25_addr,
                        devname, 
@@ -1211,7 +1212,8 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length, in
                        s->protinfo.x25->t22 / HZ,
                        s->protinfo.x25->t23 / HZ,
                        atomic_read(&s->wmem_alloc),
-                       atomic_read(&s->rmem_alloc));
+                       atomic_read(&s->rmem_alloc),
+                       s->socket != NULL ? s->socket->inode->i_ino : 0L);
 
                pos = begin + len;
 
index b9a66103c31af1ec9c6e59f65bacf538728cbacf..ae98e95ec34e90828c60dab8b0616c1ce51f8613 100644 (file)
@@ -184,11 +184,6 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
 
                case X25_RR:
                case X25_RNR:
-                       if (frametype == X25_RNR) {
-                               sk->protinfo.x25->condition |= X25_COND_PEER_RX_BUSY;
-                       } else {
-                               sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
-                       }
                        if (!x25_validate_nr(sk, nr)) {
                                x25_clear_queues(sk);
                                x25_write_internal(sk, X25_RESET_REQUEST);
@@ -201,8 +196,11 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                sk->protinfo.x25->state     = X25_STATE_4;
                        } else {
                                x25_frames_acked(sk, nr);
-                               if (frametype == X25_RNR)
-                                       x25_requeue_frames(sk);
+                               if (frametype == X25_RNR) {
+                                       sk->protinfo.x25->condition |= X25_COND_PEER_RX_BUSY;
+                               } else {
+                                       sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
+                               }
                        }
                        break;
 
@@ -221,15 +219,25 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                break;
                        }
                        x25_frames_acked(sk, nr);
-                       if (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)
-                               break;
                        if (ns == sk->protinfo.x25->vr) {
                                if (x25_queue_rx_frame(sk, skb, m) == 0) {
                                        sk->protinfo.x25->vr = (sk->protinfo.x25->vr + 1) % modulus;
                                        queued = 1;
                                } else {
-                                       sk->protinfo.x25->condition |= X25_COND_OWN_RX_BUSY;
+                                       /* Should never happen */
+                                       x25_clear_queues(sk);
+                                       x25_write_internal(sk, X25_RESET_REQUEST);
+                                       x25_start_t22timer(sk);
+                                       sk->protinfo.x25->condition = 0x00;
+                                       sk->protinfo.x25->vs        = 0;
+                                       sk->protinfo.x25->vr        = 0;
+                                       sk->protinfo.x25->va        = 0;
+                                       sk->protinfo.x25->vl        = 0;
+                                       sk->protinfo.x25->state     = X25_STATE_4;
+                                       break;
                                }
+                               if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
+                                       sk->protinfo.x25->condition |= X25_COND_OWN_RX_BUSY;
                        }
                        /*
                         *      If the window is full Ack it immediately, else
index 3b05916e6a3fe060dd6bdeaf0440961ecffa1f84..a2b90f9102a7a709c141c101c30b3562c49de7ff 100644 (file)
 #
 # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
 # texts.
+#
+# 100498 Riley Williams (rhw@bigfoot.com) - added ability to display
+# blank lines in help texts: Any line consisting only of a single dot
+# will be displayed blank.
 
 #
 # Make sure we're really running bash.
@@ -103,7 +107,7 @@ ${var}:\\
      then
          echo; echo "  Sorry, no help available for this option yet.";echo
      else
-         (echo; echo "$text") | ${PAGER:-more}
+         (echo; echo "$text") | sed 's/^\.$//' | ${PAGER:-more}
      fi
   else
      echo;
index 6f112d1e5f1cd00db6c74d95ad880e763f56f5ee..f96b75070e0a864b775529e21606e0b58d767d0f 100644 (file)
 # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
 # texts.
 #----------------------------------------------------------------------------
+#
+# 10 Apr 1998 - Added ability to display blank lines in help text: Any line
+#               which only contains a single dot will be displayed blank.
+#               Author: Riley Williams <rhw@bigfoot.com>
+#
+#----------------------------------------------------------------------------
 
 
 #
@@ -295,7 +301,7 @@ ${var}:\\
           echo "There is no help available for this kernel option."
          return 1
      else
-         echo "$text"
+         echo "$text" | sed 's/^\.$//'
      fi
   else
         echo "There is no help available for this kernel option."