diff -u --recursive --new-file v2.1.95/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.95/linux/Documentation/Configure.help Wed Apr 8 19:36:24 1998 +++ linux/Documentation/Configure.help Sat Apr 11 11:19:34 1998 @@ -2398,74 +2398,64 @@ 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 diff -u --recursive --new-file v2.1.95/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.1.95/linux/Documentation/parport.txt Sat Nov 29 10:33:18 1997 +++ linux/Documentation/parport.txt Sun Apr 12 11:39:20 1998 @@ -5,11 +5,15 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v2.1.95/linux/Documentation/sound/ultrasound linux/Documentation/sound/ultrasound --- v2.1.95/linux/Documentation/sound/ultrasound Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/ultrasound Sun Apr 12 11:42:15 1998 @@ -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. diff -u --recursive --new-file v2.1.95/linux/Makefile linux/Makefile --- v2.1.95/linux/Makefile Fri Apr 10 13:03:48 1998 +++ linux/Makefile Fri Apr 10 13:03:35 1998 @@ -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/) diff -u --recursive --new-file v2.1.95/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.1.95/linux/arch/alpha/kernel/bios32.c Fri Apr 10 13:03:48 1998 +++ linux/arch/alpha/kernel/bios32.c Fri Apr 10 13:44:09 1998 @@ -410,7 +410,7 @@ 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)); } diff -u --recursive --new-file v2.1.95/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.1.95/linux/arch/arm/Makefile Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/Makefile Sun Apr 12 11:42:15 1998 @@ -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 @@ # 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 @@ 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 @@ 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 @@ 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 @@ 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_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) arch/arm/drivers/scsi/scsi.a +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 @@ @$(MAKEBOOT) install # My testing targets (that short circuit a few dependencies) -# zImg:; @$(MAKEBOOT) zImage Img:; @$(MAKEBOOT) Image i:; @$(MAKEBOOT) install @@ -191,8 +223,7 @@ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile --- v2.1.95/linux/arch/arm/boot/Makefile Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/boot/Makefile Sun Apr 12 11:42:15 1998 @@ -25,11 +25,8 @@ 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: diff -u --recursive --new-file v2.1.95/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.1.95/linux/arch/arm/boot/compressed/Makefile Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/boot/compressed/Makefile Sun Apr 12 11:42:15 1998 @@ -26,7 +26,7 @@ $(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 -u --recursive --new-file v2.1.95/linux/arch/arm/boot/tools/build.c linux/arch/arm/boot/tools/build.c --- v2.1.95/linux/arch/arm/boot/tools/build.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/boot/tools/build.c Wed Dec 31 16:00:00 1969 @@ -1,70 +0,0 @@ -#include -#include -#include -#include -#include - -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; -} diff -u --recursive --new-file v2.1.95/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.1.95/linux/arch/arm/config.in Wed Apr 8 19:36:24 1998 +++ linux/arch/arm/config.in Sun Apr 12 11:42:15 1998 @@ -7,38 +7,25 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/defconfig linux/arch/arm/defconfig --- v2.1.95/linux/arch/arm/defconfig Wed Apr 8 19:36:24 1998 +++ linux/arch/arm/defconfig Sun Apr 12 11:42:15 1998 @@ -31,6 +31,7 @@ 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 @@ # # 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_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 @@ # 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_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 @@ # # 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.1.95/linux/arch/arm/kernel/Makefile Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/Makefile Sun Apr 12 11:42:15 1998 @@ -19,15 +19,24 @@ 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 @@ $(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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.1.95/linux/arch/arm/kernel/armksyms.c Wed Apr 8 19:36:24 1998 +++ linux/arch/arm/kernel/armksyms.c Sun Apr 12 11:42:15 1998 @@ -12,7 +12,6 @@ #include #include #include -#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, struct user_fp_struct *); @@ -64,7 +63,6 @@ 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 @@ /* 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(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 -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.1.95/linux/arch/arm/kernel/bios32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/bios32.c Sun Apr 12 11:42:15 1998 @@ -0,0 +1,145 @@ +/* + * arch/arm/kernel/bios32.c: PCI functions for ARM + * + * Copyright (C) 1998 Russell King + */ +#include +#include +#include +#include + +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 -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma-a5k.c linux/arch/arm/kernel/dma-a5k.c --- v2.1.95/linux/arch/arm/kernel/dma-a5k.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/dma-a5k.c Sun Apr 12 11:42:15 1998 @@ -0,0 +1,79 @@ +/* + * arch/arm/kernel/dma-a5k.c + * + * Copyright (C) 1998 Russell King + * + * DMA functions specific to A5000 architecture + */ +#include +#include + +#include +#include +#include + +#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 -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c --- v2.1.95/linux/arch/arm/kernel/dma-arc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/dma-arc.c Sun Apr 12 11:42:15 1998 @@ -0,0 +1,115 @@ +/* + * arch/arm/kernel/dma-arc.c + * + * Copyright (C) 1998 Dave Gilbert / Russell King + * + * DMA functions specific to Archimedes architecture + */ +#include +#include + +#include +#include +#include + +#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 -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma-dummy.c linux/arch/arm/kernel/dma-dummy.c --- v2.1.95/linux/arch/arm/kernel/dma-dummy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/dma-dummy.c Sun Apr 12 11:42:15 1998 @@ -0,0 +1,45 @@ +/* + * arch/arm/kernel/dma-dummy.c + * + * Copyright (C) 1998 Russell King + * + * Dummy DMA functions + */ +#include +#include + +#include +#include +#include + +#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 -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c --- v2.1.95/linux/arch/arm/kernel/dma-rpc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/dma-rpc.c Sun Apr 12 11:42:15 1998 @@ -0,0 +1,342 @@ +/* + * arch/arm/kernel/dma-rpc.c + * + * Copyright (C) 1998 Russell King + * + * DMA functions specific to RiscPC architecture + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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); +} diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c --- v2.1.95/linux/arch/arm/kernel/dma.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/dma.c Sun Apr 12 11:42:15 1998 @@ -1,199 +1,189 @@ /* * 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 #include #include #include +#include #include #include #include #include #include -#define KERNEL_ARCH_DMA #include -static unsigned long dma_address[8]; -static unsigned long dma_count[8]; -static char dma_direction[8] = { -1, -1, -1, -1, -1, -1, -1}; - -#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 - -void enable_dma (unsigned int dmanr) -{ - 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; +#include "dma.h" - 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; - - /*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 */ +static dma_t dma_chan[MAX_DMA_CHANNELS]; - restore_flags(flags); - } - 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; +/* Get dma list + * for /proc/dma + */ +int get_dma_list(char *buf) +{ + int i, len = 0; - default: - printk ("enable_dma: dma %d not supported\n", dmanr); + 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; } -void set_dma_mode (unsigned int dmanr, char mode) +/* 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 (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); -} - -void set_dma_addr (unsigned int dmanr, unsigned int addr) -{ - 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); -} - -void set_dma_count (unsigned int dmanr, unsigned int count) -{ - 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); -} - -int get_dma_residue (unsigned int dmanr) -{ - if (dmanr < 8) { - switch (dmanr) { -#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC) - case 2: { - extern int floppy_fiqresidual (void); - return floppy_fiqresidual (); + 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; + } + + 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; } -#endif -#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD) - case 0: { - extern unsigned int fdc1772_bytestogo; - return fdc1772_bytestogo; + + 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; +} + +/* Set DMA address + * + * Copy address to the structure, and set the invalid bit + */ +void set_dma_addr (dmach_t channel, unsigned long physaddr) +{ + 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; +} + +/* 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 (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; +} + +/* Set DMA direction mode + */ +void set_dma_mode (dmach_t channel, dmamode_t mode) +{ + 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; +} + +/* Enable DMA channel + */ +void enable_dma (dmach_t channel) +{ + 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 -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma.h linux/arch/arm/kernel/dma.h --- v2.1.95/linux/arch/arm/kernel/dma.h Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/dma.h Sun Apr 12 11:42:15 1998 @@ -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); diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.1.95/linux/arch/arm/kernel/ecard.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/ecard.c Sun Apr 12 11:42:15 1998 @@ -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 @@ -24,13 +25,14 @@ #include #include #include +#include -#include -#include -#include #include #include #include +#include +#include +#include #ifdef CONFIG_ARCH_ARC #include @@ -59,9 +61,11 @@ 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 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 @@ } } -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 @@ 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 @@ } 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ have_expmask = -1; } #endif + printk("Installed expansion cards:"); /* @@ -578,27 +592,25 @@ 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; } diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.1.95/linux/arch/arm/kernel/entry-armv.S Mon Feb 23 18:12:01 1998 +++ linux/arch/arm/kernel/entry-armv.S Sun Apr 12 11:42:15 1998 @@ -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 /* for CONFIG_ARCH_EBSA110 /* +#include /* for CONFIG_ARCH_EBSA110 */ #include #include @@ -21,15 +21,6 @@ .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 @@ -82,21 +73,24 @@ 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 @@ .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 @@ .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 @@ -267,6 +284,16 @@ .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 *----------------------------------------------------------------------------- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC @@ -400,86 +427,6 @@ 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 @@ #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 @@ 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 @@ 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 @@ 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" diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.1.95/linux/arch/arm/kernel/entry-common.S Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/entry-common.S Sun Apr 12 11:42:15 1998 @@ -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 @@ 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 @@ 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 @@ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S --- v2.1.95/linux/arch/arm/kernel/head-armo.S Mon Feb 23 18:12:01 1998 +++ linux/arch/arm/kernel/head-armo.S Sun Apr 12 11:42:15 1998 @@ -42,7 +42,7 @@ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.1.95/linux/arch/arm/kernel/head-armv.S Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/head-armv.S Sun Apr 12 11:42:15 1998 @@ -16,19 +16,21 @@ .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 @@ 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 @@ .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 @@ .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 @@ .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 @@ 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 @@ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.1.95/linux/arch/arm/kernel/irq.c Wed Apr 8 19:36:24 1998 +++ linux/arch/arm/kernel/irq.c Sun Apr 12 11:42:15 1998 @@ -33,16 +33,10 @@ #include #include #include -#include #include +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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ __initfunc(void init_IRQ(void)) { + extern void init_dma(void); irq_init_irq(); + init_dma(); } diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/leds-ebsa285.c linux/arch/arm/kernel/leds-ebsa285.c --- v2.1.95/linux/arch/arm/kernel/leds-ebsa285.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/leds-ebsa285.c Sun Apr 12 11:42:15 1998 @@ -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 +#include +#include + +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; +} diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.1.95/linux/arch/arm/kernel/process.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/process.c Sun Apr 12 11:42:15 1998 @@ -69,8 +69,10 @@ 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 @@ " 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.1.95/linux/arch/arm/kernel/ptrace.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/ptrace.c Sun Apr 12 11:42:15 1998 @@ -27,18 +27,6 @@ */ #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 @@ 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) { diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/setup-ebsa110.c linux/arch/arm/kernel/setup-ebsa110.c --- v2.1.95/linux/arch/arm/kernel/setup-ebsa110.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/setup-ebsa110.c Sun Apr 12 11:42:15 1998 @@ -26,62 +26,95 @@ #include #include #include +#include -#include -#include #include #include +#include +#include +#include #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; diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.1.95/linux/arch/arm/kernel/setup.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/setup.c Sun Apr 12 11:42:15 1998 @@ -26,15 +26,16 @@ #include #include #include +#include -#include -#include #include +#include #include -#include #include -#include +#include #include +#include +#include struct drive_info_struct { char dummy[32]; } drive_info; struct screen_info screen_info; @@ -153,13 +154,17 @@ #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 @@ #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; diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.1.95/linux/arch/arm/kernel/time.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/time.c Sun Apr 12 11:42:15 1998 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,6 @@ #include #include -#include #include extern int setup_arm_irq(int, struct irqaction *); @@ -143,12 +143,12 @@ 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); } diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c --- v2.1.95/linux/arch/arm/kernel/traps.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/traps.c Sun Apr 12 11:42:15 1998 @@ -59,17 +59,27 @@ 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 @@ 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 @@ } } - dump_instr (instruction_pointer(regs)); + dump_instr(instruction_pointer(regs)); died = 0; if (ret != -1) do_exit (ret); diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.1.95/linux/arch/arm/lib/Makefile Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/lib/Makefile Sun Apr 12 11:42:15 1998 @@ -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 @@ 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 -u --recursive --new-file v2.1.95/linux/arch/arm/lib/extractconstants.pl linux/arch/arm/lib/extractconstants.pl --- v2.1.95/linux/arch/arm/lib/extractconstants.pl Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/lib/extractconstants.pl Sun Apr 12 11:42:15 1998 @@ -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 () { + ($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 () { + /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 -u --recursive --new-file v2.1.95/linux/arch/arm/lib/extractinfo.perl linux/arch/arm/lib/extractinfo.perl --- v2.1.95/linux/arch/arm/lib/extractinfo.perl Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/lib/extractinfo.perl Wed Dec 31 16:00:00 1969 @@ -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 () { - ($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 () { - /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]; -} diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c --- v2.1.95/linux/arch/arm/lib/getconsdata.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/lib/getconsdata.c Sun Apr 12 11:42:15 1998 @@ -1,9 +1,8 @@ /* * linux/arch/arm/lib/getconsdata.c * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995-1998 Russell King */ - #include #include #include @@ -15,17 +14,55 @@ #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; +unsigned long DOM_USERDOMAIN = 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 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 -u --recursive --new-file v2.1.95/linux/arch/arm/lib/getconstants.c linux/arch/arm/lib/getconstants.c --- v2.1.95/linux/arch/arm/lib/getconstants.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/lib/getconstants.c Wed Dec 31 16:00:00 1969 @@ -1,74 +0,0 @@ -/* - * linux/arch/arm/lib/getconstants.c - * - * Copyright (C) 1995, 1996 Russell King - */ - -#include -#include -#include -#include - -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 -u --recursive --new-file v2.1.95/linux/arch/arm/lib/getconstants.h linux/arch/arm/lib/getconstants.h --- v2.1.95/linux/arch/arm/lib/getconstants.h Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/lib/getconstants.h Wed Dec 31 16:00:00 1969 @@ -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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/io-acorn.S linux/arch/arm/lib/io-acorn.S --- v2.1.95/linux/arch/arm/lib/io-acorn.S Mon Feb 23 18:12:02 1998 +++ linux/arch/arm/lib/io-acorn.S Sun Apr 12 11:42:15 1998 @@ -57,7 +57,7 @@ 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 @@ 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 -u --recursive --new-file v2.1.95/linux/arch/arm/lib/io-ebsa285.S linux/arch/arm/lib/io-ebsa285.S --- v2.1.95/linux/arch/arm/lib/io-ebsa285.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/lib/io-ebsa285.S Sun Apr 12 11:42:15 1998 @@ -0,0 +1,109 @@ +#define __ASSEMBLER__ +#include + +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 + diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/ll_char_wr.S linux/arch/arm/lib/ll_char_wr.S --- v2.1.95/linux/arch/arm/lib/ll_char_wr.S Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/lib/ll_char_wr.S Sun Apr 12 11:42:15 1998 @@ -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 @@ @ @ 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 @@ 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 @@ @ 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 @@ 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}) diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S --- v2.1.95/linux/arch/arm/lib/memcpy.S Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/lib/memcpy.S Sun Apr 12 11:42:15 1998 @@ -8,6 +8,12 @@ #include #include +#ifndef ENTRY +#define ENTRY(x...) \ + .globl _##x; \ +_##x: +#endif + .text #define ENTER \ mov ip,sp ;\ @@ -84,6 +90,7 @@ blt 6b ands ip, r1, #3 beq 1b + 8: bic r1, r1, #3 ldr r7, [r1], #4 cmp ip, #2 @@ -105,14 +112,14 @@ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S --- v2.1.95/linux/arch/arm/lib/uaccess.S Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/lib/uaccess.S Sun Apr 12 11:42:15 1998 @@ -13,13 +13,21 @@ #include .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( 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 @@ 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 @@ 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( 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 @@ 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 @@ */ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.1.95/linux/arch/arm/mm/Makefile Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/Makefile Sun Apr 12 11:42:15 1998 @@ -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 @@ ../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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.1.95/linux/arch/arm/mm/fault-armv.c Wed Apr 8 19:36:24 1998 +++ linux/arch/arm/mm/fault-armv.c Sun Apr 12 11:42:15 1998 @@ -27,13 +27,13 @@ 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 @@ } 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 @@ } 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 @@ 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 @@ 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 @@ { 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 @@ 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") diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.1.95/linux/arch/arm/mm/init.c Wed Apr 8 19:36:24 1998 +++ linux/arch/arm/mm/init.c Sun Apr 12 11:42:15 1998 @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include #endif @@ -102,7 +103,7 @@ /* * 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 @@ * 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 -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-a5k.c linux/arch/arm/mm/mm-a5k.c --- v2.1.95/linux/arch/arm/mm/mm-a5k.c Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/mm-a5k.c Wed Dec 31 16:00:00 1969 @@ -1,7 +0,0 @@ -/* - * arch/arm/mm/mm-a5k.c - * - * Extra MM routines for the Archimedes architecture - * - * Copyright (C) 1998 Russell King - */ diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-arc.c linux/arch/arm/mm/mm-arc.c --- v2.1.95/linux/arch/arm/mm/mm-arc.c Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/mm-arc.c Sun Apr 12 11:42:15 1998 @@ -5,3 +5,4 @@ * * Copyright (C) 1998 Russell King */ +#include diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c --- v2.1.95/linux/arch/arm/mm/mm-ebsa110.c Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/mm-ebsa110.c Sun Apr 12 11:42:15 1998 @@ -5,3 +5,22 @@ * * Copyright (C) 1998 Russell King */ + +#include + +/* 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 -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-ebsa285.c linux/arch/arm/mm/mm-ebsa285.c --- v2.1.95/linux/arch/arm/mm/mm-ebsa285.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/mm-ebsa285.c Sun Apr 12 11:42:15 1998 @@ -0,0 +1,97 @@ +/* + * arch/arm/mm/mm-ebsa285.c + * + * Extra MM routines for the EBSA285 architecture + * + * Copyright (C) 1998 Russell King + */ +#include +#include + +#include +#include +#include +#include + +/* 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; +} + diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-nexuspci.c linux/arch/arm/mm/mm-nexuspci.c --- v2.1.95/linux/arch/arm/mm/mm-nexuspci.c Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/mm-nexuspci.c Sun Apr 12 11:42:15 1998 @@ -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 + +/* 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 -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c --- v2.1.95/linux/arch/arm/mm/mm-rpc.c Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/mm-rpc.c Sun Apr 12 11:42:15 1998 @@ -6,7 +6,14 @@ * Copyright (C) 1998 Russell King */ +#include +#include + +#include #include +#include +#include +#include #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 @@ 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; } diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.1.95/linux/arch/arm/mm/proc-arm6,7.S Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/proc-arm6,7.S Sun Apr 12 11:42:15 1998 @@ -72,10 +72,10 @@ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.1.95/linux/arch/arm/mm/proc-sa110.S Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/proc-sa110.S Sun Apr 12 11:42:15 1998 @@ -161,8 +161,6 @@ 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 @@ 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 @@ 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 diff -u --recursive --new-file v2.1.95/linux/arch/arm/vmlinux.lds linux/arch/arm/vmlinux.lds --- v2.1.95/linux/arch/arm/vmlinux.lds Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/vmlinux.lds Sun Apr 12 11:42:15 1998 @@ -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 */ OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm") @@ -34,11 +35,15 @@ _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 */ diff -u --recursive --new-file v2.1.95/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.1.95/linux/drivers/block/ide-disk.c Fri Apr 10 13:03:48 1998 +++ linux/drivers/block/ide-disk.c Fri Apr 10 16:05:01 1998 @@ -112,7 +112,6 @@ 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 @@ 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 @@ 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)) { diff -u --recursive --new-file v2.1.95/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.95/linux/drivers/block/ide.c Fri Apr 10 13:03:48 1998 +++ linux/drivers/block/ide.c Fri Apr 10 16:04:41 1998 @@ -1267,7 +1267,6 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/block/rz1000.c linux/drivers/block/rz1000.c --- v2.1.95/linux/drivers/block/rz1000.c Mon Apr 6 17:40:59 1998 +++ linux/drivers/block/rz1000.c Fri Apr 10 22:08:08 1998 @@ -84,9 +84,9 @@ { 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"); } diff -u --recursive --new-file v2.1.95/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.1.95/linux/drivers/char/cyclades.c Mon Apr 6 17:40:59 1998 +++ linux/drivers/char/cyclades.c Fri Apr 10 15:35:36 1998 @@ -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 @@ * 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 @@ #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 @@ #include #include #include +#ifndef NEW_PCI +#include +#endif #include #include @@ -566,10 +588,9 @@ #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 @@ run_task_queue(&tq_cyclades); } /* do_cyclades_bh */ - static void do_softint(void *private_) { @@ -883,6 +903,11 @@ } 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 @@ 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 @@ * Enable interrupts and see who answers */ cy_irq_triggered = 0; - cli(); + save_flags(flags); cli(); cy_writeb((u_long)base_addr+(CyCAR<= jiffies) { @@ -1050,7 +1076,7 @@ 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 @@ /* delay a bit */ cy_writeb((u_long)base_addr + (CyTDR<= 0x48 ) { + if (info->chip_rev >= CD1400_REV_J ) { /* It is a CD1400 rev. J or later */ cy_writeb((u_long)base_addr + (CyTDR<x_break*500/HZ); @@ -1361,7 +1387,30 @@ info->x_break = 0; } +#ifdef NEW_INTR_FLOW + if (!info->xmit_cnt){ + cy_writeb((u_long)base_addr+(CySRER<xmit_buf == 0){ + cy_writeb((u_long)base_addr+(CySRER<tty->stopped || info->tty->hw_stopped){ + cy_writeb((u_long)base_addr+(CySRER< 0){ +#ifdef NEW_INTR_FLOW + if (!info->xmit_cnt){ + goto txdone; + } +#else if (!info->xmit_cnt){ cy_writeb((u_long)base_addr+(CySRER<tty->stopped || info->tty->hw_stopped){ cy_writeb((u_long)base_addr+(CySRER<xmit_cnt < WAKEUP_CHARS) { cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); } - txend: /* end of service */ cy_writeb((u_long)base_addr+(CyTIR<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<tty || (info->tty->termios->c_cflag & HUPCL)) { cy_writeb((u_long)base_addr+(CyMSVR1<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 @@ 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 @@ * 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 @@ * 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 @@ 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 @@ 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<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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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<= 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 @@ 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 @@ } } } - if(cy_readb(cy_card[card].base_addr+(CyGFRCR<= 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ #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 @@ #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 */ +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 @@ 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 */ -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 @@ return chip_number; } cy_writeb((u_long)base_addr+(CyGCR<= 0x48){ + if (cy_readb(base_addr+(CyGFRCR<= 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 @@ cy_writeb((u_long)base_addr+(CyPPR<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 @@ #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 @@ }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 @@ }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 @@ 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 @@ 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_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 @@ 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 @@ 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_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 @@ 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<= 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]<= 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_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 @@ 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); diff -u --recursive --new-file v2.1.95/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.95/linux/drivers/char/lp.c Wed Apr 8 19:36:26 1998 +++ linux/drivers/char/lp.c Sun Apr 12 11:39:20 1998 @@ -239,23 +239,32 @@ } 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; } diff -u --recursive --new-file v2.1.95/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.1.95/linux/drivers/char/pc_keyb.c Mon Apr 6 17:40:59 1998 +++ linux/drivers/char/pc_keyb.c Fri Apr 10 23:12:04 1998 @@ -145,12 +145,12 @@ */ 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 @@ */ 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); diff -u --recursive --new-file v2.1.95/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c --- v2.1.95/linux/drivers/misc/parport_init.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/misc/parport_init.c Sun Apr 12 11:39:20 1998 @@ -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 @@ __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_proc_register); EXPORT_SYMBOL(parport_proc_unregister); EXPORT_SYMBOL(parport_probe_hook); +EXPORT_SYMBOL(parport_parse_irqs); void inc_parport_count(void) { diff -u --recursive --new-file v2.1.95/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.1.95/linux/drivers/misc/parport_pc.c Fri Apr 10 13:03:48 1998 +++ linux/drivers/misc/parport_pc.c Sun Apr 12 11:39:20 1998 @@ -36,7 +36,6 @@ #include #include -#include #include #include @@ -276,159 +275,6 @@ 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 @@ 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 @@ 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 @@ } #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 @@ } 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 @@ #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) diff -u --recursive --new-file v2.1.95/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c --- v2.1.95/linux/drivers/misc/parport_share.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/misc/parport_share.c Sun Apr 12 11:39:20 1998 @@ -441,3 +441,26 @@ 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++; + } +} diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.1.95/linux/drivers/scsi/53c7,8xx.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/53c7,8xx.c Sat Apr 11 11:13:25 1998 @@ -253,6 +253,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -290,6 +291,7 @@ 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 @@ 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 { @@ -4388,6 +4390,22 @@ hostdata->dstat |= DSTAT_DFE; } } +} + +/* + * 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); } /* diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c --- v2.1.95/linux/drivers/scsi/53c7xx.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/53c7xx.c Sat Apr 11 11:13:25 1998 @@ -252,6 +252,7 @@ #include #include #include +#include #ifdef CONFIG_AMIGA #include @@ -313,7 +314,8 @@ 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 @@ */ #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 @@ 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 @@ } #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 @@ * 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 */ diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c --- v2.1.95/linux/drivers/scsi/AM53C974.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/AM53C974.c Sat Apr 11 11:13:25 1998 @@ -6,6 +6,7 @@ #include #include #include +#incldue #include #include @@ -361,6 +362,7 @@ 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 @@ (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; } @@ -974,6 +976,24 @@ } /* for instance */ } while (!done); 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); } /************************************************************************ diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.95/linux/drivers/scsi/Config.in Tue Mar 10 10:03:32 1998 +++ linux/drivers/scsi/Config.in Sat Apr 11 11:19:34 1998 @@ -24,14 +24,12 @@ 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c --- v2.1.95/linux/drivers/scsi/NCR5380.c Wed Apr 1 20:11:52 1998 +++ linux/drivers/scsi/NCR5380.c Sat Apr 11 11:13:25 1998 @@ -1279,6 +1279,9 @@ } #ifndef DONT_USE_INTR +#include +#include + /* * Function : void NCR5380_intr (int irq) * @@ -1390,6 +1393,16 @@ } /* 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/NCR5380.h linux/drivers/scsi/NCR5380.h --- v2.1.95/linux/drivers/scsi/NCR5380.h Wed Apr 1 20:11:52 1998 +++ linux/drivers/scsi/NCR5380.h Sat Apr 11 11:13:25 1998 @@ -286,6 +286,7 @@ 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); diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c --- v2.1.95/linux/drivers/scsi/NCR53c406a.c Wed Apr 1 20:11:52 1998 +++ linux/drivers/scsi/NCR53c406a.c Sat Apr 11 11:13:25 1998 @@ -52,6 +52,7 @@ #include #include +#include #include "scsi.h" #include "hosts.h" #include "sd.h" @@ -171,6 +172,7 @@ /* 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 @@ 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 @@ 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;) diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx --- v2.1.95/linux/drivers/scsi/README.aic7xxx Thu Jul 31 12:37:17 1997 +++ linux/drivers/scsi/README.aic7xxx Sat Apr 11 11:19:34 1998 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c --- v2.1.95/linux/drivers/scsi/a2091.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/scsi/a2091.c Sat Apr 11 11:13:25 1998 @@ -12,6 +12,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -35,7 +36,6 @@ { 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 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 @@ 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); diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c --- v2.1.95/linux/drivers/scsi/a3000.c Tue May 13 22:41:13 1997 +++ linux/drivers/scsi/a3000.c Sat Apr 11 11:13:25 1998 @@ -11,6 +11,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -35,7 +36,6 @@ if (!(status & ISTR_INT_P)) return; - if (status & ISTR_INTS) { /* disable PORTS interrupt */ @@ -48,6 +48,14 @@ } } +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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.1.95/linux/drivers/scsi/advansys.c Thu Feb 12 20:56:10 1998 +++ linux/drivers/scsi/advansys.c Sat Apr 11 11:13:25 1998 @@ -668,6 +668,9 @@ #include #include #endif /* version >= v1.3.0 */ +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95) +#include +#endif #include "scsi.h" #include "hosts.h" #include "sd.h" @@ -4880,10 +4883,14 @@ #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( @@ -6204,6 +6211,18 @@ ASC_DBG(1, "advansys_interrupt: end\n"); 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) /* diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.1.95/linux/drivers/scsi/aha1542.c Sun Jan 4 10:55:09 1998 +++ linux/drivers/scsi/aha1542.c Sat Apr 11 11:13:25 1998 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include "scsi.h" @@ -129,6 +130,8 @@ 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 @@ 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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg --- v2.1.95/linux/drivers/scsi/aic7xxx/aic7xxx.reg Tue Dec 2 20:41:21 1997 +++ linux/drivers/scsi/aic7xxx/aic7xxx.reg Sat Apr 11 11:19:34 1998 @@ -10,10 +10,7 @@ * 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 @@ -393,6 +390,27 @@ } /* + * 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 * addresses 0x00-0x1e are gated to the appropriate channel based on this @@ -622,26 +640,19 @@ 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 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 CLRINT { address 0x092 access_mode WO + bit CLRPARERR 0x10 /* PCI only */ bit CLRBRKADRINT 0x08 bit CLRSCSIINT 0x04 bit CLRCMDINT 0x02 @@ -771,8 +786,6 @@ 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 @@ 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 @@ TARG_SCRATCH { size 16 } + /* + * Bit vector of targets that have ULTRA enabled. + */ ULTRA_ENB { size 2 } @@ -934,14 +951,11 @@ 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 @@ 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,34 +987,15 @@ 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. */ LASTPHASE { @@ -1040,23 +1012,12 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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_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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq --- v2.1.95/linux/drivers/scsi/aic7xxx/aic7xxx.seq Wed Aug 13 09:50:32 1997 +++ linux/drivers/scsi/aic7xxx/aic7xxx.seq Sat Apr 11 11:19:34 1998 @@ -10,10 +10,7 @@ * 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 -#include +#include "aic7xxx.reg" +#include "scsi_message.h" /* * A few words on the waiting SCB list: @@ -59,18 +56,21 @@ * 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 @@ * 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 @@ */ .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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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: -/* - * Set up automatic PIO transfer from MSG_OUT. Bit 3 in - * SXFRCTL0 (SPIOEN) is already on. - */ - mvi SINDEX,MSG_OUT; - mov DINDEX,MSG_LEN; - -/* - * 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. + 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 */ +/* + * 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. */ -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_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; +/* + * Interrupt the driver, and allow it to send a message + * if it asks. + */ +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_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 @@ /* * 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 @@ * 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 @@ */ 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 @@ * 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_disconnect: or SCB_CONTROL,DISCONNECTED; -.if ( SCB_PAGING ) call add_scb_to_disc_list; -.endif jmp await_busfree; /* @@ -764,24 +796,30 @@ * 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 @@ 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 @@ * 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_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 @@ * 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; + +/* + * 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; + /* - * 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. + * 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 @@ 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 @@ 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 @@ 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 @@ dequeue_free_scb: mov SCBPTR, FREE_SCBH; mov FREE_SCBH, SCB_NEXT ret; +.endif add_scb_to_disc_list: /* @@ -1153,4 +1226,3 @@ mov SCBPTR,SCB_NEXT; mov SCB_PREV,DISCONNECTED_SCBH; mov SCBPTR,DISCONNECTED_SCBH ret; -.endif diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx/scsi_message.h linux/drivers/scsi/aic7xxx/scsi_message.h --- v2.1.95/linux/drivers/scsi/aic7xxx/scsi_message.h Thu Jul 31 12:37:17 1997 +++ linux/drivers/scsi/aic7xxx/scsi_message.h Sat Apr 11 11:19:34 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx/sequencer.h linux/drivers/scsi/aic7xxx/sequencer.h --- v2.1.95/linux/drivers/scsi/aic7xxx/sequencer.h Thu Jul 31 12:37:17 1997 +++ linux/drivers/scsi/aic7xxx/sequencer.h Sat Apr 11 11:19:34 1998 @@ -11,10 +11,7 @@ * 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 @@ -36,49 +33,46 @@ * 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.1.95/linux/drivers/scsi/aic7xxx.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/aic7xxx.c Sat Apr 11 11:19:34 1998 @@ -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. * @@ -96,6 +96,73 @@ * $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $ *-M*************************************************************************/ +/*+M************************************************************************** + * + * Further driver modifications made by Doug Ledford + * + * 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 #endif @@ -103,6 +170,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +180,8 @@ #include #include #include +#include +#include #include "sd.h" #include "scsi.h" #include "hosts.h" @@ -121,10 +191,11 @@ #include "aic7xxx/scsi_message.h" #include "aic7xxx_reg.h" #include "aic7xxx_seq.h" + #include -#include /* for kmalloc() */ +#include /* for kmalloc() */ -#include /* for CONFIG_PCI */ +#include /* for CONFIG_PCI */ /* * To generate the correct addresses for the controller to issue @@ -138,13 +209,13 @@ 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 @@ # 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 - */ - -/* Uncomment this for tagged queueing. */ -#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING -#define AIC7XXX_TAGGED_QUEUEING + * 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 + */ + +#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 +#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 +# include +# 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 @@ #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 @@ #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 @@ * * 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 @@ * 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 @@ #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 @@ /* * 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 @@ * 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 @@ /* * 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 @@ /*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 @@ { 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 @@ 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 @@ 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 @@ * < 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 @@ 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 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 @@ * 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 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 @@ { int i, n; char *p; + char *end; static struct { const char *name; @@ -999,25 +1202,112 @@ { "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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } 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 @@ 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 @@ 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 @@ static void aic7xxx_delay(int seconds) { - int i; + unsigned int i; /* * Call udelay() for 1 millisecond inside a loop for @@ -1278,139 +1610,65 @@ /*+F************************************************************************* * Function: - * rcs_version - * - * Description: - * Return a string containing just the RCS version number from either - * an Id or Revision RCS clause. - *-F*************************************************************************/ -const char * -rcs_version(const char *version_info) -{ - 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'; - } - } - - return buf; -} - -/*+F************************************************************************* - * Function: * aic7xxx_info * * Description: * Return a string describing the driver. *-F*************************************************************************/ const char * -aic7xxx_info(struct Scsi_Host *notused) +aic7xxx_info(struct Scsi_Host *dooh) { - static char buffer[128]; + static char buffer[256]; + char *bp; + struct aic7xxx_host *p; - 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 + 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 buffer; + return(bp); } + /*+F************************************************************************* * Function: - * aic7xxx_length + * aic7xxx_scsirate * * 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. + * Look up the valid period to SCSIRATE conversion in our table *-F*************************************************************************/ -static unsigned -aic7xxx_length(Scsi_Cmnd *cmd, int sg_last) +static unsigned char +aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate, + unsigned char *period, unsigned char *offset, int target, int channel, + int set) { - int i, segments; - unsigned length; - struct scatterlist *sg; + int i = num_aic7xxx_syncrates; + unsigned char response_period; + unsigned char tindex; + unsigned short target_mask; + unsigned char lun; - segments = cmd->use_sg - sg_last; - sg = (struct scatterlist *) cmd->request_buffer; + tindex = target | (channel << 3); + target_mask = 0x01 << tindex; + lun = aic_inb(p, SCB_TCL) & 0x07; - if (cmd->use_sg) + response_period = *period; + + /* + * If the offset is 0, then the device is requesting asynchronous + * transfers. + */ + if ((*period != 0) && (*offset != 0)) { - 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; - - /* - * If the offset is 0, then the device is requesting asynchronous - * transfers. - */ - if ((*period <= aic7xxx_syncrates[i - 1].period) && *offset != 0) - { - for (i = 0; i < num_aic7xxx_syncrates; i++) + for (i = 0; i < num_aic7xxx_syncrates; i++) { if (*period <= aic7xxx_syncrates[i].period) { @@ -1418,7 +1676,7 @@ * 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 @@ *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 @@ *scsirate = 0; *period = 0; *offset = 0; - if (aic7xxx_verbose) - { - printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n", - p->host_no, target, channel); + response_period = 0; + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) && + (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) ) + { + 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 @@ * *-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 @@ * *-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 @@ * 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 @@ * *-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 @@ * *-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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ * 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 @@ * 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 @@ 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 @@ * 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) - { - 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++; + + /* + * 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) + { + 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } #endif /* AIC7XXX_PROC_STATS */ + + aic7xxx_free_scb(p, scb); + aic7xxx_queue_cmd_complete(p, cmd); + } /*+F************************************************************************* @@ -2039,20 +2398,25 @@ 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 @@ /* * 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 @@ /* * 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 @@ * 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)) ) + { + 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) ) + { + del_timer(&p->dev_timer[i]); + } + p->dev_timer[i].expires = jiffies + (3 * HZ); + add_timer(&p->dev_timer[i]); + } + for(j=0; jscb_data->scb_array[busy_scbid]; - - next_scbid = le32_to_cpu(busy_scb->hscb->data_count) >> 24; - - if (next_scbid == SCB_LIST_NULL) + 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 ) + { + 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)) { - busy_scbid = aic7xxx_find_scb(p, busy_scb); - - if (busy_scbid != SCB_LIST_NULL) + scbq_remove(&p->delayed_scbs[i], prev_scbp); + if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) ) { - outb(busy_scbid, p->base + SCBPTR); - next_scbid = inb(p->base + SCB_LINKED_NEXT); - } - } + p->dev_active_cmds[i]++; + 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 " + "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_match_scb(busy_scb, target, channel, lun, tag)) - { - aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE); - } + 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; - if (next_scbid != SCB_LIST_NULL) + 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) ) { - next_scb = p->scb_data->scb_array[next_scbid]; - if (aic7xxx_match_scb(next_scb, target, channel, lun, tag)) - { - continue; - } - /* Requeue for later processing */ - scbq_insert_head(&p->waiting_scbs, next_scb); - next_scb->flags |= SCB_WAITINGQ; - } + 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 @@ { 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); } - scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(scbp, target, channel, lun, tag)) + else { - next = aic7xxx_rem_scb_from_disc_list(p, next); + 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); + } + } + } + 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 ) + { + 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 @@ * 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; - - found++; - - if ((scbp->flags & SCB_WAITINGQ) != 0) - { - scbq_remove(&p->waiting_scbs, scbp); - scbp->flags &= ~SCB_WAITINGQ; - } + scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; + scbp->flags &= ~(SCB_ACTIVE | 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 @@ 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 @@ 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 @@ * 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; - 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 (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" ); - if (channel == 'B') + + if (channel == 1) { p->needsdtr |= (p->needsdtr_copy & 0xFF00); p->sdtr_pending &= 0x00FF; @@ -2508,7 +3080,7 @@ } 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 @@ */ 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 @@ 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; idev_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 @@ * 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 @@ * 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 @@ { struct aic7xxx_hwscb *hscb; Scsi_Cmnd *cmd; - int actual; + int actual, i; cmd = scb->cmd; hscb = scb->hscb; @@ -2734,18 +3353,22 @@ * 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 @@ * 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 @@ { 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 @@ { /* * 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; - - 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]; + p->msg_type = MSG_TYPE_INITIATOR_MSGIN; + p->msg_len = 0; + p->msg_index = 0; - 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; + /* + * 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); - 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); + 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); + } } - udelay(1000); /* A small pause (1ms) to help the drive */ - break; + 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; + unsigned char scb_index; - scb_index = inb(p->base + SCB_TAG); - scb = p->scb_data->scb_array[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. + */ - /* - * 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)); - } + 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)); - } - else if (scb->flags & SCB_MSGOUT_WDTR) - { - aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT); + 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, (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) + period = p->syncinfo[scratch_offset].period; + offset = p->syncinfo[scratch_offset].offset; + if ( (p->needsdtr_copy & target_mask) == 0) { - sxfr |= 0x100; + period = 0; + offset = 0; } - for (i = 0; i < num_aic7xxx_syncrates; i++) - { - if (sxfr == aic7xxx_syncrates[i].rate) - break; - } - 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; -/* #if AIC7XXX_NOT_YET */ + case TRACEPOINT2: + { + printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel, + target, lun); + } + break; + +#if AIC7XXX_NOT_YET /* XXX Fill these in later */ case MSG_BUFFER_BUSY: printk("aic7xxx: Message buffer busy.\n"); @@ -3477,33 +4119,376 @@ 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 * * Description: @@ -3516,8 +4501,8 @@ 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 @@ 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 @@ * 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 @@ { 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)); - } - outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1); - outb(CLRBUSFREE, p->base + CLRSINT1); - outb(CLRSCSIINT, p->base + CLRINT); + 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; + } + 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 @@ 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 @@ } 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 @@ 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 @@ * 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 @@ */ 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,19 +4800,87 @@ * 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_pci_intr + * + * Description: + * 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_pci_intr(struct aic7xxx_host *p) +{ + 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 @@ -3801,169 +4891,157 @@ static void aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) { - struct aic7xxx_host *p = (struct aic7xxx_host *) dev_id; + struct aic7xxx_host *p; unsigned char intstat; - unsigned long flags; + unsigned long cpu_flags = 0; - /* - * 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 */ - return; + p = (struct aic7xxx_host *)dev_id; /* - * Keep track of interrupts for /proc/scsi + * 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. */ - p->isr_count++; - - if (!(p->flags & A_SCANNED) && (p->isr_count == 1)) + if (p == NULL) { - /* - * We must only have one card at this IRQ and it must have been - * added to the board data before the spurious interrupt occurred. - * 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) + 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)) { - /* Try clearing all interrupts. */ - outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT); + 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; } - if (p->flags & IN_ISR) + /* + * 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++; + p->flags |= AHC_IN_ISR; + if (!(p->flags & AHC_A_SCANNED) && (p->isr_count == 1)) { - printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n", - p->host_no); + /* + * We must only have one card at this IRQ and it must have been + * added to the board data before the spurious interrupt occurred. + * It is sufficient that we check isr_count and not the spurious + * interrupt count. + */ + if (intstat) + { + /* Try clearing all interrupts. */ + aic_outb(p, CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, CLRINT); + unpause_sequencer(p, TRUE); + } + 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 @@ 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_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 @@ 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_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 @@ { 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 @@ * 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 @@ 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 @@ { 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: " @@ -4197,9 +5320,8 @@ } } - return (AIC_NONE); + return (AHC_NONE); } -#endif /* __sparc_v9__ or __powerpc__ */ /*+F************************************************************************* * Function: @@ -4236,11 +5358,11 @@ 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 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ /* * 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 @@ * 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 @@ static inline void release_seeprom(struct aic7xxx_host *p) { - outb(0, p->base + SEECTL); + aic_outb(p, 0, SEECTL); } /*+F************************************************************************* @@ -4444,8 +5566,8 @@ * 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 @@ 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 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ /* * 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 @@ } printk("\n"); #endif - if (checksum != scarray[len - 1]) { return (0); @@ -4594,13 +5715,13 @@ 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 @@ 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 @@ 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); - - /* - * 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); + aic_outb(p, SEECS | SEEMS, SEECTL); - /* - * 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 (max_targ > 8) + if ( (p->type & AHC_AIC7860) == AHC_AIC7860 ) { - internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1; + aic785x_cable_detect(p, &internal50_present, &external_present, + &eprom_present); } - - /* - * 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) - { - 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); + else + { + aic787x_cable_detect(p, &internal50_present, &internal68_present, + &external_present, &eprom_present); } + 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"); + 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ * 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 @@ * 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 @@ */ 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; - - 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 @@ 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->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; + 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; } - - /* - * Request an IRQ for the board. Only allow sharing IRQs with PCI devices. - */ -#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) + if (p->type & AHC_TWIN) { - printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n", - p->irq); - return (0); + 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); } - - /* - * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels - */ - if (p->bus_type == AIC_TWIN) + else + { + 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); + + /* + * Detect SCB parameters and initialize the SCB array. + */ + 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 "(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->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 @@ 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 @@ /* * 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 @@ */ 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 @@ * 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 @@ 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 @@ /* 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); - } - - /* - * 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); + 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); + + /* 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,24 +6460,24 @@ */ 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 * command is sent to us by the high-level SCSI code. */ 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 @@ * 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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ * 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 @@ { /* 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 @@ * 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 @@ 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 @@ * 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; - - default: - printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ " - "level %d, ignoring.\n", irq); - irq = 0; - aic7xxx_free(p); - break; - } + temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL); - 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; - } - break; + 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 */ + } } - - 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)) + case AHC_284: + load_seeprom(temp_p, &sxfrctl1); + temp_p->board_name_index = 4; + switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL ) { - /* - * We successfully found a board and registered it. - */ - found = found + 1; - } - else - { - /* - * 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)); + /* + * 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 + + 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. - */ - 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; + /* + * 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 - 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(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,115 +7541,315 @@ */ 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; + current_p = list_p; + while(current_p->next != NULL) + current_p = current_p->next; + current_p->next = temp_p; + } + 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 + /* + * 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) + */ -#ifdef AIC7XXX_USE_EXT_SCBRAM + { + struct aic7xxx_host *vlb_enab, *vlb_disab, *pci; + struct aic7xxx_host *prev_p; + struct aic7xxx_host *p; + unsigned char left; + + prev_p = vlb_enab = vlb_disab = pci = NULL; + + 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; + } + } /* - * 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. + * 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 ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883)) + 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 (shared_scb_data == NULL) + if (temp_p->flags & AHC_CHNLB) { - shared_scb_data = p->scb_data; + 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; + } } } -#endif + 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; + } } - - index++; - } /* Found an Adaptec PCI device. */ + 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); + } } -#endif CONFIG_PCI - return (found); } - /*+F************************************************************************* * Function: * aic7xxx_buildscb @@ -6191,57 +7871,61 @@ * 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; -#ifdef AIC7XXX_TAGGED_QUEUEING - if (cmd->device->tagged_queue) + if (p->tagenable & mask) { cmd->tag = hscb->tag; - p->device_status[TARGET_INDEX(cmd)].commands_sent++; - if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75) + 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 { - hscb->control |= MSG_ORDERED_Q_TAG; - p->device_status[TARGET_INDEX(cmd)].commands_sent = 0; + 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; } } -#endif /* Tagged queueing */ } - - if ((p->needwdtr & mask) && !(p->wdtr_pending & mask)) + if ( (p->needwdtr & mask) && + !(p->wdtr_pending & mask) && + !(scb->tag_action)) { 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 + 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)) + 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; -#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); + ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07); /* * The interpretation of request_buffer and request_bufflen @@ -6253,8 +7937,6 @@ /* * 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)); @@ -6272,46 +7954,42 @@ 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 @@ 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_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 @@ 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 @@ { 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); + lastphase = aic_inb(p, LASTPHASE); + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) { - 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) - { - 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,154 +8166,155 @@ * 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) - { - /* - * 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); - } - 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); - } + 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); } - else - { - unsigned char hscb_index, linked_next; - int disconnected; - - disconnected = FALSE; - hscb_index = aic7xxx_find_scb(p, scb); - if (hscb_index == SCB_LIST_NULL) + if (scb->hscb->tag == aic_inb(p, SCB_TAG)) + { + if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) ) { - disconnected = TRUE; - linked_next = (le32_to_cpu(scb->hscb->data_count) >> 24) & 0xFF; + /* 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 { - 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) - { + /* 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); + } + } + } /* 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) + { + 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_control = inb(p->base + SCB_CONTROL); - outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + 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; + + 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; idev_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 * * Description: @@ -6708,86 +8325,307 @@ { 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); + } + 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); } -#endif - if (p->flags & IN_TIMEOUT) + 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 ( 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) - { - 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; - } + 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 ) + { + 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 @@ { 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; + + + if ( cmd == NULL ) + { + printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd " + "pointer, failing.\n"); + return(SCSI_RESET_SNOOZE); + } 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) + /* + * 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); + + DRIVER_LOCK + + pause_sequencer(p); + while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) { - 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); + aic7xxx_isr(p->irq, p, (void *)NULL ); + pause_sequencer(p); } - else + + if (scb == NULL) { - printk("aic7xxx: Reset called with no SCB for cmd.\n"); + 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 + { + action = BUS_RESET; + } } -#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. - */ - save_flags(processor_flags); - cli(); - - if (scb->cmd != cmd) - scb = NULL; - - if (p->flags & IN_TIMEOUT) + else if (scb->cmd != cmd) { - /* - * We've already started a recovery operation. - */ - if ((scb->flags & SCB_RECOVERY_SCB) == 0) + 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 ) + { + if (cmd_next == cmd) + { + 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 { - restore_flags(processor_flags); - return (SCSI_RESET_PENDING); + 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; } } else { - 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, 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) ) { - /* - * 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->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 "SCB on qoutfifo, returning.\n", p->host_no, + CTL_OF_SCB(scb)); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_NOT_RUNNING); + } + if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) + { + action = HOST_RESET; + } + else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET ) + { + action = BUS_RESET; + } + else + { + action = DEVICE_RESET; } } - if (result == -1) + if ( (action & DEVICE_RESET) && + (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) ) { - /* - * 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_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) { - 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; - } + 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)); } - - if (result == -1) + 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) { - /* - * 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)) + 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; - p->flags &= ~IN_TIMEOUT; - } + 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; + } + 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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h --- v2.1.95/linux/drivers/scsi/aic7xxx.h Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/aic7xxx.h Sat Apr 11 11:24:43 1998 @@ -23,40 +23,88 @@ #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 +#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 *); diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c --- v2.1.95/linux/drivers/scsi/aic7xxx_proc.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/aic7xxx_proc.c Sat Apr 11 11:19:34 1998 @@ -53,9 +53,6 @@ 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 @@ 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 @@ return (length); } } + HBAptr = p->host; if (inout == TRUE) /* Has data been written to the file? */ @@ -124,16 +123,20 @@ * 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 @@ 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 @@ 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 @@ { 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 @@ { 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); diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h --- v2.1.95/linux/drivers/scsi/aic7xxx_reg.h Tue Dec 2 20:41:21 1997 +++ linux/drivers/scsi/aic7xxx_reg.h Sat Apr 11 11:19:34 1998 @@ -30,13 +30,6 @@ #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 @@ -47,6 +40,13 @@ #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 @@ -147,6 +147,16 @@ #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 @@ -181,11 +191,9 @@ #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 @@ -196,36 +204,21 @@ #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 @@ -238,40 +231,46 @@ #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 @@ -315,16 +314,16 @@ #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 @@ -356,13 +355,13 @@ #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 @@ -374,18 +373,22 @@ #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 @@ -410,17 +413,15 @@ #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 @@ -440,8 +441,6 @@ #define SCB_DATACNT 0xb0 -#define SCB_LINKED_NEXT 0xb3 - #define SCB_CMDPTR 0xb4 #define SCB_CMDLEN 0xb8 @@ -466,10 +465,24 @@ #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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx_seq.h linux/drivers/scsi/aic7xxx_seq.h --- v2.1.95/linux/drivers/scsi/aic7xxx_seq.h Tue Dec 2 20:41:21 1997 +++ linux/drivers/scsi/aic7xxx_seq.h Sat Apr 11 11:19:34 1998 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 } }; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/dtc.c linux/drivers/scsi/dtc.c --- v2.1.95/linux/drivers/scsi/dtc.c Wed Apr 23 19:01:22 1997 +++ linux/drivers/scsi/dtc.c Sat Apr 11 11:13:25 1998 @@ -263,7 +263,7 @@ /* 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/dtc.h linux/drivers/scsi/dtc.h --- v2.1.95/linux/drivers/scsi/dtc.h Sun Dec 21 17:04:48 1997 +++ linux/drivers/scsi/dtc.h Sat Apr 11 11:13:25 1998 @@ -112,6 +112,7 @@ #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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.1.95/linux/drivers/scsi/eata.c Fri Apr 10 13:03:49 1998 +++ linux/drivers/scsi/eata.c Sat Apr 11 11:16:31 1998 @@ -316,6 +316,7 @@ #include #include #include +#include #include #include #include "scsi.h" @@ -599,7 +600,7 @@ #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 @@ } /* 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 @@ 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) diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v2.1.95/linux/drivers/scsi/eata_dma.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/eata_dma.c Sat Apr 11 11:13:25 1998 @@ -81,6 +81,7 @@ #include #ifdef __mips__ #include +#include #endif #include #include "scsi.h" @@ -240,6 +241,16 @@ } } +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 @@ 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); } } diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c --- v2.1.95/linux/drivers/scsi/eata_pio.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/eata_pio.c Sat Apr 11 11:13:25 1998 @@ -56,6 +56,8 @@ #include #include /* for CONFIG_PCI */ +#include +#include struct proc_dir_entry proc_scsi_eata_pio = { PROC_SCSI_EATA_PIO, 9, "eata_pio", @@ -109,6 +111,17 @@ } } +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 @@ } 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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v2.1.95/linux/drivers/scsi/esp.c Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/esp.c Sat Apr 11 11:13:25 1998 @@ -37,6 +37,7 @@ #include #include #include +#include #define DEBUG_ESP /* #define DEBUG_ESP_HME */ @@ -172,6 +173,7 @@ /* 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 @@ 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 @@ 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"); @@ -4036,6 +4038,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__ diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.1.95/linux/drivers/scsi/fdomain.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/fdomain.c Sat Apr 11 11:13:25 1998 @@ -264,6 +264,7 @@ #include "hosts.h" #include "fdomain.h" #include +#include #include #include #include @@ -948,7 +949,7 @@ /* 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) { @@ -1608,6 +1609,15 @@ in_interrupt_flag = 0; #endif 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 *)) diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c --- v2.1.95/linux/drivers/scsi/g_NCR5380.c Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/g_NCR5380.c Sat Apr 11 11:13:25 1998 @@ -251,7 +251,7 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/g_NCR5380.h linux/drivers/scsi/g_NCR5380.h --- v2.1.95/linux/drivers/scsi/g_NCR5380.h Mon Jan 5 00:23:39 1998 +++ linux/drivers/scsi/g_NCR5380.h Sat Apr 11 11:13:25 1998 @@ -155,6 +155,7 @@ 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c --- v2.1.95/linux/drivers/scsi/gdth.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/gdth.c Sat Apr 11 11:13:25 1998 @@ -102,6 +102,7 @@ #include #include #include +#include #if LINUX_VERSION_CODE >= 0x010300 #include @@ -116,6 +117,7 @@ #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 @@ /* 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 @@ 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 @@ 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 @@ 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c --- v2.1.95/linux/drivers/scsi/gvp11.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/scsi/gvp11.c Sat Apr 11 11:13:25 1998 @@ -12,6 +12,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -51,6 +52,15 @@ } } +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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.1.95/linux/drivers/scsi/hosts.h Wed Apr 1 20:11:52 1998 +++ linux/drivers/scsi/hosts.h Fri Apr 10 15:57:01 1998 @@ -108,6 +108,11 @@ 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 * data buffer pointer, and data buffer length pointer. The return @@ -263,6 +268,11 @@ * to use the new error handling code. */ unsigned use_new_eh_code:1; + + /* + * True for emulated SCSI host adapters (e.g. ATAPI) + */ + unsigned emulated:1; } Scsi_Host_Template; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c --- v2.1.95/linux/drivers/scsi/ibmmca.c Wed Feb 4 11:36:00 1998 +++ linux/drivers/scsi/ibmmca.c Sat Apr 11 11:13:25 1998 @@ -298,6 +298,7 @@ #include #include #include +#include #include #include "sd.h" #include "scsi.h" @@ -834,6 +835,7 @@ /*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 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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.1.95/linux/drivers/scsi/ide-scsi.c Sat Jan 10 10:42:55 1998 +++ linux/drivers/scsi/ide-scsi.c Fri Apr 10 15:22:21 1998 @@ -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 */ @@ -20,9 +20,12 @@ * 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 #include @@ -37,6 +40,7 @@ #include #include +#include #include "../block/ide.h" @@ -44,6 +48,7 @@ #include "hosts.h" #include "sd.h" #include "ide-scsi.h" +#include #define IDESCSI_DEBUG_LOG 0 @@ -68,12 +73,25 @@ */ #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 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 @@ 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 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 @@ } 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 @@ 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 @@ } } 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 @@ 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 @@ 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 @@ 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 @@ 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,7 +737,19 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ide-scsi.h linux/drivers/scsi/ide-scsi.h --- v2.1.95/linux/drivers/scsi/ide-scsi.h Sun Dec 21 17:09:12 1997 +++ linux/drivers/scsi/ide-scsi.h Fri Apr 10 15:22:21 1998 @@ -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 @@ 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 @@ 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 */ diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c --- v2.1.95/linux/drivers/scsi/in2000.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/in2000.c Sat Apr 11 11:13:25 1998 @@ -117,6 +117,7 @@ #include #include +#include #include "scsi.h" #include "sd.h" @@ -1638,7 +1639,14 @@ } +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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/mac53c94.c linux/drivers/scsi/mac53c94.c --- v2.1.95/linux/drivers/scsi/mac53c94.c Sat Aug 16 09:53:08 1997 +++ linux/drivers/scsi/mac53c94.c Sat Apr 11 11:13:25 1998 @@ -19,6 +19,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -57,6 +58,7 @@ 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 @@ *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); } @@ -268,6 +270,16 @@ if (cmd->use_sg > 0 || cmd->request_bufflen != 0) 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c --- v2.1.95/linux/drivers/scsi/mesh.c Sat Sep 6 10:04:15 1997 +++ linux/drivers/scsi/mesh.c Sat Apr 11 11:13:25 1998 @@ -23,6 +23,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -138,6 +139,7 @@ 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 @@ *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); } @@ -973,6 +975,16 @@ } ms->phase = idle; 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.1.95/linux/drivers/scsi/ncr53c8xx.c Fri Apr 10 13:03:49 1998 +++ linux/drivers/scsi/ncr53c8xx.c Sat Apr 11 11:13:25 1998 @@ -112,6 +112,7 @@ #include #include #include +#include #include #include #include @@ -557,6 +558,7 @@ #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 @@ 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 @@ -9798,6 +9800,14 @@ ncr_exception((ncb_p) dev_id); 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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c --- v2.1.95/linux/drivers/scsi/pas16.c Sun Jan 4 10:55:09 1998 +++ linux/drivers/scsi/pas16.c Sat Apr 11 11:13:25 1998 @@ -426,7 +426,7 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/pas16.h linux/drivers/scsi/pas16.h --- v2.1.95/linux/drivers/scsi/pas16.h Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/pas16.h Sat Apr 11 11:13:25 1998 @@ -186,6 +186,7 @@ #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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c --- v2.1.95/linux/drivers/scsi/pci2000.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/pci2000.c Sat Apr 11 11:13:25 1998 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "scsi.h" @@ -466,6 +467,14 @@ 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 @@ } 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.1.95/linux/drivers/scsi/pci2220i.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/pci2220i.c Sat Apr 11 11:13:25 1998 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include "scsi.h" @@ -431,6 +432,14 @@ 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 @@ } 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/psi240i.c linux/drivers/scsi/psi240i.c --- v2.1.95/linux/drivers/scsi/psi240i.c Wed Nov 5 13:09:56 1997 +++ linux/drivers/scsi/psi240i.c Sat Apr 11 11:13:25 1998 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include "scsi.h" @@ -370,6 +371,14 @@ 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 @@ 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); diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c --- v2.1.95/linux/drivers/scsi/qlogicfas.c Sun Feb 2 05:34:32 1997 +++ linux/drivers/scsi/qlogicfas.c Sat Apr 11 11:13:25 1998 @@ -125,6 +125,7 @@ #include #include #include +#include #include "sd.h" #include "hosts.h" #include "qlogicfas.h" @@ -446,7 +447,7 @@ #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 @@ /* 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 @@ 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"); diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.1.95/linux/drivers/scsi/qlogicisp.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/qlogicisp.c Sat Apr 11 11:13:25 1998 @@ -26,6 +26,7 @@ #include #include #include +#include #include "sd.h" #include "hosts.h" @@ -516,6 +517,7 @@ 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 @@ 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", @@ -800,6 +802,15 @@ #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) { diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.1.95/linux/drivers/scsi/qlogicpti.c Sat Sep 6 10:04:16 1997 +++ linux/drivers/scsi/qlogicpti.c Sat Apr 11 11:13:25 1998 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -562,6 +563,7 @@ } 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 @@ 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 @@ 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"); @@ -1038,6 +1040,15 @@ } 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__ diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.95/linux/drivers/scsi/scsi.c Fri Apr 10 13:03:49 1998 +++ linux/drivers/scsi/scsi.c Sun Apr 12 11:05:00 1998 @@ -332,7 +332,6 @@ scsi_make_blocked_list(void) { int block_count = 0, index; - unsigned long flags; struct Scsi_Host * sh[128], * shpnt; /* @@ -1078,7 +1077,6 @@ 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 @@ #ifdef DEBUG_DELAY unsigned long clock; #endif - unsigned long flags; struct Scsi_Host * host; int rtn = 0; unsigned long timeout; @@ -1373,7 +1370,9 @@ 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 *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 @@ 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 @@ 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 @@ 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 void scsi_unregister_host(Scsi_Host_Template * tpnt) { - unsigned long flags; int online_status; int pcount; Scsi_Cmnd * SCpnt; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v2.1.95/linux/drivers/scsi/scsi_ioctl.c Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/scsi_ioctl.c Sun Apr 12 11:05:00 1998 @@ -96,6 +96,7 @@ 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 @@ { 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_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic) { + unsigned long flags; char * buf; unsigned char cmd[12]; char * cmd_in; @@ -271,8 +275,10 @@ { 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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.1.95/linux/drivers/scsi/scsi_obsolete.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/scsi_obsolete.c Sun Apr 12 11:05:00 1998 @@ -143,7 +143,9 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ */ 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 @@ 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 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 @@ #endif while (1) { - save_flags(flags); - cli(); /* * Protect against races here. If the command is done, or we are @@ -903,15 +892,15 @@ */ 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 @@ if (host->host_busy) { - restore_flags(flags); for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { SCpnt1 = SDpnt->device_queue; @@ -955,7 +943,6 @@ 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 @@ 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 @@ * 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: diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c --- v2.1.95/linux/drivers/scsi/scsiiom.c Tue Mar 10 10:03:33 1998 +++ linux/drivers/scsi/scsiiom.c Sat Apr 11 11:13:25 1998 @@ -269,6 +269,15 @@ } } +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) diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v2.1.95/linux/drivers/scsi/seagate.c Fri Nov 14 10:36:16 1997 +++ linux/drivers/scsi/seagate.c Sat Apr 11 11:13:25 1998 @@ -91,6 +91,7 @@ #include #include +#include #include #include #include @@ -343,6 +344,7 @@ 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 @@ */ 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); @@ -630,6 +632,16 @@ * host adapter. This occurs on the interrupt triggered by the target * 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) diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.1.95/linux/drivers/scsi/sg.c Fri Apr 10 13:03:49 1998 +++ linux/drivers/scsi/sg.c Sun Apr 12 11:05:00 1998 @@ -95,6 +95,8 @@ 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 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 @@ * 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"); diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c --- v2.1.95/linux/drivers/scsi/t128.c Fri Jan 23 18:10:32 1998 +++ linux/drivers/scsi/t128.c Sat Apr 11 11:13:25 1998 @@ -250,7 +250,7 @@ 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; diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/t128.h linux/drivers/scsi/t128.h --- v2.1.95/linux/drivers/scsi/t128.h Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/t128.h Sat Apr 11 11:13:25 1998 @@ -163,6 +163,7 @@ #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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c --- v2.1.95/linux/drivers/scsi/tmscsim.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/tmscsim.c Sat Apr 11 11:13:25 1998 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -1157,7 +1158,7 @@ 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 ); diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c --- v2.1.95/linux/drivers/scsi/ultrastor.c Tue Aug 12 20:26:26 1997 +++ linux/drivers/scsi/ultrastor.c Sat Apr 11 11:13:25 1998 @@ -137,6 +137,7 @@ #include #include #include +#include #include #define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */ @@ -294,6 +295,7 @@ #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 @@ 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 @@ 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); @@ -1155,6 +1157,15 @@ #if (ULTRASTOR_DEBUG & UD_INTERRUPT) printk("USx4F: interrupt: returning\n"); #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 diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.1.95/linux/drivers/scsi/wd7000.c Wed Apr 1 20:11:53 1998 +++ linux/drivers/scsi/wd7000.c Sat Apr 11 11:13:25 1998 @@ -154,6 +154,7 @@ #include #include #include +#include #include #include #include @@ -1148,6 +1149,15 @@ #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 @@ 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); } diff -u --recursive --new-file v2.1.95/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.95/linux/drivers/sound/Config.in Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/Config.in Sun Apr 12 11:42:15 1998 @@ -2,6 +2,7 @@ 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 diff -u --recursive --new-file v2.1.95/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.1.95/linux/drivers/sound/gus_card.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/gus_card.c Sun Apr 12 11:42:15 1998 @@ -3,6 +3,7 @@ * * Detection routine for the Gravis Ultrasound. */ + /* * Copyright (C) by Hannu Savolainen 1993-1997 * @@ -10,6 +11,15 @@ * 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 #include @@ -23,10 +33,14 @@ 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 @@ #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 @@ } #endif + + #ifdef MODULE static struct address_info config; @@ -207,7 +227,10 @@ 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(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 @@ 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) diff -u --recursive --new-file v2.1.95/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.95/linux/drivers/sound/gus_wave.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/gus_wave.c Sun Apr 12 11:42:15 1998 @@ -11,11 +11,14 @@ * 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 - #define GUSPNP_AUTODETECT #include "sound_config.h" @@ -70,10 +73,11 @@ }; 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 @@ 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 @@ 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 @@ 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 @@ 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) { diff -u --recursive --new-file v2.1.95/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.1.95/linux/drivers/sound/pas2_card.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/pas2_card.c Sun Apr 12 11:42:15 1998 @@ -37,6 +37,11 @@ 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 @@ */ , 0xB88); pas_write(0x80 -#ifdef PAS_JOYSTICK_ENABLE - | 0x40 -#endif + | joystick?0x40:0 ,0xF388); if (pas_irq < 0 || pas_irq > 15) @@ -379,6 +382,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; diff -u --recursive --new-file v2.1.95/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c --- v2.1.95/linux/fs/binfmt_misc.c Sun Oct 12 10:16:38 1997 +++ linux/fs/binfmt_misc.c Sat Apr 11 17:19:56 1998 @@ -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 @@ 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 @@ 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 @@ 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 @@ } } else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) { if (data) - clear_entry((int) data); + clear_entry((long) data); else clear_entries(); } else { diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/a.out.h linux/include/asm-arm/a.out.h --- v2.1.95/linux/include/asm-arm/a.out.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/a.out.h Sun Apr 12 11:42:15 1998 @@ -1,16 +1,18 @@ #ifndef __ARM_A_OUT_H__ #define __ARM_A_OUT_H__ +#include + 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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/a.out.h linux/include/asm-arm/arch-a5k/a.out.h --- v2.1.95/linux/include/asm-arm/arch-a5k/a.out.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/a.out.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/dma.h linux/include/asm-arm/arch-a5k/dma.h --- v2.1.95/linux/include/asm-arm/arch-a5k/dma.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/dma.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/hardware.h linux/include/asm-arm/arch-a5k/hardware.h --- v2.1.95/linux/include/asm-arm/arch-a5k/hardware.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/hardware.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/ide.h linux/include/asm-arm/arch-a5k/ide.h --- v2.1.95/linux/include/asm-arm/arch-a5k/ide.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/ide.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/io.h linux/include/asm-arm/arch-a5k/io.h --- v2.1.95/linux/include/asm-arm/arch-a5k/io.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/io.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/irq.h linux/include/asm-arm/arch-a5k/irq.h --- v2.1.95/linux/include/asm-arm/arch-a5k/irq.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/irq.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/irqs.h linux/include/asm-arm/arch-a5k/irqs.h --- v2.1.95/linux/include/asm-arm/arch-a5k/irqs.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/irqs.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/mmu.h linux/include/asm-arm/arch-a5k/mmu.h --- v2.1.95/linux/include/asm-arm/arch-a5k/mmu.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/mmu.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/oldlatches.h linux/include/asm-arm/arch-a5k/oldlatches.h --- v2.1.95/linux/include/asm-arm/arch-a5k/oldlatches.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/oldlatches.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/processor.h linux/include/asm-arm/arch-a5k/processor.h --- v2.1.95/linux/include/asm-arm/arch-a5k/processor.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/processor.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/serial.h linux/include/asm-arm/arch-a5k/serial.h --- v2.1.95/linux/include/asm-arm/arch-a5k/serial.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/serial.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/shmparam.h linux/include/asm-arm/arch-a5k/shmparam.h --- v2.1.95/linux/include/asm-arm/arch-a5k/shmparam.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/shmparam.h Wed Dec 31 16:00:00 1969 @@ -1,5 +0,0 @@ -/* - * linux/include/asm-arm/arch-a5k/shmparam.h - * - * Copyright (c) 1996 Russell King. - */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/system.h linux/include/asm-arm/arch-a5k/system.h --- v2.1.95/linux/include/asm-arm/arch-a5k/system.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/system.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/time.h linux/include/asm-arm/arch-a5k/time.h --- v2.1.95/linux/include/asm-arm/arch-a5k/time.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/time.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/timex.h linux/include/asm-arm/arch-a5k/timex.h --- v2.1.95/linux/include/asm-arm/arch-a5k/timex.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/timex.h Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/uncompress.h linux/include/asm-arm/arch-a5k/uncompress.h --- v2.1.95/linux/include/asm-arm/arch-a5k/uncompress.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-a5k/uncompress.h Wed Dec 31 16:00:00 1969 @@ -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"); -} diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/a.out.h linux/include/asm-arm/arch-arc/a.out.h --- v2.1.95/linux/include/asm-arm/arch-arc/a.out.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/a.out.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/dma.h linux/include/asm-arm/arch-arc/dma.h --- v2.1.95/linux/include/asm-arm/arch-arc/dma.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/dma.h Sun Apr 12 11:42:15 1998 @@ -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 +#include -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 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); - -/* 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); +#define MAX_DMA_ADDRESS 0x03000000 -/* 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; + +#define MAX_DMA_CHANNELS 4 + +#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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h --- v2.1.95/linux/include/asm-arm/arch-arc/hardware.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/hardware.h Sun Apr 12 11:42:15 1998 @@ -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 + /* - * 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 */ @@ -29,8 +40,10 @@ */ #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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/ide.h linux/include/asm-arm/arch-arc/ide.h --- v2.1.95/linux/include/asm-arm/arch-arc/ide.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/ide.h Sun Apr 12 11:42:15 1998 @@ -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 + 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; } diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/io.h linux/include/asm-arm/arch-arc/io.h --- v2.1.95/linux/include/asm-arm/arch-arc/io.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/io.h Sun Apr 12 11:42:15 1998 @@ -10,16 +10,6 @@ #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 @@ "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 @@ "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"); diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h --- v2.1.95/linux/include/asm-arm/arch-arc/irq.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/irq.h Sun Apr 12 11:42:15 1998 @@ -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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/irqs.h linux/include/asm-arm/arch-arc/irqs.h --- v2.1.95/linux/include/asm-arm/arch-arc/irqs.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/irqs.h Sun Apr 12 11:42:15 1998 @@ -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 + +#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 @@ -16,15 +30,20 @@ #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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/keyboard.h linux/include/asm-arm/arch-arc/keyboard.h --- v2.1.95/linux/include/asm-arm/arch-arc/keyboard.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-arc/keyboard.h Sun Apr 12 11:42:15 1998 @@ -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 + +#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) diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/mmu.h linux/include/asm-arm/arch-arc/mmu.h --- v2.1.95/linux/include/asm-arm/arch-arc/mmu.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/mmu.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/oldlatches.h linux/include/asm-arm/arch-arc/oldlatches.h --- v2.1.95/linux/include/asm-arm/arch-arc/oldlatches.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/oldlatches.h Sun Apr 12 11:42:15 1998 @@ -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 + +#if defined(CONFIG_ARCH_ARC) #define LATCHA_FDSEL0 (1<<0) #define LATCHA_FDSEL1 (1<<1) #define LATCHA_FDSEL2 (1<<2) @@ -21,4 +34,12 @@ /* 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 + diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/processor.h linux/include/asm-arm/arch-arc/processor.h --- v2.1.95/linux/include/asm-arm/arch-arc/processor.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/processor.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/serial.h linux/include/asm-arm/arch-arc/serial.h --- v2.1.95/linux/include/asm-arm/arch-arc/serial.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/serial.h Sun Apr 12 11:42:15 1998 @@ -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 + /* * This assumes you have a 1.8432 MHz clock for your UART. * @@ -20,6 +23,26 @@ #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 */ \ @@ -37,4 +60,5 @@ { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS12 */ \ { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS13 */ +#endif #endif diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h --- v2.1.95/linux/include/asm-arm/arch-arc/system.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/system.h Sun Apr 12 11:42:15 1998 @@ -6,6 +6,8 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H +#ifdef CONFIG_ARCH_ARC + #define cliIF() \ do { \ unsigned long temp; \ @@ -16,6 +18,8 @@ : "=r" (temp) \ : ); \ } while(0) + +#endif extern __inline__ void arch_hard_reset (void) { diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/timex.h linux/include/asm-arm/arch-arc/timex.h --- v2.1.95/linux/include/asm-arm/arch-arc/timex.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/timex.h Sun Apr 12 11:42:15 1998 @@ -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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/uncompress.h linux/include/asm-arm/arch-arc/uncompress.h --- v2.1.95/linux/include/asm-arm/arch-arc/uncompress.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-arc/uncompress.h Sun Apr 12 11:42:15 1998 @@ -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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/a.out.h linux/include/asm-arm/arch-ebsa110/a.out.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/a.out.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/a.out.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/dma.h linux/include/asm-arm/arch-ebsa110/dma.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/dma.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/dma.h Sun Apr 12 11:42:15 1998 @@ -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. +/* + * This is the maximum DMA address that can be DMAd to. + * There should not be more than (0xd0000000 - 0xc0000000) + * bytes of RAM. */ -static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) -{ - printk (dma_str, "set_dma_page", dmanr); -} +#define MAX_DMA_ADDRESS 0xd0000000 - -/* 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. +/* + * 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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/hardware.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/hardware.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/io.h linux/include/asm-arm/arch-ebsa110/io.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/io.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/io.h Sun Apr 12 11:42:15 1998 @@ -10,16 +10,6 @@ #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 @@ 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) \ ({ \ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/irqs.h linux/include/asm-arm/arch-ebsa110/irqs.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/irqs.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/irqs.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/mm-init.h linux/include/asm-arm/arch-ebsa110/mm-init.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/mm-init.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/mm-init.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/mmap.h linux/include/asm-arm/arch-ebsa110/mmap.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/mmap.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/mmap.h Wed Dec 31 16:00:00 1969 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/mmu.h linux/include/asm-arm/arch-ebsa110/mmu.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/mmu.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/mmu.h Sun Apr 12 11:42:15 1998 @@ -13,7 +13,14 @@ /* * 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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/processor.h linux/include/asm-arm/arch-ebsa110/processor.h --- v2.1.95/linux/include/asm-arm/arch-ebsa110/processor.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-ebsa110/processor.h Sun Apr 12 11:42:15 1998 @@ -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, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } #endif diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/a.out.h linux/include/asm-arm/arch-ebsa285/a.out.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/a.out.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/a.out.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/dma.h linux/include/asm-arm/arch-ebsa285/dma.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/dma.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/dma.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/hardware.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/hardware.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/ide.h linux/include/asm-arm/arch-ebsa285/ide.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/ide.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/ide.h Sun Apr 12 11:42:15 1998 @@ -0,0 +1 @@ +/* no ide */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/io.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/io.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/irq.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/irq.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/irqs.h linux/include/asm-arm/arch-ebsa285/irqs.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/irqs.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/irqs.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/keyboard.h linux/include/asm-arm/arch-ebsa285/keyboard.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/keyboard.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/keyboard.h Sun Apr 12 11:42:15 1998 @@ -0,0 +1,36 @@ +/* + * linux/include/asm-arm/arch-ebsa285/keyboard.h + * + * Keyboard driver definitions for EBSA285 architecture + * + * (C) 1998 Russell King + */ + +#include + +#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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/mm-init.h linux/include/asm-arm/arch-ebsa285/mm-init.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/mm-init.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/mm-init.h Sun Apr 12 11:42:15 1998 @@ -0,0 +1,5 @@ +/* + * linux/include/asm-arm/arch-ebsa110/mmap.h + * + * Copyright (C) 1996,1997,1998 Russell King + */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/mmu.h linux/include/asm-arm/arch-ebsa285/mmu.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/mmu.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/mmu.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/oldlatches.h linux/include/asm-arm/arch-ebsa285/oldlatches.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/oldlatches.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/oldlatches.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/processor.h linux/include/asm-arm/arch-ebsa285/processor.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/processor.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/processor.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/shmparam.h linux/include/asm-arm/arch-ebsa285/shmparam.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/shmparam.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/shmparam.h Sun Apr 12 11:42:15 1998 @@ -0,0 +1,5 @@ +/* + * linux/include/asm-arm/arch-ebsa110/shmparam.h + * + * Copyright (c) 1996 Russell King. + */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/system.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/system.h Sun Apr 12 11:42:15 1998 @@ -0,0 +1,24 @@ +/* + * linux/include/asm-arm/arch-ebsa285/system.h + * + * Copyright (c) 1996,1997,1998 Russell King. + */ +#include +#include + +/* 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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/time.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/time.h Sun Apr 12 11:42:15 1998 @@ -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 + +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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/timex.h linux/include/asm-arm/arch-ebsa285/timex.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/timex.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/timex.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/uncompress.h linux/include/asm-arm/arch-ebsa285/uncompress.h --- v2.1.95/linux/include/asm-arm/arch-ebsa285/uncompress.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-ebsa285/uncompress.h Sun Apr 12 11:42:15 1998 @@ -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() diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/a.out.h linux/include/asm-arm/arch-nexuspci/a.out.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/a.out.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-nexuspci/a.out.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/dma.h linux/include/asm-arm/arch-nexuspci/dma.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/dma.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-nexuspci/dma.h Sun Apr 12 11:42:15 1998 @@ -1,100 +1,17 @@ /* - * 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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/hardware.h linux/include/asm-arm/arch-nexuspci/hardware.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/hardware.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-nexuspci/hardware.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/irqs.h linux/include/asm-arm/arch-nexuspci/irqs.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/irqs.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-nexuspci/irqs.h Sun Apr 12 11:42:15 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/mm-init.h linux/include/asm-arm/arch-nexuspci/mm-init.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/mm-init.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-nexuspci/mm-init.h Sun Apr 12 11:42:15 1998 @@ -0,0 +1,5 @@ +/* + * linux/include/asm-arm/arch-nexuspci/mmap.h + * + * Copyright (C) 1998 Philip Blundell + */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/mmap.h linux/include/asm-arm/arch-nexuspci/mmap.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/mmap.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-nexuspci/mmap.h Wed Dec 31 16:00:00 1969 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/processor.h linux/include/asm-arm/arch-nexuspci/processor.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/processor.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-nexuspci/processor.h Sun Apr 12 11:42:15 1998 @@ -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, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } #endif diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/serial.h linux/include/asm-arm/arch-nexuspci/serial.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/serial.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-nexuspci/serial.h Wed Dec 31 16:00:00 1969 @@ -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 - diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/uncompress.h linux/include/asm-arm/arch-nexuspci/uncompress.h --- v2.1.95/linux/include/asm-arm/arch-nexuspci/uncompress.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-nexuspci/uncompress.h Sun Apr 12 11:42:15 1998 @@ -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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/a.out.h linux/include/asm-arm/arch-rpc/a.out.h --- v2.1.95/linux/include/asm-arm/arch-rpc/a.out.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/a.out.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/dma.h linux/include/asm-arm/arch-rpc/dma.h --- v2.1.95/linux/include/asm-arm/arch-rpc/dma.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/dma.h Sun Apr 12 11:42:15 1998 @@ -1,128 +1,33 @@ #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. +/* + * This is the maximum DMA address that can be DMAd to. + * There should not be more than (0xd0000000 - 0xc0000000) + * bytes of RAM. */ -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); +#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; + +#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 -/* 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 DMA_FLOPPY DMA_VIRTUAL_FLOPPY #endif /* _ASM_ARCH_DMA_H */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h --- v2.1.95/linux/include/asm-arm/arch-rpc/hardware.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/hardware.h Sun Apr 12 11:42:15 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/io.h linux/include/asm-arm/arch-rpc/io.h --- v2.1.95/linux/include/asm-arm/arch-rpc/io.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/io.h Sun Apr 12 11:42:16 1998 @@ -10,16 +10,6 @@ #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 @@ }) #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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h --- v2.1.95/linux/include/asm-arm/arch-rpc/irq.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/irq.h Sun Apr 12 11:42:16 1998 @@ -131,8 +131,4 @@ 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); } diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/irqs.h linux/include/asm-arm/arch-rpc/irqs.h --- v2.1.95/linux/include/asm-arm/arch-rpc/irqs.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/irqs.h Sun Apr 12 11:42:16 1998 @@ -21,8 +21,17 @@ #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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/keyboard.h linux/include/asm-arm/arch-rpc/keyboard.h --- v2.1.95/linux/include/asm-arm/arch-rpc/keyboard.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-rpc/keyboard.h Sun Apr 12 11:42:16 1998 @@ -0,0 +1,38 @@ +/* + * linux/include/asm-arm/arch-rpc/keyboard.h + * + * Keyboard driver definitions for RiscPC architecture + * + * (C) 1998 Russell King + */ + +#include + +#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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/mm-init.h linux/include/asm-arm/arch-rpc/mm-init.h --- v2.1.95/linux/include/asm-arm/arch-rpc/mm-init.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-rpc/mm-init.h Sun Apr 12 11:42:16 1998 @@ -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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/mmap.h linux/include/asm-arm/arch-rpc/mmap.h --- v2.1.95/linux/include/asm-arm/arch-rpc/mmap.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/mmap.h Wed Dec 31 16:00:00 1969 @@ -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; -} diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/mmu.h linux/include/asm-arm/arch-rpc/mmu.h --- v2.1.95/linux/include/asm-arm/arch-rpc/mmu.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/mmu.h Sun Apr 12 11:42:16 1998 @@ -7,11 +7,21 @@ * 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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/processor.h linux/include/asm-arm/arch-rpc/processor.h --- v2.1.95/linux/include/asm-arm/arch-rpc/processor.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/processor.h Sun Apr 12 11:42:16 1998 @@ -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, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } #endif diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/uncompress.h linux/include/asm-arm/arch-rpc/uncompress.h --- v2.1.95/linux/include/asm-arm/arch-rpc/uncompress.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/uncompress.h Sun Apr 12 11:42:16 1998 @@ -77,7 +77,7 @@ } } 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 ) { diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h --- v2.1.95/linux/include/asm-arm/dma.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/dma.h Sun Apr 12 11:42:16 1998 @@ -1,28 +1,105 @@ #ifndef __ASM_ARM_DMA_H #define __ASM_ARM_DMA_H -#include +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 +#include -#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 - -/* 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); +/* 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) + +/* 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); +} + +/* 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 */ - diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/ecard.h linux/include/asm-arm/ecard.h --- v2.1.95/linux/include/asm-arm/ecard.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/ecard.h Sun Apr 12 11:42:16 1998 @@ -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 @@ 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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/elf.h linux/include/asm-arm/elf.h --- v2.1.95/linux/include/asm-arm/elf.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/elf.h Sun Apr 12 11:42:16 1998 @@ -38,6 +38,23 @@ #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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h --- v2.1.95/linux/include/asm-arm/hardirq.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/hardirq.h Sun Apr 12 11:42:16 1998 @@ -4,7 +4,6 @@ #include extern unsigned int local_irq_count[NR_CPUS]; -#define in_interrupt() (local_irq_count[smp_processor_id()] != 0) #ifndef __SMP__ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/hardware.h linux/include/asm-arm/hardware.h --- v2.1.95/linux/include/asm-arm/hardware.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/hardware.h Sun Apr 12 11:42:16 1998 @@ -140,6 +140,11 @@ #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) @@ -194,6 +199,9 @@ #define IOMD_DMASTAT __IOMD(0x1F0) #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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/io.h linux/include/asm-arm/io.h --- v2.1.95/linux/include/asm-arm/io.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/io.h Sun Apr 12 11:42:16 1998 @@ -17,10 +17,20 @@ #include /* 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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/irq-no.h linux/include/asm-arm/irq-no.h --- v2.1.95/linux/include/asm-arm/irq-no.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/irq-no.h Wed Dec 31 16:00:00 1969 @@ -1,11 +0,0 @@ -/* - * linux/include/asm-arm/irq-no.h - * - * Machine independent interrupt numbers - */ - -#include - -#ifndef NR_IRQS -#define NR_IRQS 128 -#endif diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/irq.h linux/include/asm-arm/irq.h --- v2.1.95/linux/include/asm-arm/irq.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/irq.h Sun Apr 12 11:42:16 1998 @@ -1,7 +1,19 @@ #ifndef __ASM_ARM_IRQ_H #define __ASM_ARM_IRQ_H -#include +#include + +#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 -u --recursive --new-file v2.1.95/linux/include/asm-arm/keyboard.h linux/include/asm-arm/keyboard.h --- v2.1.95/linux/include/asm-arm/keyboard.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/keyboard.h Sun Apr 12 11:42:16 1998 @@ -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 + +#define SYSRQ_KEY 13 + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARM_KEYBOARD_H */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/leds.h linux/include/asm-arm/leds.h --- v2.1.95/linux/include/asm-arm/leds.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/leds.h Sun Apr 12 11:42:16 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armo/processor.h linux/include/asm-arm/proc-armo/processor.h --- v2.1.95/linux/include/asm-arm/proc-armo/processor.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/proc-armo/processor.h Sun Apr 12 11:42:16 1998 @@ -113,6 +113,15 @@ 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 diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armv/mm-init.h linux/include/asm-arm/proc-armv/mm-init.h --- v2.1.95/linux/include/asm-arm/proc-armv/mm-init.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/proc-armv/mm-init.h Sun Apr 12 11:42:16 1998 @@ -35,76 +35,120 @@ * * We set it up using the section page table entries. */ - -#include #include -#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; + + pgdp = pgd_offset_k(virt); + pmdp = pmd_offset(pgdp, virt); - pmd_val(pmd) = entry; - set_pmd (pmd_offset (swapper_pg_dir + index, 0), pmd); + 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; + 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); - /* 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; + 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; /* - * An area to invalidate the cache + * map in zero page */ - setup_swapper_dir (0xdf0, SAFE_ADDR | PMD_SECT | PMD_SECT_AP_READ); + alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET), DOMAIN_USER, PTE_CACHEABLE); - /* 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; - } + /* + * 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); -#ifdef HAVE_MAP_VID_MEM - map_screen_mem(0, 0, 0); -#endif + /* + * An area to invalidate the cache + */ + alloc_init_section(&start_mem, 0xdf000000, SAFE_ADDR, DOMAIN_KERNEL, + PMD_SECT_CACHEABLE | PMD_SECT_AP_READ); + + /* + * 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; diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h --- v2.1.95/linux/include/asm-arm/proc-armv/pgtable.h Wed Apr 8 19:36:28 1998 +++ linux/include/asm-arm/proc-armv/pgtable.h Sun Apr 12 11:42:16 1998 @@ -178,17 +178,29 @@ /* * 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 @@ /* 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 @@ return 0; } #else - return ((pte_val(pmd) + 1) & PMD_TYPE_MASK); + return ((pte_val(pte) + 1) & 2); #endif } @@ -300,18 +312,24 @@ 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 @@ 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__ 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__ 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 @@ * 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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9)) #endif /* __ASM_PROC_PAGE_H */ - diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h --- v2.1.95/linux/include/asm-arm/proc-armv/processor.h Wed Apr 8 19:36:28 1998 +++ linux/include/asm-arm/proc-armv/processor.h Sun Apr 12 11:42:16 1998 @@ -82,7 +82,10 @@ 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) */ \ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armv/system.h linux/include/asm-arm/proc-armv/system.h --- v2.1.95/linux/include/asm-arm/proc-armv/system.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/proc-armv/system.h Sun Apr 12 11:42:16 1998 @@ -33,16 +33,13 @@ /* * 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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/smp.h linux/include/asm-arm/smp.h --- v2.1.95/linux/include/asm-arm/smp.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/smp.h Sun Apr 12 11:42:16 1998 @@ -3,5 +3,10 @@ #ifdef __SMP__ #error SMP not supported +#else + +#define cpu_logical_map(cpu) (cpu) + #endif + #endif diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/socket.h linux/include/asm-arm/socket.h --- v2.1.95/linux/include/asm-arm/socket.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/socket.h Sun Apr 12 11:42:16 1998 @@ -28,6 +28,11 @@ #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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/softirq.h linux/include/asm-arm/softirq.h --- v2.1.95/linux/include/asm-arm/softirq.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/softirq.h Sun Apr 12 11:42:16 1998 @@ -4,6 +4,9 @@ #include #include +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 @@ 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 */ diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/types.h linux/include/asm-arm/types.h --- v2.1.95/linux/include/asm-arm/types.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/types.h Sun Apr 12 11:42:16 1998 @@ -39,6 +39,8 @@ typedef signed long long s64; typedef unsigned long long u64; +#define BITS_PER_LONG 32 + #endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v2.1.95/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.1.95/linux/include/asm-i386/system.h Fri Apr 10 13:03:49 1998 +++ linux/include/asm-i386/system.h Fri Apr 10 13:04:39 1998 @@ -138,8 +138,8 @@ "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) { diff -u --recursive --new-file v2.1.95/linux/include/linux/cyclades.h linux/include/linux/cyclades.h --- v2.1.95/linux/include/linux/cyclades.h Tue Nov 11 11:04:15 1997 +++ linux/include/linux/cyclades.h Fri Apr 10 15:35:00 1998 @@ -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 and + * This file is maintained by Ivan Passos , + * Marcio Saito and * Randolph Bentson . * * 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 @@ #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 @@ #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_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 @@ 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 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 @@ * 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 @@ /**** 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 */ diff -u --recursive --new-file v2.1.95/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.1.95/linux/include/linux/if_arp.h Fri Feb 6 15:33:34 1998 +++ linux/include/linux/if_arp.h Sat Apr 11 17:18:15 1998 @@ -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 */ diff -u --recursive --new-file v2.1.95/linux/include/linux/parport.h linux/include/linux/parport.h --- v2.1.95/linux/include/linux/parport.h Tue Mar 10 10:03:35 1998 +++ linux/include/linux/parport.h Sun Apr 12 11:39:20 1998 @@ -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 @@ #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); diff -u --recursive --new-file v2.1.95/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.95/linux/include/linux/pci.h Fri Apr 10 13:03:49 1998 +++ linux/include/linux/pci.h Sat Apr 11 11:19:34 1998 @@ -935,6 +935,7 @@ #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 diff -u --recursive --new-file v2.1.95/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.95/linux/include/linux/socket.h Thu Mar 26 15:57:06 1998 +++ linux/include/linux/socket.h Sat Apr 11 17:18:15 1998 @@ -150,6 +150,7 @@ #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. */ diff -u --recursive --new-file v2.1.95/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.1.95/linux/include/linux/sysctl.h Wed Apr 1 20:11:54 1998 +++ linux/include/linux/sysctl.h Sat Apr 11 17:18:15 1998 @@ -153,6 +153,7 @@ 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, diff -u --recursive --new-file v2.1.95/linux/include/linux/tcp.h linux/include/linux/tcp.h --- v2.1.95/linux/include/linux/tcp.h Fri Feb 6 15:33:34 1998 +++ linux/include/linux/tcp.h Sat Apr 11 17:18:15 1998 @@ -65,8 +65,13 @@ 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), diff -u --recursive --new-file v2.1.95/linux/include/net/ipx.h linux/include/net/ipx.h --- v2.1.95/linux/include/net/ipx.h Mon Feb 23 18:12:12 1998 +++ linux/include/net/ipx.h Sat Apr 11 17:18:15 1998 @@ -34,7 +34,7 @@ #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)); @@ -75,5 +75,8 @@ #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_ */ diff -u --recursive --new-file v2.1.95/linux/include/net/netrom.h linux/include/net/netrom.h --- v2.1.95/linux/include/net/netrom.h Thu Dec 4 13:36:25 1997 +++ linux/include/net/netrom.h Sat Apr 11 17:18:15 1998 @@ -126,6 +126,11 @@ /* 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 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 */ diff -u --recursive --new-file v2.1.95/linux/include/net/rose.h linux/include/net/rose.h --- v2.1.95/linux/include/net/rose.h Thu Dec 4 13:36:25 1997 +++ linux/include/net/rose.h Sat Apr 11 17:18:15 1998 @@ -87,6 +87,7 @@ 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 @@ rose_address address; unsigned short mask; unsigned char count; + char loopback; struct rose_neigh *neighbour[3]; }; @@ -179,11 +181,21 @@ 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); diff -u --recursive --new-file v2.1.95/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.95/linux/include/net/sock.h Mon Apr 6 17:41:01 1998 +++ linux/include/net/sock.h Sat Apr 11 17:18:15 1998 @@ -66,8 +66,12 @@ #endif #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) +#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE) +#include +#else #include -#endif +#endif /* CONFIG_SPX */ +#endif /* CONFIG_IPX */ #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #include @@ -413,7 +417,11 @@ #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 diff -u --recursive --new-file v2.1.95/linux/include/net/spx.h linux/include/net/spx.h --- v2.1.95/linux/include/net/spx.h Thu Aug 1 05:43:05 1996 +++ linux/include/net/spx.h Sat Apr 11 17:18:15 1998 @@ -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 + 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 -u --recursive --new-file v2.1.95/linux/include/net/spxcall.h linux/include/net/spxcall.h --- v2.1.95/linux/include/net/spxcall.h Wed Dec 31 16:00:00 1969 +++ linux/include/net/spxcall.h Sat Apr 11 17:18:15 1998 @@ -0,0 +1,2 @@ +/* Separate to keep compilation of protocols.c simpler */ +extern void spx_proto_init(struct net_proto *pro); diff -u --recursive --new-file v2.1.95/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.1.95/linux/include/net/tcp.h Mon Apr 6 17:41:01 1998 +++ linux/include/net/tcp.h Sat Apr 11 17:18:15 1998 @@ -218,17 +218,6 @@ !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 @@ #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 __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 @@ 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--; @@ -940,9 +931,6 @@ /* Set the clamp no higher than max representable value */ (*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) { diff -u --recursive --new-file v2.1.95/linux/include/scsi/sg.h linux/include/scsi/sg.h --- v2.1.95/linux/include/scsi/sg.h Wed May 1 21:48:55 1996 +++ linux/include/scsi/sg.h Fri Apr 10 15:22:21 1998 @@ -30,6 +30,12 @@ #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 diff -u --recursive --new-file v2.1.95/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.95/linux/net/ax25/af_ax25.c Tue Mar 17 22:18:16 1998 +++ linux/net/ax25/af_ax25.c Sat Apr 11 17:18:16 1998 @@ -1622,7 +1622,7 @@ 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 @@ 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"); } diff -u --recursive --new-file v2.1.95/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v2.1.95/linux/net/ax25/ax25_out.c Thu Feb 12 20:56:14 1998 +++ linux/net/ax25/ax25_out.c Sat Apr 11 17:18:16 1998 @@ -362,7 +362,7 @@ 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); } diff -u --recursive --new-file v2.1.95/linux/net/core/iovec.c linux/net/core/iovec.c --- v2.1.95/linux/net/core/iovec.c Thu Mar 26 15:57:10 1998 +++ linux/net/core/iovec.c Sat Apr 11 17:18:16 1998 @@ -29,7 +29,8 @@ #include /* - * 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 @@ } 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; } /* diff -u --recursive --new-file v2.1.95/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.95/linux/net/core/sock.c Thu Mar 26 15:57:10 1998 +++ linux/net/core/sock.c Sat Apr 11 17:18:16 1998 @@ -589,38 +589,37 @@ */ 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 @@ * 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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.1.95/linux/net/ipv4/icmp.c Tue Mar 17 22:18:16 1998 +++ linux/net/ipv4/icmp.c Sat Apr 11 17:18:16 1998 @@ -3,7 +3,7 @@ * * Alan Cox, * - * 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 @@ * 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 @@ /* 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, }, diff -u --recursive --new-file v2.1.95/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.1.95/linux/net/ipv4/sysctl_net_ipv4.c Mon Apr 6 17:41:01 1998 +++ linux/net/ipv4/sysctl_net_ipv4.c Sat Apr 11 17:18:16 1998 @@ -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_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_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 @@ {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 @@ {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", diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.95/linux/net/ipv4/tcp.c Mon Apr 6 17:41:01 1998 +++ linux/net/ipv4/tcp.c Sat Apr 11 17:18:16 1998 @@ -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, * Fred N. van Kempen, @@ -197,7 +197,7 @@ * 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(). @@ -451,35 +451,6 @@ } /* - * 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. * * Must be called with the socket lock held. @@ -513,14 +484,12 @@ * 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 @@ /* 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 @@ 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 @@ /* * 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 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 @@ 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 @@ 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 @@ 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); @@ -1286,43 +1256,43 @@ } /* + * 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 * states. A shutdown() may have already sent the FIN, or we may be * 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 @@ * 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ if (signal_pending(current)) break; } + current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); return req; } @@ -1515,14 +1522,14 @@ /* 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; } diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.95/linux/net/ipv4/tcp_input.c Mon Apr 6 17:41:01 1998 +++ linux/net/ipv4/tcp_input.c Sat Apr 11 17:18:16 1998 @@ -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, * Fred N. van Kempen, @@ -42,6 +42,11 @@ * 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 @@ -667,7 +672,20 @@ 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 + */ + 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 @@ } } 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 @@ * 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; } diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.95/linux/net/ipv4/tcp_ipv4.c Wed Apr 8 19:36:29 1998 +++ linux/net/ipv4/tcp_ipv4.c Sat Apr 11 17:18:16 1998 @@ -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 * @@ -38,13 +38,12 @@ * 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 @@ -337,9 +336,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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), diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.1.95/linux/net/ipv4/tcp_output.c Mon Apr 6 17:41:01 1998 +++ linux/net/ipv4/tcp_output.c Sat Apr 11 17:18:16 1998 @@ -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, * Fred N. van Kempen, @@ -37,6 +37,10 @@ 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 @@ 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)) diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.1.95/linux/net/ipv4/tcp_timer.c Mon Apr 6 17:41:01 1998 +++ linux/net/ipv4/tcp_timer.c Sat Apr 11 17:18:16 1998 @@ -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, * Fred N. van Kempen, @@ -460,11 +460,7 @@ #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) diff -u --recursive --new-file v2.1.95/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.1.95/linux/net/ipv6/tcp_ipv6.c Mon Apr 6 17:41:01 1998 +++ linux/net/ipv6/tcp_ipv6.c Sat Apr 11 17:18:16 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $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 +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 @@ 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 @@ __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 @@ goto hit; } } -#ifdef USE_QUICKSYNS -listener_shortcut: -#endif sk = tcp_v6_lookup_listener(daddr, hnum, dif); hit: return sk; @@ -638,6 +628,7 @@ 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 @@ 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 @@ /* * 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 @@ goto drop; } - sk->ack_backlog++; + BACKLOG(sk)++; req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */ @@ -820,7 +814,7 @@ struct tcp_opt *newtp; struct sock *newsk; int mss; - + if (skb->protocol == __constant_htons(ETH_P_IP)) { /* * v6 mapped @@ -848,6 +842,9 @@ } + if (sk->ack_backlog > sk->max_ack_backlog) + return NULL; + if (dst == NULL) { /* * options / mss / route cache @@ -866,6 +863,8 @@ 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 @@ 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); diff -u --recursive --new-file v2.1.95/linux/net/ipx/Config.in linux/net/ipx/Config.in --- v2.1.95/linux/net/ipx/Config.in Mon Feb 23 18:12:14 1998 +++ linux/net/ipx/Config.in Sat Apr 11 17:18:16 1998 @@ -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 diff -u --recursive --new-file v2.1.95/linux/net/ipx/Makefile linux/net/ipx/Makefile --- v2.1.95/linux/net/ipx/Makefile Mon Feb 23 18:12:14 1998 +++ linux/net/ipx/Makefile Sat Apr 11 17:18:16 1998 @@ -17,6 +17,14 @@ 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: diff -u --recursive --new-file v2.1.95/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.1.95/linux/net/ipx/af_ipx.c Tue Mar 17 22:18:16 1998 +++ linux/net/ipx/af_ipx.c Sat Apr 11 17:18:16 1998 @@ -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 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 @@ * 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 @@ 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 @@ */ __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 @@ if(packet->ipx_pktsize&htons(1)) sum+=ntohs(0xff00)&*p; + packet->ipx_tctrl = hops; /* * Do final fixup */ @@ -1713,19 +1720,24 @@ 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 @@ 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 proto_ops ipx_dgram_ops = { AF_IPX, - sock_no_dup, ipx_release, ipx_bind, @@ -2280,7 +2319,7 @@ 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 @@ /* 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 @@ */ __initfunc(static void ipx_proto_finito(void)) -{ ipx_interface *ifc; +{ + ipx_interface *ifc; while (ipx_interfaces) { ifc = ipx_interfaces; diff -u --recursive --new-file v2.1.95/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c --- v2.1.95/linux/net/ipx/af_spx.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipx/af_spx.c Sat Apr 11 17:18:16 1998 @@ -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 + * Jim Freeman + * + * 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 +#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 */ diff -u --recursive --new-file v2.1.95/linux/net/netrom/Makefile linux/net/netrom/Makefile --- v2.1.95/linux/net/netrom/Makefile Mon Apr 7 11:35:33 1997 +++ linux/net/netrom/Makefile Sat Apr 11 17:18:16 1998 @@ -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) diff -u --recursive --new-file v2.1.95/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.1.95/linux/net/netrom/af_netrom.c Tue Mar 17 22:18:16 1998 +++ linux/net/netrom/af_netrom.c Sat Apr 11 17:18:16 1998 @@ -259,6 +259,28 @@ } /* + * 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. */ void nr_destroy_socket(struct sock *); @@ -535,12 +557,12 @@ 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 @@ 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 @@ sti(); /* Now attach up the new socket */ - skb->sk = NULL; kfree_skb(skb); sk->ack_backlog--; newsock->sk = newsk; @@ -802,7 +822,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); diff -u --recursive --new-file v2.1.95/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c --- v2.1.95/linux/net/netrom/nr_in.c Thu Feb 12 20:56:15 1998 +++ linux/net/netrom/nr_in.c Sat Apr 11 17:18:16 1998 @@ -129,6 +129,10 @@ { 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 @@ nr_disconnect(sk, 0); break; + case NR_CONNACK | NR_CHOKE_FLAG: case NR_DISCACK: nr_disconnect(sk, ECONNRESET); break; diff -u --recursive --new-file v2.1.95/linux/net/netrom/nr_loopback.c linux/net/netrom/nr_loopback.c --- v2.1.95/linux/net/netrom/nr_loopback.c Wed Dec 31 16:00:00 1969 +++ linux/net/netrom/nr_loopback.c Sat Apr 11 17:18:16 1998 @@ -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 +#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) +#include +#include +#include +#include +#include +#include + +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 diff -u --recursive --new-file v2.1.95/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c --- v2.1.95/linux/net/netrom/nr_route.c Mon Jul 7 08:20:00 1997 +++ linux/net/netrom/nr_route.c Sat Apr 11 17:18:16 1998 @@ -697,8 +697,12 @@ 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; diff -u --recursive --new-file v2.1.95/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c --- v2.1.95/linux/net/netrom/nr_subr.c Thu Feb 12 20:56:15 1998 +++ linux/net/netrom/nr_subr.c Sat Apr 11 17:18:16 1998 @@ -229,7 +229,7 @@ * 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 @@ *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; diff -u --recursive --new-file v2.1.95/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.95/linux/net/netsyms.c Wed Apr 1 20:11:55 1998 +++ linux/net/netsyms.c Sat Apr 11 17:18:16 1998 @@ -64,12 +64,17 @@ 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 #endif +EXPORT_SYMBOL(dev_lockct); + /* Skbuff symbols. */ EXPORT_SYMBOL(skb_push_errstr); EXPORT_SYMBOL(skb_put_errstr); @@ -177,17 +182,10 @@ 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_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(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(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_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) || \ @@ -424,9 +421,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); diff -u --recursive --new-file v2.1.95/linux/net/rose/Makefile linux/net/rose/Makefile --- v2.1.95/linux/net/rose/Makefile Mon Apr 7 11:35:33 1997 +++ linux/net/rose/Makefile Sat Apr 11 17:18:16 1998 @@ -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) diff -u --recursive --new-file v2.1.95/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.1.95/linux/net/rose/af_rose.c Tue Mar 17 22:18:16 1998 +++ linux/net/rose/af_rose.c Sat Apr 11 17:18:16 1998 @@ -1261,7 +1261,7 @@ 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 @@ 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 @@ 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 @@ #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 @@ 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); diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c --- v2.1.95/linux/net/rose/rose_dev.c Thu Feb 12 20:56:15 1998 +++ linux/net/rose/rose_dev.c Sat Apr 11 17:18:16 1998 @@ -134,11 +134,11 @@ { 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 @@ 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 @@ MOD_DEC_USE_COUNT; - ax25_listen_release((ax25_address *)dev->dev_addr, NULL); + rose_del_loopback_node((rose_address *)dev->dev_addr); return 0; } diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_in.c linux/net/rose/rose_in.c --- v2.1.95/linux/net/rose/rose_in.c Sun Nov 30 14:00:40 1997 +++ linux/net/rose/rose_in.c Sat Apr 11 17:18:16 1998 @@ -141,10 +141,6 @@ 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 @@ 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 @@ 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 diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_link.c linux/net/rose/rose_link.c --- v2.1.95/linux/net/rose/rose_link.c Thu Feb 12 20:56:15 1998 +++ linux/net/rose/rose_link.c Sat Apr 11 17:18:16 1998 @@ -113,7 +113,7 @@ 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); } @@ -293,6 +293,11 @@ if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) { kfree_skb(skb); + return; + } + + if (neigh->loopback) { + rose_loopback_queue(skb, neigh); return; } diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_loopback.c linux/net/rose/rose_loopback.c --- v2.1.95/linux/net/rose/rose_loopback.c Wed Dec 31 16:00:00 1969 +++ linux/net/rose/rose_loopback.c Sat Apr 11 17:18:16 1998 @@ -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 +#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE) +#include +#include +#include +#include +#include +#include + +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 diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_route.c linux/net/rose/rose_route.c --- v2.1.95/linux/net/rose/rose_route.c Thu Feb 12 20:56:15 1998 +++ linux/net/rose/rose_route.c Sat Apr 11 17:18:16 1998 @@ -55,6 +55,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; @@ -299,6 +308,86 @@ } /* + * 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. */ void rose_rt_device_down(struct device *dev) @@ -723,16 +812,12 @@ 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 @@ 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); - - for (i = 0; i < rose_node->count; i++) - len += sprintf(buffer + len, " %05d", - rose_node->neighbour[i]->number); + 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); - len += sprintf(buffer + len, "\n"); + len += sprintf(buffer + len, "\n"); + } pos = begin + len; @@ -834,33 +925,35 @@ 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(); diff -u --recursive --new-file v2.1.95/linux/net/socket.c linux/net/socket.c --- v2.1.95/linux/net/socket.c Wed Apr 1 20:11:55 1998 +++ linux/net/socket.c Sat Apr 11 17:18:16 1998 @@ -547,20 +547,19 @@ return -1; switch (how) { - case 0: - kill_fasync(sock->fasync_list, SIGIO); - 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; - } + case 1: + if (sock->flags & SO_WAITDATA) break; + 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 @@ 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 @@ { 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ sk_init(); +#ifdef SLAB_SKB /* * Initialize skbuff SLAB cache */ skb_init(); +#endif + /* * Wan router layer. diff -u --recursive --new-file v2.1.95/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.1.95/linux/net/x25/af_x25.c Tue Mar 17 22:18:16 1998 +++ linux/net/x25/af_x25.c Sun Apr 12 11:42:16 1998 @@ -1118,13 +1118,14 @@ 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 @@ 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 @@ 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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/net/x25/x25_in.c linux/net/x25/x25_in.c --- v2.1.95/linux/net/x25/x25_in.c Thu Feb 12 20:56:15 1998 +++ linux/net/x25/x25_in.c Sat Apr 11 17:18:16 1998 @@ -184,11 +184,6 @@ 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 @@ 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 @@ 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 diff -u --recursive --new-file v2.1.95/linux/scripts/Configure linux/scripts/Configure --- v2.1.95/linux/scripts/Configure Wed Apr 1 20:11:55 1998 +++ linux/scripts/Configure Fri Apr 10 15:18:55 1998 @@ -53,6 +53,10 @@ # # 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 @@ 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; diff -u --recursive --new-file v2.1.95/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v2.1.95/linux/scripts/Menuconfig Wed Apr 1 20:11:55 1998 +++ linux/scripts/Menuconfig Fri Apr 10 15:16:56 1998 @@ -48,6 +48,12 @@ # 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 +# +#---------------------------------------------------------------------------- # @@ -295,7 +301,7 @@ 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."