]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.48pre3 2.1.48pre3
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:41 +0000 (15:13 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:41 +0000 (15:13 -0500)
264 files changed:
CREDITS
Documentation/Configure.help
MAINTAINERS
arch/i386/defconfig
arch/i386/kernel/smp.c
arch/m68k/Makefile
arch/m68k/amiga/amikeyb.c
arch/m68k/amiga/zorro.c
arch/m68k/boot/Makefile [deleted file]
arch/m68k/boot/amiga/bootstrap.c [deleted file]
arch/m68k/boot/amiga/bootstrap.h [deleted file]
arch/m68k/boot/amiga/linuxboot.c [deleted file]
arch/m68k/boot/amiga/linuxboot.h [deleted file]
arch/m68k/boot/atari/bootp.c [deleted file]
arch/m68k/boot/atari/bootp.h [deleted file]
arch/m68k/boot/atari/bootstrap.c [deleted file]
arch/m68k/boot/atari/bootstrap.h [deleted file]
arch/m68k/boot/atari/ethlance.c [deleted file]
arch/m68k/boot/atari/ethlance.h [deleted file]
arch/m68k/boot/atari/sysvars.h [deleted file]
arch/m68k/config.in
arch/m68k/defconfig
arch/m68k/ifpsp060/iskeleton.S
arch/m68k/kernel/console.c
arch/m68k/kernel/entry.S
arch/m68k/kernel/head.S
arch/m68k/kernel/process.c
arch/m68k/kernel/sys_m68k.c
arch/mips/config.in
arch/mips/defconfig
arch/mips/jazz/int-handler.S
arch/mips/jazz/jazzdma.c
arch/mips/jazz/setup.c
arch/mips/kernel/irixelf.c
arch/mips/kernel/syscall.c
arch/mips/kernel/syscalls.h
arch/mips/kernel/sysirix.c
arch/mips/kernel/sysmips.c
arch/mips/mm/fault.c
arch/mips/mm/init.c
arch/ppc/Makefile
arch/ppc/boot/Makefile
arch/ppc/boot/cortstrip.c [deleted file]
arch/ppc/boot/find_name.c [new file with mode: 0644]
arch/ppc/boot/gzip.h
arch/ppc/boot/head.S
arch/ppc/boot/inflate.c
arch/ppc/boot/misc.c
arch/ppc/boot/mk_type41.c [deleted file]
arch/ppc/boot/mkprep.c
arch/ppc/boot/piggyback.c [deleted file]
arch/ppc/boot/unzip.c
arch/ppc/boot/vreset.c
arch/ppc/config.in
arch/ppc/defconfig [new file with mode: 0644]
arch/ppc/ignore [new file with mode: 0644]
arch/ppc/kernel/Makefile
arch/ppc/kernel/align.c [new file with mode: 0644]
arch/ppc/kernel/bitops.c [new file with mode: 0644]
arch/ppc/kernel/checks.c [new file with mode: 0644]
arch/ppc/kernel/head.S
arch/ppc/kernel/irq.c
arch/ppc/kernel/ksyms.c
arch/ppc/kernel/misc.S
arch/ppc/kernel/mk_defs.c
arch/ppc/kernel/pci.c
arch/ppc/kernel/pmac_setup.c [new file with mode: 0644]
arch/ppc/kernel/pmac_support.c [new file with mode: 0644]
arch/ppc/kernel/pmac_time.c [new file with mode: 0644]
arch/ppc/kernel/port_io.c
arch/ppc/kernel/ppc_asm.tmpl
arch/ppc/kernel/ppc_defs.h [new file with mode: 0644]
arch/ppc/kernel/ppc_defs.head [new file with mode: 0644]
arch/ppc/kernel/prep_setup.c [new file with mode: 0644]
arch/ppc/kernel/prep_time.c [new file with mode: 0644]
arch/ppc/kernel/process.c
arch/ppc/kernel/ptrace.c
arch/ppc/kernel/setup.c [deleted file]
arch/ppc/kernel/signal.c
arch/ppc/kernel/strcase.c [new file with mode: 0644]
arch/ppc/kernel/stubs.c [deleted file]
arch/ppc/kernel/support.c [deleted file]
arch/ppc/kernel/syscalls.c
arch/ppc/kernel/time.c [deleted file]
arch/ppc/kernel/traps.c
arch/ppc/kernel/usercpy.c [deleted file]
arch/ppc/ld.script
arch/ppc/lib/Makefile
arch/ppc/lib/string.S [new file with mode: 0644]
arch/ppc/mkdiff [new file with mode: 0644]
arch/ppc/mkdist [new file with mode: 0644]
arch/ppc/mktar [new file with mode: 0644]
arch/ppc/mm/Makefile
arch/ppc/mm/extable.c [new file with mode: 0644]
arch/ppc/mm/fault.c
arch/ppc/mm/init.c
arch/ppc/prep_defconfig [new file with mode: 0644]
arch/sparc/defconfig
arch/sparc/kernel/sys_sunos.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/cpu.c
arch/sparc64/kernel/devices.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/ioctl32.c
arch/sparc64/kernel/ioport.c
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/time.c
arch/sparc64/kernel/trampoline.S [new file with mode: 0644]
arch/sparc64/lib/locks.S
arch/sparc64/mm/Makefile
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
arch/sparc64/prom/console.c
arch/sparc64/prom/misc.c
arch/sparc64/prom/p1275.c
drivers/block/acsi.c
drivers/block/acsi_slm.c
drivers/char/Config.in
drivers/char/Makefile
drivers/char/fbmem.c
drivers/char/keyboard.c
drivers/char/mem.c
drivers/char/misc.c
drivers/char/nvram.c [new file with mode: 0644]
drivers/char/pc110pad.c
drivers/char/pc110pad.h
drivers/char/pc_keyb.c
drivers/char/pc_keyb.h
drivers/char/psaux.c
drivers/char/sysrq.c
drivers/char/vga.c
drivers/net/myri_sbus.c
drivers/net/plip.c
drivers/net/soundmodem/sm_sbc.c
drivers/net/soundmodem/sm_wss.c
drivers/sbus/char/Makefile
drivers/sbus/char/creator.c
drivers/sbus/char/suncons.c
drivers/sbus/char/tcx.c
drivers/sbus/char/weitek.c
drivers/sbus/sbus.c
drivers/scsi/53c7,8xx.c
drivers/scsi/53c7,8xx.h
drivers/scsi/Makefile
drivers/scsi/README.aic7xxx
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx.h
drivers/scsi/aic7xxx.seq [deleted file]
drivers/scsi/aic7xxx/aic7xxx.reg [new file with mode: 0644]
drivers/scsi/aic7xxx/aic7xxx.seq [new file with mode: 0644]
drivers/scsi/aic7xxx/scsi_message.h [new file with mode: 0644]
drivers/scsi/aic7xxx/sequencer.h [new file with mode: 0644]
drivers/scsi/aic7xxx_asm.c [deleted file]
drivers/scsi/aic7xxx_proc.c
drivers/scsi/aic7xxx_reg.h
drivers/scsi/atari_scsi.c
drivers/scsi/esp.c
fs/autofs/autofs_i.h
fs/autofs/dir.c
fs/autofs/inode.c
fs/autofs/root.c
fs/autofs/symlink.c
fs/buffer.c
fs/devices.c
fs/fat/cache.c
fs/fat/misc.c
fs/inode.c
fs/proc/array.c
fs/proc/openpromfs.c
fs/proc/root.c
fs/romfs/inode.c
fs/super.c
fs/ufs/ufs_namei.c
include/asm-alpha/keyboard.h
include/asm-i386/keyboard.h
include/asm-i386/smp_lock.h
include/asm-m68k/serial.h
include/asm-mips/byteorder.h
include/asm-mips/ioctls.h
include/asm-mips/jazz.h
include/asm-mips/jazzdma.h
include/asm-mips/pgtable.h
include/asm-mips/system.h
include/asm-mips/unistd.h
include/asm-ppc/atomic.h
include/asm-ppc/bitops.h
include/asm-ppc/bugs.h
include/asm-ppc/byteorder.h
include/asm-ppc/cache.h
include/asm-ppc/checksum.h
include/asm-ppc/current.h
include/asm-ppc/delay.h
include/asm-ppc/dma.h
include/asm-ppc/errno.h
include/asm-ppc/hardirq.h [new file with mode: 0644]
include/asm-ppc/ide.h
include/asm-ppc/init.h
include/asm-ppc/io.h
include/asm-ppc/ioctls.h
include/asm-ppc/irq.h
include/asm-ppc/keyboard.h
include/asm-ppc/mc146818rtc.h [deleted file]
include/asm-ppc/mmu.h
include/asm-ppc/mmu_context.h
include/asm-ppc/namei.h [new file with mode: 0644]
include/asm-ppc/nvram.h
include/asm-ppc/page.h
include/asm-ppc/pgtable.h
include/asm-ppc/poll.h [new file with mode: 0644]
include/asm-ppc/ppc_machine.h [deleted file]
include/asm-ppc/processor.h
include/asm-ppc/ptrace.h
include/asm-ppc/semaphore.h
include/asm-ppc/smp.h
include/asm-ppc/smp_lock.h [new file with mode: 0644]
include/asm-ppc/socket.h
include/asm-ppc/softirq.h [new file with mode: 0644]
include/asm-ppc/spinlock.h [new file with mode: 0644]
include/asm-ppc/string.h
include/asm-ppc/system.h
include/asm-ppc/termbits.h
include/asm-ppc/termios.h
include/asm-ppc/uaccess.h
include/asm-ppc/unistd.h
include/asm-sparc/fbio.h
include/asm-sparc/smp.h
include/asm-sparc64/oplib.h
include/asm-sparc64/pgtable.h
include/asm-sparc64/semaphore.h
include/asm-sparc64/smp.h
include/asm-sparc64/smp_lock.h
include/asm-sparc64/softirq.h
include/asm-sparc64/spinlock.h
include/asm-sparc64/system.h
include/asm-sparc64/timer.h [new file with mode: 0644]
include/linux/dcache.h
include/linux/fs.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/msdos_fs.h
include/linux/msdos_fs_sb.h
include/linux/nvram.h [new file with mode: 0644]
include/linux/proc_fs.h
include/linux/selection.h
include/linux/sysrq.h
lib/vsprintf.c
mm/filemap.c
mm/simp.c
net/Changes
net/ax25/ax25_ip.c
net/ax25/ax25_route.c
net/core/dev.c
net/ipv4/proc.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c

diff --git a/CREDITS b/CREDITS
index c903f985a68d343624d0e65053254f7aaf39aa91..616d29e2be3c3e47467eb1a411240f7f00e1e308 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -335,6 +335,15 @@ S: Rue de la Chapelle 51
 S: 4850 Moresnet
 S: Belgium
 
+N: Cort Dougan
+E: cort@cs.nmt.edu
+W: http://www.cs.nmt.edu/~cort/
+D: PowerPC PReP port
+S: Computer Science Department
+S: New Mexico Tech
+S: Socorro NM 87801
+S: USA
+
 N: Thomas Dunbar
 E: tdunbar@vtaix.cc.vt.edu
 D: TeX & METAFONT hacking/maintenance
@@ -912,6 +921,14 @@ N: Peter MacDonald
 D: SLS distribution
 D: Initial implementation of VC's, pty's and select()
 
+N: Paul Mackerras
+E: paulus@cs.anu.edu.au
+D: Linux port for PCI Power Macintosh
+S: Dept. of Computer Science
+S: Australian National University
+S: Canberra  ACT  0200
+S: AUSTRALIA
+
 N: James B. MacLean
 E: macleajb@ednet.ns.ca
 W: http://www.ednet.ns.ca/~macleajb/dosemu.html
index f3fcc31f067051a429b387476bbd09b88b1c3dc5..bd1cdeeb0efb7b9afeeb354e265a45501eacda35 100644 (file)
@@ -4646,6 +4646,18 @@ CONFIG_RTC
   have a use for such a device (such as periodic data sampling), then
   say Y here, and go read the file Documentation/rtc.txt for details.
 
+/dev/nvram support
+CONFIG_NVRAM
+  If you say Y here and create a character special file /dev/nvram
+  with major number 10 and minor number 144 using mknod ("man mknod"),
+  you get access to the non-volatile memory in the real time clock
+  (RTC). This is conventionally called "CMOS RAM" on PCs and "NVRAM"
+  on Ataris. /dev/nvram may be used to view settings there, or to
+  change them (with some utility). It could also be used to frequently
+  save a few bits of very important data, that may not be lost over
+  power-off and for which writing to disk is too insecure. On Atari
+  machines, /dev/nvram is always configured and needs not be selected.
+
 ARC console time
 CONFIG_RTC_ARC
   If you boot your Alpha using the ARC firmware, say Y here. This option
index d0d12290c12072ce0d7723c6810b23cb325c13e6..e6764e5c139f36cbdba863733a37c21fbf8110be 100644 (file)
@@ -452,6 +452,18 @@ W: http://www.cyberelk.demon.co.uk/parport.html
 W:     http://www.cage.curtin.edu.au/~campbell/parbus/
 S:     Maintained
 
+LINUX FOR POWERPC (PREP)
+P:     Cort Dougan
+M:     cort@cs.nmt.edu
+W:     http://www.cs.nmt.edu/~linuxppc/
+S:     Maintained
+
+LINUX FOR POWER MACINTOSH
+P:     Paul Mackerras
+M:     paulus@cs.anu.edu.au
+L:     linux-pmac@samba.anu.edu.au
+S:     Maintained
+
 FPU EMULATOR
 P:     Bill Metzenthen
 M:     billm@suburbia.net
index 2265ac20fa2a97a7c7de49315bb03d081666e378..e3e50886cfccdd304f6236f2ec38051b775f2f7a 100644 (file)
@@ -236,6 +236,7 @@ CONFIG_82C710_MOUSE=y
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
 # CONFIG_JOYSTICK is not set
 
 #
index 5a020b7235512c07913bf107a0137a3011494acd..d187128e10d9cf2a9586927295c036bd4ad41b80 100644 (file)
@@ -156,6 +156,9 @@ volatile unsigned long smp_idle_map=0;                      /* Map for idle processors                              */
 volatile unsigned long  smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
 volatile int smp_process_available=0;
 
+const char lk_lockmsg[] = "lock from interrupt context at %p\n"; 
+
+
 /*#define SMP_DEBUG*/
 
 #ifdef SMP_DEBUG
index 7548a8dc8ba744ae9c7a263c2a576a47d293025b..94257b578f0477338357178c44c47963fe23e971 100644 (file)
@@ -79,8 +79,6 @@ CORE_FILES := $(CORE_FILES) arch/m68k/ifpsp060/ifpsp.o
 SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060
 endif
 
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-
 lilo:  vmlinux
        if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
        if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
@@ -106,7 +104,5 @@ bootstrap: dummy
 
 archclean:
        rm -f vmlinux.gz
-       @$(MAKEBOOT) clean
 
 archdep:
-       $(MAKEBOOT) dep
index 06fe55d29202919598bd63d92366623b27502312..5a102a12cf90458ab8b3a83f879fe4fa6019247d 100644 (file)
@@ -195,7 +195,7 @@ static void amikeyb_rep(unsigned long ignore)
 
 static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
-    unsigned char scancode, break_flag;
+    unsigned char scancode, break_flag, keycode;
     static int reset_warning = 0;
 
     /* save frame for register dump */
@@ -207,6 +207,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
     /* switch SP pin to output for handshake */
     ciaa.cra |= 0x40;
 
+#if 0 // No longer used
     /*
      *  On receipt of the second RESET_WARNING, we must not pull KDAT high
      *  again to delay the hard reset as long as possible.
@@ -222,6 +223,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
        } else
            /* Probably a mistake, cancel the alert */
            reset_warning = 0;
+#endif
 
     /* wait until 85 us have expired */
     udelay(85);
@@ -237,27 +239,27 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
      * Check make/break first
      */
     break_flag = scancode & BREAK_MASK;
-    scancode &= (unsigned char )~BREAK_MASK;
+    keycode = scancode & (unsigned char)~BREAK_MASK;
 
-    if (scancode == AMIKEY_CAPS) {
+    if (keycode == AMIKEY_CAPS) {
        /* if the key is CAPS, fake a press/release. */
        handle_scancode(AMIKEY_CAPS);
        handle_scancode(BREAK_MASK | AMIKEY_CAPS);
-    } else if (scancode < 0x78) {
+    } else if (keycode < 0x78) {
        /* handle repeat */
        if (break_flag) {
            del_timer(&amikeyb_rep_timer);
            rep_scancode = 0;
        } else {
            del_timer(&amikeyb_rep_timer);
-           rep_scancode = scancode;
+           rep_scancode = keycode;
            amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
            amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
            add_timer(&amikeyb_rep_timer);
        }
-       handle_scancode(break_flag | scancode);
+       handle_scancode(scancode);
     } else
-       switch (scancode) {
+       switch (keycode) {
            case 0x78:
                reset_warning = 1;
                break;
@@ -288,7 +290,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
 #endif
            default:
                printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
-                      break_flag | scancode);
+                      scancode);
                break;
        }
 }
index d64ad8ce39b032144e8102fcbaae13ab45b73c65..1da9481348302b88f5dfafaa7a446e25ddf8466a 100644 (file)
@@ -730,7 +730,7 @@ int zorro_find(int manuf, int prod, int part, int index)
 {
    int key;
    struct ConfigDev *cd;
-  
+
    if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
       return(0);
 
diff --git a/arch/m68k/boot/Makefile b/arch/m68k/boot/Makefile
deleted file mode 100644 (file)
index 822030e..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# linux/arch/m68k/boot/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-
-ifdef CONFIG_AMIGA
-AMIGA_BOOTSTRAP = amiga_bootstrap
-AMIGA_BOOTOBJS := amiga/bootstrap.o amiga/linuxboot.o
-AMIGA_HOSTCC = m68k-cbm-amigados-gcc
-AMIGA_HOSTINC = -I$(TOPDIR)/include
-AMIGA_HOSTFLAGS=-m68030 -O2 -Wall -Dlinux
-endif
-
-ifdef CONFIG_ATARI
-ATARI_BOOTSTRAP = atari_bootstrap
-ATARI_BOOTOBJS := atari/bootstrap.o
-ATARI_HOSTCC = m68k-mint-gcc
-ATARI_HOSTINC = -I$(TOPDIR)/include
-ATARI_HOSTFLAGS = -m68030 -m68881 -Dlinux -O2 -Wall
-
-# BOOTP/TFTP support in bootstrap?
-# USE_BOOTP = y
-
-ifdef USE_BOOTP
-ATARI_BOOTOBJS += atari/bootp.o
-ATARI_HOSTFLAGS += -DUSE_BOOTP
-
-# low-level Ethernet drivers:
-
-# Lance (RieblCard, PAM-VME)
-ATARI_BOOTOBJS += atari/ethlance.o
-ATARI_HOSTFLAGS += -DETHLL_LANCE
-
-endif
-endif
-
-ifdef CONFIG_ATARI
-atari_bootstrap: $(ATARI_BOOTOBJS)
-       $(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
-       rm -f ../../../bootstrap
-       ln $@ ../../../bootstrap
-endif
-
-ifdef CONFIG_AMIGA
-amiga_bootstrap: $(AMIGA_BOOTOBJS)
-       $(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -o $@ -s -noixemul $(AMIGA_BOOTOBJS)
-       rm -f ../../../bootstrap
-       ln $@ ../../../bootstrap
-endif
-
-$(AMIGA_BOOTOBJS): %.o: %.c
-       $(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -c $< -o $@
-
-$(ATARI_BOOTOBJS): %.o: %.c
-       $(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -c $< -o $@
-
-bootstrap: $(AMIGA_BOOTSTRAP) $(ATARI_BOOTSTRAP)
-
-clean:
-       rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap \
-          ../../../bootstrap
-
-dep:
diff --git a/arch/m68k/boot/amiga/bootstrap.c b/arch/m68k/boot/amiga/bootstrap.c
deleted file mode 100644 (file)
index 41ac75a..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
-** linux/arch/m68k/boot/amiga/bootstrap.c -- This program loads the Linux/m68k
-**                                          kernel into an Amiga and launches
-**                                          it.
-**
-** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
-**
-** Modified 11-May-94 by Geert Uytterhoeven
-**                     (Geert.Uytterhoeven@cs.kuleuven.ac.be)
-**     - A3640 MapROM check
-** Modified 31-May-94 by Geert Uytterhoeven
-**     - Memory thrash problem solved
-** Modified 07-March-95 by Geert Uytterhoeven
-**     - Memory block sizes are rounded to a multiple of 256K instead of 1M
-**      This _requires_ >0.9pl5 to work!
-**      (unless all block sizes are multiples of 1M :-)
-** Modified 11-July-95 by Andreas Schwab
-**     - Support for ELF kernel (untested!)
-** Modified 10-Jan-96 by Geert Uytterhoeven
-**     - The real Linux/m68k boot code moved to linuxboot.[ch]
-** Modified 9-Sep-96 by Geert Uytterhoeven
-**     - Rewritten option parsing
-**     - New parameter passing to linuxboot() (linuxboot_args)
-** Modified 6-Oct-96 by Geert Uytterhoeven
-**     - Updated for the new boot information structure
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/file.h>
-#include <unistd.h>
-
-/* required Linux/m68k include files */
-#define __KERNEL_STRICT_NAMES          /* This is ugly, I know */
-#define _LINUX_POSIX_TYPES_H
-#include <asm/posix_types.h>
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <asm/amigahw.h>
-#include <asm/page.h>
-
-/* Amiga bootstrap include files */
-#include "linuxboot.h"
-#include "bootstrap.h"
-
-
-/* Library Bases */
-long __oslibversion = 36;
-extern const struct ExecBase *SysBase;
-
-static const char *memfile_name = NULL;
-
-static int model = AMI_UNKNOWN;
-
-static const char *ProgramName;
-
-struct linuxboot_args args;
-
-
-    /*
-     *  Function Prototypes
-     */
-
-static void Usage(void) __attribute__ ((noreturn));
-int main(int argc, char *argv[]);
-static void Puts(const char *str);
-static long GetChar(void);
-static void PutChar(char c);
-static void Printf(const char *fmt, ...);
-static int Open(const char *path);
-static int Seek(int fd, int offset);
-static int Read(int fd, char *buf, int count);
-static void Close(int fd);
-static int FileSize(const char *path);
-static void Sleep(u_long micros);
-
-
-static void Usage(void)
-{
-    fprintf(stderr,
-       "Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n"
-       "Usage: %s [options] [kernel command line]\n\n"
-       "Basic options:\n"
-       "    -h, --help           Display this usage information\n"
-       "    -k, --kernel file    Use kernel image `file' (default is `vmlinux')\n"
-       "    -r, --ramdisk file   Use ramdisk image `file'\n"
-       "Advanced options:\n"
-       "    -d, --debug          Enable debug mode\n"
-       "    -b, --baud speed     Set the serial port speed (default is 9600)\n"
-       "    -m, --memfile file   Use memory file `file'\n"
-       "    -v, --keep-video     Don't reset the video mode\n"
-       "    -t, --model id       Set the Amiga model to `id'\n"
-       "    -p, --processor cfm  Set the processor type to `cfm\n\n",
-       ProgramName);
-    exit(EXIT_FAILURE);
-}
-
-
-int main(int argc, char *argv[])
-{
-    int i;
-    int processor = 0, debugflag = 0, keep_video = 0;
-    u_int baud = 0;
-    const char *kernel_name = NULL;
-    const char *ramdisk_name = NULL;
-    char commandline[CL_SIZE] = "";
-
-    ProgramName = argv[0];
-    while (--argc) {
-       argv++;
-       if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help"))
-           Usage();
-       else if (!strcmp(argv[0], "-k") || !strcmp(argv[0], "--kernel"))
-           if (--argc && !kernel_name) {
-               kernel_name = argv[1];
-               argv++;
-           } else
-               Usage();
-       else if (!strcmp(argv[0], "-r") || !strcmp(argv[0], "--ramdisk"))
-           if (--argc && !ramdisk_name) {
-               ramdisk_name = argv[1];
-               argv++;
-           } else
-               Usage();
-       else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--debug"))
-           debugflag = 1;
-       else if (!strcmp(argv[0], "-b") || !strcmp(argv[0], "--baud"))
-           if (--argc && !baud) {
-               baud = atoi(argv[1]);
-               argv++;
-           } else
-               Usage();
-       else if (!strcmp(argv[0], "-m") || !strcmp(argv[0], "--memfile"))
-           if (--argc && !memfile_name) {
-               memfile_name = argv[1];
-               argv++;
-           } else
-               Usage();
-       else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--keep-video"))
-           keep_video = 1;
-       else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--model"))
-           if (--argc && !model) {
-               model = atoi(argv[1]);
-               argv++;
-           } else
-               Usage();
-       else if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--processor"))
-           if (--argc && !processor) {
-               processor = atoi(argv[1]);
-               argv++;
-           } else
-               Usage();
-       else
-           break;
-    }
-    if (!kernel_name)
-       kernel_name = "vmlinux";
-
-    SysBase = *(struct ExecBase **)4;
-
-    /*
-     * Join command line options
-     */
-    i = 0;
-    while (argc--) {
-       if ((i+strlen(*argv)+1) < CL_SIZE) {
-           i += strlen(*argv) + 1;
-           if (commandline[0])
-               strcat(commandline, " ");
-           strcat(commandline, *argv++);
-       }
-    }
-
-    memset(&args.bi, 0, sizeof(args.bi));
-    if (processor) {
-       int cpu = processor/100%10;
-       int fpu = processor/10%10;
-       int mmu = processor%10;
-       if (cpu)
-           args.bi.cputype = 1<<(cpu-1);
-       if (fpu)
-           args.bi.fputype = 1<<(fpu-1);
-       if (mmu)
-           args.bi.mmutype = 1<<(mmu-1);
-    }
-    /*
-     * If we have a memory file, read the memory information from it
-     */
-    if (memfile_name) {
-       FILE *fp;
-       int i;
-
-       if ((fp = fopen(memfile_name, "r")) == NULL) {
-           perror("open memory file");
-           fprintf(stderr, "Cannot open memory file %s\n", memfile_name);
-           return(FALSE);
-       }
-
-       if (fscanf(fp, "%lu", &args.bi.chip_size) != 1) {
-           fprintf(stderr, "memory file does not contain chip memory size\n");
-           fclose(fp);
-           return(FALSE);
-       }
-
-       for (i = 0; i < NUM_MEMINFO; i++)
-           if (fscanf(fp, "%lx %lu", &args.bi.memory[i].addr,
-                      &args.bi.memory[i].size) != 2)
-               break;
-
-       fclose(fp);
-       args.bi.num_memory = i;
-    }
-    strncpy(args.bi.command_line, commandline, CL_SIZE);
-    args.bi.command_line[CL_SIZE-1] = '\0';
-    if (model != AMI_UNKNOWN)
-       args.bi.model = model;
-
-    args.kernelname = kernel_name;
-    args.ramdiskname = ramdisk_name;
-    args.debugflag = debugflag;
-    args.keep_video = keep_video;
-    args.reset_boards = 1;
-    args.baud = baud;
-    args.puts = Puts;
-    args.getchar = GetChar;
-    args.putchar = PutChar;
-    args.printf = Printf;
-    args.open = Open;
-    args.seek = Seek;
-    args.read = Read;
-    args.close = Close;
-    args.filesize = FileSize;
-    args.sleep = Sleep;
-
-    /* Do The Right Stuff */
-    linuxboot(&args);
-
-    /* if we ever get here, something went wrong */
-    exit(EXIT_FAILURE);
-}
-
-
-    /*
-     *  Routines needed by linuxboot
-     */
-
-static void Puts(const char *str)
-{
-    fputs(str, stderr);
-    fflush(stderr);
-}
-
-static long GetChar(void)
-{
-    return(getchar());
-}
-
-static void PutChar(char c)
-{
-    fputc(c, stderr);
-    fflush(stderr);
-}
-
-static void Printf(const char *fmt, ...)
-{
-    va_list args;
-
-    va_start(args, fmt);
-    vfprintf(stderr, fmt, args);
-    va_end(args);
-    fflush(stderr);
-}
-
-static int Open(const char *path)
-{
-    return(open(path, O_RDONLY));
-}
-
-static int Seek(int fd, int offset)
-{
-    return(lseek(fd, offset, SEEK_SET));
-}
-
-
-static int Read(int fd, char *buf, int count)
-{
-    return(read(fd, buf, count));
-}
-
-static void Close(int fd)
-{
-    close(fd);
-}
-
-static int FileSize(const char *path)
-{
-    int fd, size = -1;
-
-    if ((fd = open(path, O_RDONLY)) != -1) {
-       size = lseek(fd, 0, SEEK_END);
-       close(fd);
-    }
-    return(size);
-}
-
-static void Sleep(u_long micros)
-{
-    struct MsgPort *TimerPort;
-    struct timerequest *TimerRequest;
-
-    if ((TimerPort = CreateMsgPort())) {
-       if ((TimerRequest = CreateIORequest(TimerPort,
-                                           sizeof(struct timerequest)))) {
-           if (!OpenDevice("timer.device", UNIT_VBLANK,
-                           (struct IORequest *)TimerRequest, 0)) {
-               TimerRequest->io_Command = TR_ADDREQUEST;
-               TimerRequest->io_Flags = IOF_QUICK;
-               TimerRequest->tv_secs = micros/1000000;
-               TimerRequest->tv_micro = micros%1000000;
-               DoIO((struct IORequest *)TimerRequest);
-               CloseDevice((struct IORequest *)TimerRequest);
-           }
-           DeleteIORequest(TimerRequest);
-       }
-       DeleteMsgPort(TimerPort);
-    }
-}
diff --git a/arch/m68k/boot/amiga/bootstrap.h b/arch/m68k/boot/amiga/bootstrap.h
deleted file mode 100644 (file)
index 4d072cc..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
-** linux/arch/m68k/boot/amiga/bootstrap.h -- This file is part of the Amiga
-**                                          bootloader.
-**
-** Copyright 1993, 1994 by Hamish Macdonald
-**
-** Some minor additions by Michael Rausch 1-11-94
-** Modified 11-May-94 by Geert Uytterhoeven
-**                     (Geert.Uytterhoeven@cs.kuleuven.ac.be)
-**     - inline Supervisor() call
-** Modified 10-Jan-96 by Geert Uytterhoeven
-**     - The real Linux/m68k boot code moved to linuxboot.[ch]
-** Modified 9-Sep-96 by Geert Uytterhoeven
-**     - const library bases
-**     - fixed register naming for m68k-cbm-amigados-gcc
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-
-struct MsgPort {
-    u_char fill1[15];
-    u_char mp_SigBit;
-    u_char fill2[18];
-};
-
-struct IOStdReq {
-    u_char fill1[20];
-    struct Device *io_Device;
-    u_char fill2[4];
-    u_short io_Command;
-    u_char io_Flags;
-    char io_Error;
-    u_long io_Actual;
-    u_long io_Length;
-    void *io_Data;
-    u_char fill4[4];
-};
-
-#define IOF_QUICK      (1<<0)
-
-struct timerequest {
-    u_char fill1[28];
-    u_short io_Command;
-    u_char io_Flags;
-    u_char fill2[1];
-    u_long tv_secs;
-    u_long tv_micro;
-};
-
-#define UNIT_VBLANK    1
-#define TR_ADDREQUEST  9
-
-
-struct Library;
-struct IORequest;
-
-
-static __inline char OpenDevice(u_char *devName, u_long unit,
-                               struct IORequest *ioRequest, u_long flags)
-{
-    register char _res __asm("d0");
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register u_char *a0 __asm("a0") = devName;
-    register u_long d0 __asm("d0") = unit;
-    register struct IORequest *a1 __asm("a1") = ioRequest;
-    register u_long d1 __asm("d1") = flags;
-
-    __asm __volatile ("jsr a6@(-0x1bc)"
-                     : "=r" (_res)
-                     : "r" (a6), "r" (a0), "r" (a1), "r" (d0), "r" (d1)
-                     : "a0","a1","d0","d1", "memory");
-    return(_res);
-}
-
-static __inline void CloseDevice(struct IORequest *ioRequest)
-{
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register struct IORequest *a1 __asm("a1") = ioRequest;
-
-    __asm __volatile ("jsr a6@(-0x1c2)"
-                     : /* no output */
-                     : "r" (a6), "r" (a1)
-                     : "a0","a1","d0","d1", "memory");
-}
-
-static __inline char DoIO(struct IORequest *ioRequest)
-{
-    register char _res __asm("d0");
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register struct IORequest *a1 __asm("a1") = ioRequest;
-
-    __asm __volatile ("jsr a6@(-0x1c8)"
-                     : "=r" (_res)
-                     : "r" (a6), "r" (a1)
-                     : "a0","a1","d0","d1", "memory");
-    return(_res);
-}
-
-static __inline void *CreateIORequest(struct MsgPort *port, u_long size)
-{
-    register struct Library *_res __asm("d0");
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register struct MsgPort *a0 __asm("a0") = port;
-    register u_long d0 __asm("d0") = size;
-
-    __asm __volatile ("jsr a6@(-0x28e)"
-                     : "=r" (_res)
-                     : "r" (a6), "r" (a0), "r" (d0)
-                     : "a0","a1","d0","d1", "memory");
-    return(_res);
-}
-
-static __inline void DeleteIORequest(void *ioRequest)
-{
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register void *a0 __asm("a0") = ioRequest;
-
-    __asm __volatile ("jsr a6@(-0x294)"
-                     : /* no output */
-                     : "r" (a6), "r" (a0)
-                     : "a0","a1","d0","d1", "memory");
-}
-
-static __inline struct MsgPort *CreateMsgPort(void)
-{
-    register struct MsgPort *_res __asm("d0");
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-
-    __asm __volatile ("jsr a6@(-0x29a)"
-                     : "=r" (_res)
-                     : "r" (a6)
-                     : "a0","a1","d0","d1", "memory");
-    return(_res);
-}
-
-static __inline void DeleteMsgPort(struct MsgPort *port)
-{
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register struct MsgPort *a0 __asm("a0") = port;
-
-    __asm __volatile ("jsr a6@(-0x2a0)"
-                     : /* no output */
-                     : "r" (a6), "r" (a0)
-                     : "a0","a1","d0","d1", "memory");
-}
diff --git a/arch/m68k/boot/amiga/linuxboot.c b/arch/m68k/boot/amiga/linuxboot.c
deleted file mode 100644 (file)
index 74b873b..0000000
+++ /dev/null
@@ -1,1692 +0,0 @@
-/*
- *  linux/arch/m68k/boot/amiga/linuxboot.c -- Generic routine to boot Linux/m68k
- *                                           on Amiga, used by both Amiboot and
- *                                           Amiga-Lilo.
- *
- *     Created 1996 by Geert Uytterhoeven
- *
- *
- *  This file is based on the original bootstrap code (bootstrap.c):
- *
- *     Copyright (C) 1993, 1994 Hamish Macdonald
- *                              Greg Harp
- *
- *                 with work by Michael Rausch
- *                              Geert Uytterhoeven
- *                              Frank Neumann
- *                              Andreas Schwab
- *
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive
- *  for more details.
- *
- *  History:
- *     11 Jun 1997 Fix for unpadded gzipped ramdisks with bootinfo interface
- *                 version 1.0
- *     27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo
- *                 interface version 1.0 (Geert)
- *      3 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
- *                 code for ataboot)
- *     30 Dec 1996 Reverted the CPU detection to the old scheme
- *                 New boot parameter override scheme (Geert)
- *      27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
- *       9 Sep 1996 Rewritten option parsing
- *                 New parameter passing to linuxboot() (linuxboot_args)
- *                 (Geert)
- *     18 Aug 1996 Updated for the new boot information structure (Geert)
- *     10 Jan 1996 The real Linux/m68k boot code moved to linuxboot.[ch]
- *                 (Geert)
- *     11 Jul 1995 Support for ELF kernel (untested!) (Andreas)
- *      7 Mar 1995 Memory block sizes are rounded to a multiple of 256K
- *                 instead of 1M (Geert)
- *     31 May 1994 Memory thrash problem solved (Geert)
- *     11 May 1994 A3640 MapROM check (Geert)
- */
-
-
-#ifndef __GNUC__
-#error GNU CC is required to compile this program
-#endif /* __GNUC__ */
-
-
-#define BOOTINFO_COMPAT_1_0    /* bootinfo interface version 1.0 compatible */
-/* support compressed kernels? */
-#define ZKERNEL
-
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <linux/linkage.h>
-#include <asm/bootinfo.h>
-#include <asm/amigahw.h>
-#include <asm/page.h>
-
-#include "linuxboot.h"
-
-
-#undef custom
-#define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
-
-/* a.out linkage conventions */
-#undef SYMBOL_NAME_STR
-#define SYMBOL_NAME_STR(X) "_"#X
-
-/* temporary stack size */
-#define TEMP_STACKSIZE (256)
-
-#define DEFAULT_BAUD   (9600)
-
-extern char copyall, copyallend;
-
-static struct exec kexec;
-static Elf32_Ehdr kexec_elf;
-static const struct linuxboot_args *linuxboot_args;
-
-/* Bootinfo */
-struct amiga_bootinfo bi;
-
-#ifdef BOOTINFO_COMPAT_1_0
-static struct compat_bootinfo compat_bootinfo;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-#define MAX_BI_SIZE    (4096)
-static u_long bi_size;
-static union {
-    struct bi_record record;
-    u_char fake[MAX_BI_SIZE];
-} bi_union;
-
-#define kernelname     linuxboot_args->kernelname
-#define ramdiskname    linuxboot_args->ramdiskname
-#define debugflag      linuxboot_args->debugflag
-#define keep_video     linuxboot_args->keep_video
-#define reset_boards   linuxboot_args->reset_boards
-#define baud           linuxboot_args->baud
-
-#define Puts           linuxboot_args->puts
-#define GetChar                linuxboot_args->getchar
-#define PutChar                linuxboot_args->putchar
-#define Printf         linuxboot_args->printf
-#define Open           linuxboot_args->open
-#define Seek           linuxboot_args->seek
-#define Read           linuxboot_args->read
-#define Close          linuxboot_args->close
-#define FileSize       linuxboot_args->filesize
-#define Sleep          linuxboot_args->sleep
-
-    /*
-     *  Function Prototypes
-     */
-
-static u_long get_chipset(void);
-static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu);
-static u_long get_model(u_long chipset);
-static int probe_resident(const char *name);
-static int probe_resource(const char *name);
-static int create_bootinfo(void);
-#ifdef BOOTINFO_COMPAT_1_0
-static int create_compat_bootinfo(void);
-#endif /* BOOTINFO_COMPAT_1_0 */
-static int add_bi_record(u_short tag, u_short size, const void *data);
-static int add_bi_string(u_short tag, const u_char *s);
-static int check_bootinfo_version(const char *memptr);
-static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
-                        u_long start_mem, u_long kernel_size, u_long rd_dest,
-                        u_long rd_size) __attribute__ ((noreturn));
-asmlinkage u_long maprommed(void);
-#ifdef ZKERNEL
-static int load_zkernel(int fd);
-static int KRead(int fd, void *buf, int cnt);
-static int KSeek(int fd, int offset);
-static int KClose(int fd);
-#else
-#define KRead          Read
-#define KSeek          Seek
-#define KClose         Close
-#endif
-
-
-    /*
-     * Reset functions for nasty Zorro boards
-     */
-
-static void reset_rb3(const struct ConfigDev *cd);
-static void reset_piccolo(const struct ConfigDev *cd);
-static void reset_sd64(const struct ConfigDev *cd);
-static void reset_ariadne(const struct ConfigDev *cd);
-static void reset_hydra(const struct ConfigDev *cd);
-#if 0
-static void reset_a2060(const struct ConfigDev *cd);
-#endif
-
-struct boardreset {
-    u_short manuf;
-    u_short prod;
-    const char *name;
-    void (*reset)(const struct ConfigDev *cd);
-};
-
-static struct boardreset boardresetdb[] = {
-    { MANUF_HELFRICH1, PROD_RAINBOW3, "Rainbow 3", reset_rb3 },
-    { MANUF_HELFRICH2, PROD_PICCOLO_REG, "Piccolo", reset_piccolo },
-    { MANUF_HELFRICH2, PROD_SD64_REG, "SD64", reset_sd64 },
-    { MANUF_VILLAGE_TRONIC, PROD_ARIADNE, "Ariadne", reset_ariadne },
-    { MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, "Hydra", reset_hydra },
-#if 0
-    { MANUF_COMMODORE, PROD_A2060, "A2060", reset_a2060 },
-#endif
-};
-#define NUM_BOARDRESET sizeof(boardresetdb)/sizeof(*boardresetdb)
-
-static void (*boardresetfuncs[ZORRO_NUM_AUTO])(const struct ConfigDev *cd);
-
-
-const char *amiga_models[] = {
-    "Amiga 500", "Amiga 500+", "Amiga 600", "Amiga 1000", "Amiga 1200",
-    "Amiga 2000", "Amiga 2500", "Amiga 3000", "Amiga 3000T", "Amiga 3000+",
-    "Amiga 4000", "Amiga 4000T", "CDTV", "CD32", "Draco"
-};
-const u_long first_amiga_model = AMI_500;
-const u_long last_amiga_model = AMI_DRACO;
-
-
-#define MASK(model)    (1<<AMI_##model)
-
-#define CLASS_A3000    (MASK(3000) | MASK(3000T))
-#define CLASS_A4000    (MASK(4000) | MASK(4000T))
-#define CLASS_ZKICK    (MASK(500) | MASK(1000) | MASK(2000) | MASK(2500))
-
-
-    /*
-     * Boot the Linux/m68k Operating System
-     */
-
-u_long linuxboot(const struct linuxboot_args *args)
-{
-    int kfd = -1, rfd = -1, elf_kernel = 0, do_fast, do_chip;
-    int i, j;
-    const struct MemHeader *mnp;
-    struct ConfigDev *cdp = NULL;
-    char *memptr = NULL;
-    u_long *stack = NULL;
-    u_long fast_total, model_mask, startcodesize, start_mem, mem_size, rd_size;
-    u_long kernel_size;
-    u_int realbaud;
-    u_long memreq = 0, text_offset = 0;
-    Elf32_Phdr *kernel_phdrs = NULL;
-    void (*startfunc)(void);
-    u_short manuf;
-    u_char prod;
-    void *bi_ptr;
-
-    linuxboot_args = args;
-
-    /* print the greet message */
-    Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n");
-    Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n");
-
-    /* Note: Initial values in bi override detected values */
-    bi = args->bi;
-
-    /* machine is Amiga */
-    bi.machtype = MACH_AMIGA;
-
-    /* determine chipset */
-    if (!bi.chipset)
-       bi.chipset = get_chipset();
-
-    /* determine CPU, FPU and MMU type */
-    if (!bi.cputype)
-       get_processor(&bi.cputype, &bi.fputype, &bi.mmutype);
-
-    /* determine Amiga model */
-    if (!bi.model)
-       bi.model = get_model(bi.chipset);
-    model_mask = (bi.model != AMI_UNKNOWN) ? 1<<bi.model : 0;
-
-    /* Memory & AutoConfig based on 'unix_boot.c' by C= */
-
-    /* find all of the autoconfig boards in the system */
-    if (!bi.num_autocon)
-       for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++)
-           if (bi.num_autocon < ZORRO_NUM_AUTO)
-               /* copy the contents of each structure into our boot info and
-                  count this device */
-               memcpy(&bi.autocon[bi.num_autocon++], cdp,
-                      sizeof(struct ConfigDev));
-           else
-               Printf("Warning: too many AutoConfig devices. Ignoring device at "
-                      "0x%08lx\n", cdp->cd_BoardAddr);
-
-    do_fast = bi.num_memory ? 0 : 1;
-    do_chip = bi.chip_size ? 0 : 1;
-    /* find out the memory in the system */
-    for (mnp = (struct MemHeader *)SysBase->MemList.lh_Head;
-        mnp->mh_Node.ln_Succ;
-        mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) {
-       struct MemHeader mh;
-
-       /* copy the information */
-       mh = *mnp;
-
-       /* skip virtual memory */
-       if (!(mh.mh_Attributes & MEMF_PUBLIC))
-           continue;
-
-       /* if we suspect that Kickstart is shadowed in an A3000,
-          modify the entry to show 512K more at the top of RAM
-          Check first for a MapROMmed A3640 board: overwriting the
-          Kickstart image causes an infinite lock-up on reboot! */
-       if ((mh.mh_Upper == (void *)0x07f80000) &&
-           (model_mask & (CLASS_A3000 | CLASS_A4000)))
-           if ((bi.cputype & CPU_68040) && Supervisor(maprommed))
-               Puts("A3640 MapROM detected.\n");
-           else if (model_mask & CLASS_A3000) {
-               mh.mh_Upper = (void *)0x08000000;
-               Puts("A3000 shadowed Kickstart detected.\n");
-           }
-
-       /* if we suspect that Kickstart is zkicked,
-          modify the entry to show 512K more at the botton of RAM */
-       if ((mh.mh_Lower == (void *)0x00280020) &&
-           (model_mask & CLASS_ZKICK)) {
-           mh.mh_Lower = (void *)0x00200000;
-           Puts("ZKick detected.\n");
-       }
-
-       /* mask the memory limit values */
-       mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
-       mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
-
-       /* if fast memory */
-       if (do_fast && mh.mh_Attributes & MEMF_FAST) {
-           /* set the size value to the size of this block and mask off to a
-              256K increment */
-           u_long size = ((u_long)mh.mh_Upper-(u_long)mh.mh_Lower)&0xfffc0000;
-           if (size > 0)
-               if (bi.num_memory < NUM_MEMINFO) {
-                   /* record the start and size */
-                   bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
-                   bi.memory[bi.num_memory].size = size;
-                   /* count this block */
-                   bi.num_memory++;
-               } else
-                   Printf("Warning: too many memory blocks. Ignoring block "
-                          "of %ldK at 0x%08x\n", size>>10,
-                          (u_long)mh.mh_Lower);
-       } else if (do_chip && mh.mh_Attributes & MEMF_CHIP)
-           /* if CHIP memory, record the size */
-           bi.chip_size = (u_long)mh.mh_Upper;
-    }
-
-    /* get info from ExecBase */
-    if (!bi.vblank)
-       bi.vblank = SysBase->VBlankFrequency;
-    if (!bi.psfreq)
-       bi.psfreq = SysBase->PowerSupplyFrequency;
-    if (!bi.eclock)
-       bi.eclock = SysBase->ex_EClockFrequency;
-
-    /* serial port */
-    if (!bi.serper) {
-       realbaud = baud ? baud : DEFAULT_BAUD;
-       bi.serper = (5*bi.eclock+realbaud/2)/realbaud-1;
-    }
-
-    /* display Amiga model */
-    if (bi.model >= first_amiga_model && bi.model <= last_amiga_model)
-       Printf("%s ", amiga_models[bi.model-first_amiga_model]);
-    else
-       Puts("Amiga ");
-
-    /* display the CPU type */
-    Puts("CPU: ");
-    switch (bi.cputype) {
-       case CPU_68020:
-           Puts("68020 (Do you have an MMU?)");
-           break;
-       case CPU_68030:
-           Puts("68030");
-           break;
-       case CPU_68040:
-           Puts("68040");
-           break;
-       case CPU_68060:
-           Puts("68060");
-           break;
-       default:
-           Puts("Insufficient for Linux.  Aborting...\n");
-           Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags);
-           goto Fail;
-    }
-    switch (bi.fputype) {
-       case FPU_68881:
-           Puts(" with 68881 FPU");
-           break;
-       case FPU_68882:
-           Puts(" with 68882 FPU");
-           break;
-       case FPU_68040:
-       case FPU_68060:
-           Puts(" with internal FPU");
-           break;
-       default:
-           Puts(" without FPU");
-           break;
-    }
-
-    /* display the chipset */
-    switch (bi.chipset) {
-       case CS_STONEAGE:
-           Puts(", old or unknown chipset");
-           break;
-       case CS_OCS:
-           Puts(", OCS");
-           break;
-       case CS_ECS:
-           Puts(", ECS");
-           break;
-       case CS_AGA:
-           Puts(", AGA chipset");
-           break;
-    }
-
-    Puts("\n\n");
-
-    /* display the command line */
-    Printf("Command line is '%s'\n", bi.command_line);
-
-    /* display the clock statistics */
-    Printf("Vertical Blank Frequency: %ldHz\n", bi.vblank);
-    Printf("Power Supply Frequency: %ldHz\n", bi.psfreq);
-    Printf("EClock Frequency: %ldHz\n\n", bi.eclock);
-
-    /* display autoconfig devices */
-    if (bi.num_autocon) {
-       Printf("Found %ld AutoConfig Device%s\n", bi.num_autocon,
-              bi.num_autocon > 1 ? "s" : "");
-       for (i = 0; i < bi.num_autocon; i++) {
-           Printf("Device %ld: addr = 0x%08lx", i,
-                  (u_long)bi.autocon[i].cd_BoardAddr);
-           boardresetfuncs[i] = NULL;
-           if (reset_boards) {
-               manuf = bi.autocon[i].cd_Rom.er_Manufacturer;
-               prod = bi.autocon[i].cd_Rom.er_Product;
-               for (j = 0; j < NUM_BOARDRESET; j++)
-                   if ((manuf == boardresetdb[j].manuf) &&
-                       (prod == boardresetdb[j].prod)) {
-                       Printf(" [%s - will be reset at kernel boot time]",
-                              boardresetdb[j].name);
-                       boardresetfuncs[i] = boardresetdb[j].reset;
-                       break;
-                   }
-           }
-           PutChar('\n');
-       }
-    } else
-       Puts("No AutoConfig Devices Found\n");
-
-    /* display memory */
-    if (bi.num_memory) {
-       Printf("\nFound %ld Block%sof Memory\n", bi.num_memory,
-              bi.num_memory > 1 ? "s " : " ");
-       for (i = 0; i < bi.num_memory; i++)
-           Printf("Block %ld: 0x%08lx to 0x%08lx (%ldK)\n", i,
-                  bi.memory[i].addr, bi.memory[i].addr+bi.memory[i].size,
-                  bi.memory[i].size>>10);
-    } else {
-       Puts("No memory found?!  Aborting...\n");
-       goto Fail;
-    }
-
-    /* display chip memory size */
-    Printf("%ldK of CHIP memory\n", bi.chip_size>>10);
-
-    start_mem = bi.memory[0].addr;
-    mem_size = bi.memory[0].size;
-
-    /* tell us where the kernel will go */
-    Printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
-
-    /* verify that there is enough Chip RAM */
-    if (bi.chip_size < 512*1024) {
-       Puts("Not enough Chip RAM in this system.  Aborting...\n");
-       goto Fail;
-    }
-
-    /* verify that there is enough Fast RAM */
-    for (fast_total = 0, i = 0; i < bi.num_memory; i++)
-       fast_total += bi.memory[i].size;
-    if (fast_total < 2*1024*1024) {
-       Puts("Not enough Fast RAM in this system.  Aborting...\n");
-       goto Fail;
-    }
-
-    /* support for ramdisk */
-    if (ramdiskname) {
-       int size;
-
-       if ((size = FileSize(ramdiskname)) == -1) {
-           Printf("Unable to find size of ramdisk file `%s'\n", ramdiskname);
-           goto Fail;
-       }
-       /* record ramdisk size */
-       bi.ramdisk.size = size;
-    } else
-       bi.ramdisk.size = 0;
-    rd_size = bi.ramdisk.size;
-    bi.ramdisk.addr = (u_long)start_mem+mem_size-rd_size;
-
-    /* create the bootinfo structure */
-    if (!create_bootinfo())
-       goto Fail;
-
-    /* open kernel executable and read exec header */
-    if ((kfd = Open(kernelname)) == -1) {
-       Printf("Unable to open kernel file `%s'\n", kernelname);
-       goto Fail;
-    }
-    if (KRead(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
-       Puts("Unable to read exec header from kernel file\n");
-       goto Fail;
-    }
-
-#ifdef ZKERNEL
-    if (((unsigned char *)&kexec)[0] == 037 &&
-       (((unsigned char *)&kexec)[1] == 0213 ||
-        ((unsigned char *)&kexec)[1] == 0236)) {
-       /* That's a compressed kernel */
-       Puts("Kernel is compressed\n");
-       if (load_zkernel(kfd)) {
-           Puts("Decompression error -- aborting\n");
-           goto Fail;
-       }
-    }
-#endif
-
-    switch (N_MAGIC(kexec)) {
-       case ZMAGIC:
-           if (debugflag)
-               Puts("\nLoading a.out (ZMAGIC) Linux/m68k kernel...\n");
-           text_offset = N_TXTOFF(kexec);
-           break;
-
-       case QMAGIC:
-           if (debugflag)
-               Puts("\nLoading a.out (QMAGIC) Linux/m68k kernel...\n");
-           text_offset = sizeof(kexec);
-           /* the text size includes the exec header; remove this */
-           kexec.a_text -= sizeof(kexec);
-           break;
-
-       default:
-           /* Try to parse it as an ELF header */
-           KSeek(kfd, 0);
-           if ((KRead(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) ==
-                sizeof(kexec_elf)) &&
-                (memcmp(&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)) {
-               elf_kernel = 1;
-               if (debugflag)
-                   Puts("\nLoading ELF Linux/m68k kernel...\n");
-               /* A few plausibility checks */
-               if ((kexec_elf.e_type != ET_EXEC) ||
-                   (kexec_elf.e_machine != EM_68K) ||
-                   (kexec_elf.e_version != EV_CURRENT)) {
-                   Puts("Invalid ELF header contents in kernel\n");
-                   goto Fail;
-               }
-               /* Load the program headers */
-               if (!(kernel_phdrs =
-                     (Elf32_Phdr *)AllocMem(kexec_elf.e_phnum*sizeof(Elf32_Phdr),
-                                            MEMF_FAST | MEMF_PUBLIC |
-                                            MEMF_CLEAR))) {
-                   Puts("Unable to allocate memory for program headers\n");
-                   goto Fail;
-               }
-               KSeek(kfd, kexec_elf.e_phoff);
-               if (KRead(kfd, (void *)kernel_phdrs,
-                        kexec_elf.e_phnum*sizeof(*kernel_phdrs)) !=
-                   kexec_elf.e_phnum*sizeof(*kernel_phdrs)) {
-                   Puts("Unable to read program headers from kernel file\n");
-                   goto Fail;
-               }
-               break;
-           }
-           Printf("Wrong magic number 0x%08lx in kernel header\n",
-                  N_MAGIC(kexec));
-           goto Fail;
-    }
-
-    /* Load the kernel at one page after start of mem */
-    start_mem += PAGE_SIZE;
-    mem_size -= PAGE_SIZE;
-    /* Align bss size to multiple of four */
-    if (!elf_kernel)
-       kexec.a_bss = (kexec.a_bss+3) & ~3;
-
-    /* calculate the total required amount of memory */
-    if (elf_kernel) {
-       u_long min_addr = 0xffffffff, max_addr = 0;
-       for (i = 0; i < kexec_elf.e_phnum; i++) {
-           if (min_addr > kernel_phdrs[i].p_vaddr)
-               min_addr = kernel_phdrs[i].p_vaddr;
-           if (max_addr < kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz)
-               max_addr = kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz;
-       }
-       /* This is needed for newer linkers that include the header in
-          the first segment.  */
-       if (min_addr == 0) {
-           min_addr = PAGE_SIZE;
-           kernel_phdrs[0].p_vaddr += PAGE_SIZE;
-           kernel_phdrs[0].p_offset += PAGE_SIZE;
-           kernel_phdrs[0].p_filesz -= PAGE_SIZE;
-           kernel_phdrs[0].p_memsz -= PAGE_SIZE;
-       }
-       kernel_size = max_addr-min_addr;
-    } else
-       kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss;
-    memreq = kernel_size+bi_size+rd_size;
-#ifdef BOOTINFO_COMPAT_1_0
-    if (sizeof(compat_bootinfo) > bi_size)
-       memreq = kernel_size+sizeof(compat_bootinfo)+rd_size;
-#endif /* BOOTINFO_COMPAT_1_0 */
-    if (!(memptr = (char *)AllocMem(memreq, MEMF_FAST | MEMF_PUBLIC |
-                                           MEMF_CLEAR))) {
-       Puts("Unable to allocate memory\n");
-       goto Fail;
-    }
-
-    /* read the text and data segments from the kernel image */
-    if (elf_kernel)
-       for (i = 0; i < kexec_elf.e_phnum; i++) {
-           if (KSeek(kfd, kernel_phdrs[i].p_offset) == -1) {
-               Printf("Failed to seek to segment %ld\n", i);
-               goto Fail;
-           }
-           if (KRead(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
-                     kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) {
-               Printf("Failed to read segment %ld\n", i);
-               goto Fail;
-           }
-       }
-    else {
-       if (KSeek(kfd, text_offset) == -1) {
-           Puts("Failed to seek to text\n");
-           goto Fail;
-       }
-       if (KRead(kfd, memptr, kexec.a_text) != kexec.a_text) {
-           Puts("Failed to read text\n");
-           goto Fail;
-       }
-       /* data follows immediately after text */
-       if (KRead(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) {
-           Puts("Failed to read data\n");
-           goto Fail;
-       }
-    }
-    KClose(kfd);
-    kfd = -1;
-
-    /* Check kernel's bootinfo version */
-    switch (check_bootinfo_version(memptr)) {
-       case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
-           bi_ptr = &bi_union.record;
-           break;
-
-#ifdef BOOTINFO_COMPAT_1_0
-       case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
-           if (!create_compat_bootinfo())
-               goto Fail;
-           bi_ptr = &compat_bootinfo;
-           bi_size = sizeof(compat_bootinfo);
-           break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-       default:
-           goto Fail;
-    }
-
-    /* copy the bootinfo to the end of the kernel image */
-    memcpy((void *)(memptr+kernel_size), bi_ptr, bi_size);
-
-    if (ramdiskname) {
-       if ((rfd = Open(ramdiskname)) == -1) {
-           Printf("Unable to open ramdisk file `%s'\n", ramdiskname);
-           goto Fail;
-       }
-       if (Read(rfd, memptr+kernel_size+bi_size, rd_size) != rd_size) {
-           Puts("Failed to read ramdisk file\n");
-           goto Fail;
-       }
-       Close(rfd);
-       rfd = -1;
-    }
-
-    /* allocate temporary chip ram stack */
-    if (!(stack = (u_long *)AllocMem(TEMP_STACKSIZE, MEMF_CHIP | MEMF_CLEAR))) {
-       Puts("Unable to allocate memory for stack\n");
-       goto Fail;
-    }
-
-    /* allocate chip ram for copy of startup code */
-    startcodesize = &copyallend-&copyall;
-    if (!(startfunc = (void (*)(void))AllocMem(startcodesize,
-                                              MEMF_CHIP | MEMF_CLEAR))) {
-       Puts("Unable to allocate memory for startcode\n");
-       goto Fail;
-    }
-
-    /* copy startup code to CHIP RAM */
-    memcpy(startfunc, &copyall, startcodesize);
-
-    if (debugflag) {
-       if (bi.ramdisk.size)
-           Printf("RAM disk at 0x%08lx, size is %ldK\n",
-                  (u_long)memptr+kernel_size+bi_size, bi.ramdisk.size>>10);
-
-       if (elf_kernel) {
-           PutChar('\n');
-           for (i = 0; i < kexec_elf.e_phnum; i++)
-               Printf("Kernel segment %ld at 0x%08lx, size %ld\n", i,
-                      start_mem+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
-                      kernel_phdrs[i].p_memsz);
-           Printf("Boot info        at 0x%08lx\n", start_mem+kernel_size);
-       } else {
-           Printf("\nKernel text at 0x%08lx, code size 0x%08lx\n", start_mem,
-                  kexec.a_text);
-           Printf("Kernel data at 0x%08lx, data size 0x%08lx\n",
-                  start_mem+kexec.a_text, kexec.a_data);
-           Printf("Kernel bss  at 0x%08lx, bss  size 0x%08lx\n",
-                  start_mem+kexec.a_text+kexec.a_data, kexec.a_bss);
-           Printf("Boot info   at 0x%08lx\n", start_mem+kernel_size);
-       }
-       Printf("\nKernel entry is 0x%08lx\n", elf_kernel ? kexec_elf.e_entry :
-                                                          kexec.a_entry);
-
-       Printf("ramdisk dest is 0x%08lx\n", bi.ramdisk.addr);
-       Printf("ramdisk lower limit is 0x%08lx\n",
-              (u_long)memptr+kernel_size+bi_size);
-       Printf("ramdisk src top is 0x%08lx\n",
-              (u_long)memptr+kernel_size+bi_size+rd_size);
-
-       Puts("\nType a key to continue the Linux/m68k boot...");
-       GetChar();
-       PutChar('\n');
-    }
-
-    /* wait for things to settle down */
-    Sleep(1000000);
-
-    if (!keep_video)
-       /* set graphics mode to a nice normal one */
-       LoadView(NULL);
-
-    Disable();
-
-    /* reset nasty Zorro boards */
-    if (reset_boards)
-       for (i = 0; i < bi.num_autocon; i++)
-           if (boardresetfuncs[i])
-               boardresetfuncs[i](&bi.autocon[i]);
-
-    /* Turn off all DMA */
-    custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
-    /* turn off caches */
-    CacheControl(0, ~0);
-
-    /* Go into supervisor state */
-    SuperState();
-
-    /* turn off any mmu translation */
-    disable_mmu();
-
-    /* execute the copy-and-go code (from CHIP RAM) */
-    start_kernel(startfunc, (char *)stack+TEMP_STACKSIZE, memptr, start_mem,
-                kernel_size, bi.ramdisk.addr, rd_size);
-
-    /* Clean up and exit in case of a failure */
-Fail:
-    if (kfd != -1)
-       KClose(kfd);
-    if (rfd != -1)
-       Close(rfd);
-    if (memptr)
-       FreeMem((void *)memptr, memreq);
-    if (stack)
-       FreeMem((void *)stack, TEMP_STACKSIZE);
-    if (kernel_phdrs)
-       FreeMem((void *)kernel_phdrs, kexec_elf.e_phnum*sizeof(Elf32_Phdr));
-    return(FALSE);
-}
-
-
-    /*
-     * Determine the Chipset
-     */
-
-static u_long get_chipset(void)
-{
-    u_char cs;
-    u_long chipset;
-
-    if (GfxBase->Version >= 39)
-       cs = SetChipRev(SETCHIPREV_BEST);
-    else
-       cs = GfxBase->ChipRevBits0;
-    if ((cs & GFXG_AGA) == GFXG_AGA)
-       chipset = CS_AGA;
-    else if ((cs & GFXG_ECS) == GFXG_ECS)
-       chipset = CS_ECS;
-    else if ((cs & GFXG_OCS) == GFXG_OCS)
-       chipset = CS_OCS;
-    else
-       chipset = CS_STONEAGE;
-    return(chipset);
-}
-
-
-    /*
-     * Determine the CPU Type
-     */
-
-static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
-{
-    *cpu = *fpu = 0;
-
-    if (SysBase->AttnFlags & AFF_68060)
-       *cpu = CPU_68060;
-    else if (SysBase->AttnFlags & AFF_68040)
-       *cpu = CPU_68040;
-    else if (SysBase->AttnFlags & AFF_68030)
-       *cpu = CPU_68030;
-    else if (SysBase->AttnFlags & AFF_68020)
-       *cpu = CPU_68020;
-
-    if (*cpu == CPU_68040 || *cpu == CPU_68060) {
-       if (SysBase->AttnFlags & AFF_FPU40)
-           *fpu = *cpu;
-    } else if (SysBase->AttnFlags & AFF_68882)
-       *fpu = FPU_68882;
-    else if (SysBase->AttnFlags & AFF_68881)
-       *fpu = FPU_68881;
-
-    *mmu = *cpu;
-}
-
-    /*
-     * Determine the Amiga Model
-     */
-
-static u_long get_model(u_long chipset)
-{
-    u_long model = AMI_UNKNOWN;
-
-    if (debugflag)
-       Puts("Amiga model identification:\n");
-    if (probe_resource("draco.resource"))
-       model = AMI_DRACO;
-    else {
-       if (debugflag)
-           Puts("    Chipset: ");
-       switch (chipset) {
-           case CS_STONEAGE:
-               if (debugflag)
-                   Puts("Old or unknown\n");
-               goto OCS;
-               break;
-
-           case CS_OCS:
-               if (debugflag)
-                   Puts("OCS\n");
-OCS:           if (probe_resident("cd.device"))
-                   model = AMI_CDTV;
-               else
-                   /* let's call it an A2000 (may be A500, A1000, A2500) */
-                   model = AMI_2000;
-               break;
-
-           case CS_ECS:
-               if (debugflag)
-                   Puts("ECS\n");
-               if (probe_resident("Magic 36.7") ||
-                   probe_resident("kickad 36.57") ||
-                   probe_resident("A3000 Bonus") ||
-                   probe_resident("A3000 bonus"))
-                   /* let's call it an A3000 (may be A3000T) */
-                   model = AMI_3000;
-               else if (probe_resource("card.resource"))
-                   model = AMI_600;
-               else
-                   /* let's call it an A2000 (may be A500[+], A1000, A2500) */
-                   model = AMI_2000;
-               break;
-
-           case CS_AGA:
-               if (debugflag)
-                   Puts("AGA\n");
-               if (probe_resident("A1000 Bonus") ||
-                   probe_resident("A4000 bonus"))
-                   model = probe_resident("NCR scsi.device") ? AMI_4000T :
-                                                               AMI_4000;
-               else if (probe_resource("card.resource"))
-                   model = AMI_1200;
-               else if (probe_resident("cd.device"))
-                   model = AMI_CD32;
-               else
-                   model = AMI_3000PLUS;
-               break;
-       }
-    }
-    if (debugflag) {
-       Puts("\nType a key to continue...");
-       GetChar();
-       Puts("\n\n");
-    }
-    return(model);
-}
-
-
-    /*
-     * Probe for a Resident Modules
-     */
-
-static int probe_resident(const char *name)
-{
-    const struct Resident *res;
-
-    if (debugflag)
-       Printf("    Module `%s': ", name);
-    res = FindResident(name);
-    if (debugflag)
-       if (res)
-           Printf("0x%08lx\n", res);
-       else
-           Puts("not present\n");
-    return(res ? TRUE : FALSE);
-}
-
-
-    /*
-     * Probe for an available Resource
-     */
-
-static int probe_resource(const char *name)
-{
-    const void *res;
-
-    if (debugflag)
-       Printf("    Resource `%s': ", name);
-    res = OpenResource(name);
-    if (debugflag)
-       if (res)
-           Printf("0x%08lx\n", res);
-       else
-           Puts("not present\n");
-    return(res ? TRUE : FALSE);
-}
-
-
-    /*
-     *  Create the Bootinfo structure
-     */
-
-static int create_bootinfo(void)
-{
-    int i;
-    struct bi_record *record;
-
-    /* Initialization */
-    bi_size = 0;
-
-    /* Generic tags */
-    if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
-       return(0);
-    if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
-       return(0);
-    if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
-       return(0);
-    if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
-       return(0);
-    for (i = 0; i < bi.num_memory; i++)
-       if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
-           return(0);
-    if (bi.ramdisk.size)
-       if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
-           return(0);
-    if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
-       return(0);
-
-    /* Amiga tags */
-    if (!add_bi_record(BI_AMIGA_MODEL, sizeof(bi.model), &bi.model))
-       return(0);
-    for (i = 0; i < bi.num_autocon; i++)
-       if (!add_bi_record(BI_AMIGA_AUTOCON, sizeof(bi.autocon[i]),
-                           &bi.autocon[i]))
-           return(0);
-    if (!add_bi_record(BI_AMIGA_CHIP_SIZE, sizeof(bi.chip_size), &bi.chip_size))
-       return(0);
-    if (!add_bi_record(BI_AMIGA_VBLANK, sizeof(bi.vblank), &bi.vblank))
-       return(0);
-    if (!add_bi_record(BI_AMIGA_PSFREQ, sizeof(bi.psfreq), &bi.psfreq))
-       return(0);
-    if (!add_bi_record(BI_AMIGA_ECLOCK, sizeof(bi.eclock), &bi.eclock))
-       return(0);
-    if (!add_bi_record(BI_AMIGA_CHIPSET, sizeof(bi.chipset), &bi.chipset))
-       return(0);
-    if (!add_bi_record(BI_AMIGA_SERPER, sizeof(bi.serper), &bi.serper))
-       return(0);
-
-    /* Trailer */
-    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
-    record->tag = BI_LAST;
-    bi_size += sizeof(bi_union.record.tag);
-
-    return(1);
-}
-
-
-    /*
-     *  Add a Record to the Bootinfo Structure
-     */
-
-static int add_bi_record(u_short tag, u_short size, const void *data)
-{
-    struct bi_record *record;
-    u_int size2;
-
-    size2 = (sizeof(struct bi_record)+size+3)&-4;
-    if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
-       Puts("Can't add bootinfo record. Ask a wizard to enlarge me.\n");
-       return(0);
-    }
-    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
-    record->tag = tag;
-    record->size = size2;
-    memcpy(record->data, data, size);
-    bi_size += size2;
-    return(1);
-}
-
-
-    /*
-     *  Add a String Record to the Bootinfo Structure
-     */
-
-static int add_bi_string(u_short tag, const u_char *s)
-{
-    return(add_bi_record(tag, strlen(s)+1, (void *)s));
-}
-
-
-#ifdef BOOTINFO_COMPAT_1_0
-
-    /*
-     *  Create the Bootinfo structure for backwards compatibility mode
-     */
-
-static int create_compat_bootinfo(void)
-{
-    u_int i;
-
-    compat_bootinfo.machtype = bi.machtype;
-    if (bi.cputype & CPU_68020)
-       compat_bootinfo.cputype = COMPAT_CPU_68020;
-    else if (bi.cputype & CPU_68030)
-       compat_bootinfo.cputype = COMPAT_CPU_68030;
-    else if (bi.cputype & CPU_68040)
-       compat_bootinfo.cputype = COMPAT_CPU_68040;
-    else if (bi.cputype & CPU_68060)
-       compat_bootinfo.cputype = COMPAT_CPU_68060;
-    else {
-       Printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
-       return(0);
-    }
-    if (bi.fputype & FPU_68881)
-       compat_bootinfo.cputype |= COMPAT_FPU_68881;
-    else if (bi.fputype & FPU_68882)
-       compat_bootinfo.cputype |= COMPAT_FPU_68882;
-    else if (bi.fputype & FPU_68040)
-       compat_bootinfo.cputype |= COMPAT_FPU_68040;
-    else if (bi.fputype & FPU_68060)
-       compat_bootinfo.cputype |= COMPAT_FPU_68060;
-    else if (bi.fputype) {
-       Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
-       return(0);
-    }
-    compat_bootinfo.num_memory = bi.num_memory;
-    if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
-       Printf("Warning: using only %ld blocks of memory\n",
-              COMPAT_NUM_MEMINFO);
-       compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
-    }
-    for (i = 0; i < compat_bootinfo.num_memory; i++) {
-       compat_bootinfo.memory[i].addr = bi.memory[i].addr;
-       compat_bootinfo.memory[i].size = bi.memory[i].size;
-    }
-    if (bi.ramdisk.size) {
-       bi.ramdisk.addr &= 0xfffffc00;
-       compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
-       compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
-    } else {
-       compat_bootinfo.ramdisk_size = 0;
-       compat_bootinfo.ramdisk_addr = 0;
-    }
-    strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
-    compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
-
-    compat_bootinfo.bi_amiga.model = bi.model;
-    compat_bootinfo.bi_amiga.num_autocon = bi.num_autocon;
-    if (compat_bootinfo.bi_amiga.num_autocon > COMPAT_NUM_AUTO) {
-       Printf("Warning: using only %ld AutoConfig devices\n",
-              COMPAT_NUM_AUTO);
-       compat_bootinfo.bi_amiga.num_autocon = COMPAT_NUM_AUTO;
-    }
-    for (i = 0; i < compat_bootinfo.bi_amiga.num_autocon; i++)
-       compat_bootinfo.bi_amiga.autocon[i] = bi.autocon[i];
-    compat_bootinfo.bi_amiga.chip_size = bi.chip_size;
-    compat_bootinfo.bi_amiga.vblank = bi.vblank;
-    compat_bootinfo.bi_amiga.psfreq = bi.psfreq;
-    compat_bootinfo.bi_amiga.eclock = bi.eclock;
-    compat_bootinfo.bi_amiga.chipset = bi.chipset;
-    compat_bootinfo.bi_amiga.hw_present = 0;
-    return(1);
-}
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
-    /*
-     *  Compare the Bootstrap and Kernel Versions
-     */
-
-static int check_bootinfo_version(const char *memptr)
-{
-    const struct bootversion *bv = (struct bootversion *)memptr;
-    unsigned long version = 0;
-    int i, kernel_major, kernel_minor, boots_major, boots_minor;
-
-    if (bv->magic == BOOTINFOV_MAGIC)
-       for (i = 0; bv->machversions[i].machtype != 0; ++i)
-           if (bv->machversions[i].machtype == MACH_AMIGA) {
-               version = bv->machversions[i].version;
-               break;
-           }
-    if (!version)
-       Puts("Kernel has no bootinfo version info, assuming 0.0\n");
-
-    kernel_major = BI_VERSION_MAJOR(version);
-    kernel_minor = BI_VERSION_MINOR(version);
-    boots_major  = BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION);
-    boots_minor  = BI_VERSION_MINOR(AMIGA_BOOTI_VERSION);
-    Printf("Bootstrap's bootinfo version: %ld.%ld\n", boots_major,
-          boots_minor);
-    Printf("Kernel's bootinfo version   : %ld.%ld\n", kernel_major,
-          kernel_minor);
-
-    switch (kernel_major) {
-       case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
-           if (kernel_minor > boots_minor) {
-               Puts("Warning: Bootinfo version of bootstrap and kernel "
-                      "differ!\n");
-               Puts("         Certain features may not work.\n");
-           }
-           break;
-
-#ifdef BOOTINFO_COMPAT_1_0
-       case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
-           Puts("(using backwards compatibility mode)\n");
-           break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-       default:
-           Printf("\nThis bootstrap is too %s for this kernel!\n",
-                  boots_major < kernel_major ? "old" : "new");
-           return(0);
-    }
-    return(kernel_major);
-}
-
-
-    /*
-     * Call the copy-and-go-code
-     */
-
-static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
-                        u_long start_mem, u_long kernel_size, u_long rd_dest,
-                        u_long rd_size)
-{
-    register void (*a0)() __asm("a0") = startfunc;
-    register char *a2 __asm("a2") = stackp;
-    register char *a3 __asm("a3") = memptr;
-    register u_long a4 __asm("a4") = start_mem;
-    register u_long d0 __asm("d0") = rd_dest;
-    register u_long d1 __asm("d1") = rd_size;
-    register u_long d2 __asm("d2") = kernel_size;
-    register u_long d3 __asm("d3") = bi_size;
-
-    __asm __volatile ("movel a2,sp;"
-                     "jmp a0@"
-                     : /* no outputs */
-                     : "r" (a0), "r" (a2), "r" (a3), "r" (a4), "r" (d0),
-                       "r" (d1), "r" (d2), "r" (d3)
-                     /* no return */);
-    /* fake a noreturn */
-    for (;;);
-}
-
-
-    /*
-     * This assembler code is copied to chip ram, and then executed.
-     * It copies the kernel to it's final resting place.
-     *
-     * It is called with:
-     *
-     *     a3 = memptr
-     *     a4 = start_mem
-     *     d0 = rd_dest
-     *     d1 = rd_size
-     *     d2 = kernel_size
-     *     d3 = bi_size
-     */
-
-asm(".text\n"
-ALIGN_STR "\n"
-SYMBOL_NAME_STR(copyall) ":
-                               | /* copy kernel text and data */
-       movel   a3,a0           | src = (u_long *)memptr;
-       movel   a0,a2           | limit = (u_long *)(memptr+kernel_size);
-       addl    d2,a2
-       movel   a4,a1           | dest = (u_long *)start_mem;
-1:     cmpl    a0,a2
-       jeq     2f              | while (src < limit)
-       moveb   a0@+,a1@+       |  *dest++ = *src++;
-       jra     1b
-2:
-                               | /* copy bootinfo to end of bss */
-       movel   a3,a0           | src = (u_long *)(memptr+kernel_size);
-       addl    d2,a0           | dest = end of bss (already in a1)
-       movel   d3,d7           | count = bi_size
-       subql   #1,d7
-1:     moveb   a0@+,a1@+       | while (--count > -1)
-       dbra    d7,1b           |     *dest++ = *src++
-
-                               | /* copy the ramdisk to the top of memory */
-       movel   a3,a0           | src = (u_long *)(memptr+kernel_size+bi_size);
-       addl    d2,a0
-       addl    d3,a0
-       movel   d0,a1           | dest = (u_long *)rd_dest;
-       movel   a0,a2           | limit = (u_long *)(memptr+kernel_size+
-       addl    d1,a2           |                    bi_size+rd_size);
-1:     cmpl    a0,a2
-       jeq     2f              | while (src > limit)
-       moveb   a0@+,a1@+       |     *dest++ = *src++;
-       jra     1b
-2:
-                               | /* jump to start of kernel */
-       movel   a4,a0           | jump_to (start_mem);
-       jmp     a0@
-"
-SYMBOL_NAME_STR(copyallend) ":
-");
-
-
-    /*
-     * Test for a MapROMmed A3640 Board
-     */
-
-asm(".text\n"
-ALIGN_STR "\n"
-SYMBOL_NAME_STR(maprommed) ":
-       oriw    #0x0700,sr
-       moveml  #0x3f20,sp@-
-                               | /* Save cache settings */
-       .long   0x4e7a1002      | movec cacr,d1 */
-                               | /* Save MMU settings */
-       .long   0x4e7a2003      | movec tc,d2
-       .long   0x4e7a3004      | movec itt0,d3
-       .long   0x4e7a4005      | movec itt1,d4
-       .long   0x4e7a5006      | movec dtt0,d5
-       .long   0x4e7a6007      | movec dtt1,d6
-       moveq   #0,d0
-       movel   d0,a2
-                               | /* Disable caches */
-       .long   0x4e7b0002      | movec d0,cacr
-                               | /* Disable MMU */
-       .long   0x4e7b0003      | movec d0,tc
-       .long   0x4e7b0004      | movec d0,itt0
-       .long   0x4e7b0005      | movec d0,itt1
-       .long   0x4e7b0006      | movec d0,dtt0
-       .long   0x4e7b0007      | movec d0,dtt1
-       lea     0x07f80000,a0
-       lea     0x00f80000,a1
-       movel   a0@,d7
-       cmpl    a1@,d7
-       jne     1f
-       movel   d7,d0
-       notl    d0
-       movel   d0,a0@
-       nop                     | /* Thanks to Jörg Mayer! */
-       cmpl    a1@,d0
-       jne     1f
-       moveq   #-1,d0          | /* MapROMmed A3640 present */
-       movel   d0,a2
-1:     movel   d7,a0@
-                               | /* Restore MMU settings */
-       .long   0x4e7b2003      | movec d2,tc
-       .long   0x4e7b3004      | movec d3,itt0
-       .long   0x4e7b4005      | movec d4,itt1
-       .long   0x4e7b5006      | movec d5,dtt0
-       .long   0x4e7b6007      | movec d6,dtt1
-                               | /* Restore cache settings */
-       .long   0x4e7b1002      | movec d1,cacr
-       movel   a2,d0
-       moveml  sp@+,#0x04fc
-       rte
-");
-
-
-    /*
-     * Reset functions for nasty Zorro boards
-     */
-
-static void reset_rb3(const struct ConfigDev *cd)
-{
-    volatile u_char *rb3_reg = (u_char *)(cd->cd_BoardAddr+0x01002000);
-
-    /* FN: If a Rainbow III board is present, reset it to disable */
-    /* its (possibly activated) vertical blank interrupts as the */
-    /* kernel is not yet prepared to handle them (level 6). */
-
-    /* set RESET bit in special function register */
-    *rb3_reg = 0x01;
-    /* actually, only a few cycles delay are required... */
-    Sleep(1000000);
-    /* clear reset bit */
-    *rb3_reg = 0x00;
-}
-
-static void reset_piccolo(const struct ConfigDev *cd)
-{
-    volatile u_char *piccolo_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
-
-    /* FN: the same stuff as above, for the Piccolo board. */
-    /* this also has the side effect of resetting the board's */
-    /* output selection logic to use the Amiga's display in single */
-    /* monitor systems - which is currently what we want. */
-
-    /* set RESET bit in special function register */
-    *piccolo_reg = 0x01;
-    /* actually, only a few cycles delay are required... */
-    Sleep(1000000);
-    /* clear reset bit */
-    *piccolo_reg = 0x51;
-}
-
-static void reset_sd64(const struct ConfigDev *cd)
-{
-    volatile u_char *sd64_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
-
-    /* FN: the same stuff as above, for the SD64 board. */
-    /* just as on the Piccolo, this also resets the monitor switch */
-
-    /* set RESET bit in special function register */
-    *sd64_reg = 0x1f;
-    /* actually, only a few cycles delay are required... */
-    Sleep(1000000);
-    /* clear reset bit AND switch monitor bit (0x20) */
-    *sd64_reg = 0x4f;
-}
-
-static void reset_ariadne(const struct ConfigDev *cd)
-{
-    volatile u_short *lance_rdp = (u_short *)(cd->cd_BoardAddr+0x0370);
-    volatile u_short *lance_rap = (u_short *)(cd->cd_BoardAddr+0x0372);
-    volatile u_short *lance_reset = (u_short *)(cd->cd_BoardAddr+0x0374);
-
-    volatile u_char *pit_paddr = (u_char *)(cd->cd_BoardAddr+0x1004);
-    volatile u_char *pit_pbddr = (u_char *)(cd->cd_BoardAddr+0x1006);
-    volatile u_char *pit_pacr = (u_char *)(cd->cd_BoardAddr+0x100b);
-    volatile u_char *pit_pbcr = (u_char *)(cd->cd_BoardAddr+0x100e);
-    volatile u_char *pit_psr = (u_char *)(cd->cd_BoardAddr+0x101a);
-
-    u_short in;
-
-    Disable();
-
-    /*
-     * Reset the Ethernet part (Am79C960 PCnet-ISA)
-     */
-
-    in = *lance_reset;   /* Reset Chip on Read Access */
-    *lance_rap = 0x0000; /* PCnet-ISA Controller Status (CSR0) */
-    *lance_rdp = 0x0400; /* STOP */
-
-    /*
-     * Reset the Parallel part (MC68230 PI/T)
-     */
-
-    *pit_pacr &= 0xfd;   /* Port A Control Register */
-    *pit_pbcr &= 0xfd;   /* Port B Control Register */
-    *pit_psr = 0x05;     /* Port Status Register */
-    *pit_paddr = 0x00;   /* Port A Data Direction Register */
-    *pit_pbddr = 0x00;   /* Port B Data Direction Register */
-
-    Enable();
-}
-
-static void reset_hydra(const struct ConfigDev *cd)
-{
-    volatile u_char *nic_cr  = (u_char *)(cd->cd_BoardAddr+0xffe1);
-    volatile u_char *nic_isr = (u_char *)(cd->cd_BoardAddr+0xffe1 + 14);
-    int n = 5000;
-
-    Disable();
-    *nic_cr = 0x21;    /* nic command register: software reset etc. */
-    while (((*nic_isr & 0x80) == 0) && --n)  /* wait for reset to complete */
-       ;
-    Enable();
-}
-
-#if 0
-static void reset_a2060(const struct ConfigDev *cd)
-{
-#error reset_a2060: not yet implemented
-}
-#endif
-
-
-#ifdef ZKERNEL
-
-#define        ZFILE_CHUNK_BITS        16  /* chunk is 64 KB */
-#define        ZFILE_CHUNK_SIZE        (1 << ZFILE_CHUNK_BITS)
-#define        ZFILE_CHUNK_MASK        (ZFILE_CHUNK_SIZE-1)
-#define        ZFILE_N_CHUNKS          (2*1024*1024/ZFILE_CHUNK_SIZE)
-
-/* variables for storing the uncompressed data */
-static char *ZFile[ZFILE_N_CHUNKS];
-static int ZFileSize = 0;
-static int ZFpos = 0;
-static int Zwpos = 0;
-
-static int Zinfd = 0;       /* fd of compressed file */
-
-/*
- * gzip declarations
- */
-
-#define OF(args)  args
-
-#define memzero(s, n)     memset ((s), 0, (n))
-
-typedef unsigned char  uch;
-typedef unsigned short ush;
-typedef unsigned long  ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000    /* window size--must be a power of two, and */
-                       /*  at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize = 0;  /* valid bytes in inbuf */
-static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0;  /* bytes in output buffer */
-static int exit_code = 0;
-static long bytes_out = 0;
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-               
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int  fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#define malloc(x)      AllocVec(x, MEMF_FAST | MEMF_PUBLIC)
-#define free(x)                FreeVec(x)
-
-#ifdef LILO
-#include "inflate.c"
-#else
-#include "../../../../lib/inflate.c"
-#endif
-
-static void gzip_mark(void **ptr)
-{
-}
-
-static void gzip_release(void **ptr)
-{
-}
-
-
-/*
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf(void)
-{
-    if (exit_code)
-       return -1;
-
-    insize = Read(Zinfd, inbuf, INBUFSIZ);
-    if (insize <= 0)
-       return -1;
-
-    inptr = 1;
-    return(inbuf[0]);
-}
-
-/*
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in, ch;
-    int chunk = Zwpos >> ZFILE_CHUNK_BITS;
-
-    if (exit_code)
-       return;
-
-    if (chunk >= ZFILE_N_CHUNKS) {
-       error("Compressed image too large! Aborting.\n");
-       return;
-    }
-    if (!ZFile[chunk]) {
-       if (!(ZFile[chunk] = (char *)AllocMem(ZFILE_CHUNK_SIZE,
-                                             MEMF_FAST | MEMF_PUBLIC))) {
-           error("Out of memory for decompresing kernel image\n");
-           return;
-       }
-    }
-    memcpy(ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt);
-    Zwpos += outcnt;
-    
-#define        DISPLAY_BITS 10
-    if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0)
-       PutChar('.');
-    
-    in = window;
-    for (n = 0; n < outcnt; n++) {
-       ch = *in++;
-       c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    outcnt = 0;
-}
-
-static void error(char *x)
-{
-    Printf("\n%s", x);
-    exit_code = 1;
-}
-
-static inline int call_sub(int (*func)(void), void *stackp)
-{
-    register int _res __asm("d0");
-    register int (*a0)(void) __asm("a0") = func;
-    register int (*a1)(void) __asm("a1") = stackp;
-
-    __asm __volatile ("movel sp,a2;"
-                     "movel a1,sp;"
-                     "jsr a0@;"
-                     "movel a2,sp"
-                     : "=r" (_res)
-                     : "r" (a0), "r" (a1)
-                     : "a0", "a1", "a2", "d0", "d1", "memory");
-    return(_res);
-}
-
-static int load_zkernel(int fd)
-{
-    int i, err = -1;
-#define ZSTACKSIZE     (16384)
-    u_long *zstack;
-    
-    for (i = 0; i < ZFILE_N_CHUNKS; ++i)
-       ZFile[i] = NULL;
-    Zinfd = fd;
-    Seek(fd, 0);
-    
-    if (!(inbuf = (uch *)AllocMem(INBUFSIZ, MEMF_FAST | MEMF_PUBLIC)))
-       Puts("Couldn't allocate gunzip buffer\n");
-    else {
-       if (!(window = (uch *)AllocMem(WSIZE, MEMF_FAST | MEMF_PUBLIC)))
-           Puts("Couldn't allocate gunzip window\n");
-       else {
-           if (!(zstack = (u_long *)AllocMem(ZSTACKSIZE,
-                                             MEMF_FAST | MEMF_PUBLIC)))
-               Puts("Couldn't allocate gunzip stack\n");
-           else {
-               Puts("Uncompressing kernel image ");
-               makecrc();
-               if (!(err = call_sub(gunzip, (char *)zstack+ZSTACKSIZE)))
-                   Puts("done\n");
-               ZFileSize = Zwpos;
-               FreeMem(zstack, ZSTACKSIZE);
-           }
-           FreeMem(window, WSIZE);
-           window = NULL;
-       }
-       FreeMem(inbuf, INBUFSIZ);
-       inbuf = NULL;
-    }
-    Close(Zinfd);      /* input file not needed anymore */
-    return(err);
-}
-
-
-/* Note about the read/lseek wrapper and its memory management: It assumes
- * that all seeks are only forward, and thus data already read or skipped can
- * be freed. This is true for current organization of bootstrap and kernels.
- * Little exception: The struct kexec at the start of the file. After reading
- * it, there may be a seek back to the end of the file. But this currently
- * doesn't hurt. (Roman)
- */
-
-static int KRead(int fd, void *buf, int cnt)
-{
-    unsigned done = 0;
-       
-    if (!ZFileSize)
-       return(Read(fd, buf, cnt));
-    
-    if (ZFpos + cnt > ZFileSize)
-       cnt = ZFileSize - ZFpos;
-    
-    while (cnt > 0) {
-       unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
-       unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
-       unsigned n = cnt;
-
-       if (ZFpos + n > endchunk)
-           n = endchunk - ZFpos;
-       memcpy(buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n);
-       cnt -= n;
-       buf += n;
-       done += n;
-       ZFpos += n;
-
-       if (ZFpos == endchunk) {
-           FreeMem(ZFile[chunk], ZFILE_CHUNK_SIZE);
-           ZFile[chunk] = NULL;
-       }
-    }
-
-    return(done);
-}
-
-
-static int KSeek(int fd, int offset)
-{
-    unsigned oldpos, oldchunk, newchunk;
-
-    if (!ZFileSize)
-       return(Seek(fd, offset));
-
-    oldpos = ZFpos;
-    ZFpos = offset;
-    if (ZFpos < 0) {
-       ZFpos = 0;
-       return(-1);
-    } else if (ZFpos > ZFileSize) {
-       ZFpos = ZFileSize;
-       return(-1);
-    }
-
-    /* free memory of skipped-over data */
-    oldchunk = oldpos >> ZFILE_CHUNK_BITS;
-    newchunk = ZFpos  >> ZFILE_CHUNK_BITS;
-    while(oldchunk < newchunk) {
-       if (ZFile[oldchunk]) {
-           FreeMem(ZFile[oldchunk], ZFILE_CHUNK_SIZE);
-           ZFile[oldchunk] = NULL;
-       }
-       ++oldchunk;
-    }
-    return(ZFpos);
-}
-
-
-static void free_zfile(void)
-{
-    int i;
-
-    for (i = 0; i < ZFILE_N_CHUNKS; ++i)
-       if (ZFile[i]) {
-           FreeMem(ZFile[i], ZFILE_CHUNK_SIZE);
-           ZFile[i] = NULL;
-       }
-}
-
-static int KClose(int fd)
-{
-    if (ZFileSize) {
-       free_zfile();
-       ZFileSize = 0;
-    } else
-       Close(fd);
-    return(0);
-}
-#endif /* ZKERNEL */
diff --git a/arch/m68k/boot/amiga/linuxboot.h b/arch/m68k/boot/amiga/linuxboot.h
deleted file mode 100644 (file)
index e04425a..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- *  linux/arch/m68k/boot/amiga/linuxboot.h -- Generic routine to boot Linux/m68k
- *                                           on Amiga, used by both Amiboot and
- *                                           Amiga-Lilo.
- *
- *     Created 1996 by Geert Uytterhoeven
- *
- *
- *  This file is based on the original bootstrap code (bootstrap.c):
- *
- *     Copyright (C) 1993, 1994 Hamish Macdonald
- *                              Greg Harp
- *
- *                 with work by Michael Rausch
- *                              Geert Uytterhoeven
- *                              Frank Neumann
- *                              Andreas Schwab
- *
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive
- *  for more details.
- */
-
-
-#include <asm/setup.h>
-#include <linux/zorro.h>
-
-
-    /*
-     *  Amiboot Version
-     */
-
-#define AMIBOOT_VERSION                "5.5"
-
-
-    /*
-     *  Amiga Bootinfo Definitions
-     *
-     *  All limits herein are `soft' limits, i.e. they don't put constraints
-     *  on the actual parameters in the kernel.
-     */
-
-struct amiga_bootinfo {
-    u_long machtype;                   /* machine type = MACH_AMIGA */
-    u_long cputype;                    /* system CPU */
-    u_long fputype;                    /* system FPU */
-    u_long mmutype;                    /* system MMU */
-    int num_memory;                    /* # of memory blocks found */
-    struct mem_info memory[NUM_MEMINFO];/* memory description */
-    struct mem_info ramdisk;           /* ramdisk description */
-    char command_line[CL_SIZE];                /* kernel command line parameters */
-    u_long model;                      /* Amiga Model */
-    int num_autocon;                   /* # of autoconfig devices found */
-    struct ConfigDev autocon[ZORRO_NUM_AUTO];  /* autoconfig devices */
-    u_long chip_size;                  /* size of chip memory (bytes) */
-    u_char vblank;                     /* VBLANK frequency */
-    u_char psfreq;                     /* power supply frequency */
-    u_long eclock;                     /* EClock frequency */
-    u_long chipset;                    /* native chipset present */
-    u_short serper;                    /* serial port period */
-};
-
-
-    /*
-     *  Parameters passed to linuxboot()
-     */
-
-struct linuxboot_args {
-    struct amiga_bootinfo bi;  /* Initial values override detected values */
-    const char *kernelname;
-    const char *ramdiskname;
-    int debugflag;
-    int keep_video;
-    int reset_boards;
-    u_int baud;
-    void (*puts)(const char *str);
-    long (*getchar)(void);
-    void (*putchar)(char c);
-    void (*printf)(const char *fmt, ...);
-    int (*open)(const char *path);
-    int (*seek)(int fd, int offset);
-    int (*read)(int fd, char *buf, int count);
-    void (*close)(int fd);
-    int (*filesize)(const char *path);
-    void (*sleep)(u_long micros);
-};
-
-
-    /*
-     *  Boot the Linux/m68k Operating System
-     */
-
-extern u_long linuxboot(const struct linuxboot_args *args);
-
-
-    /*
-     *  Amiga Models
-     */
-
-extern const char *amiga_models[];
-extern const u_long first_amiga_model;
-extern const u_long last_amiga_model;
-
-
-    /*
-     * Exec Library Definitions
-     */
-
-#define TRUE   (1)
-#define FALSE  (0)
-
-
-struct List {
-    struct Node *lh_Head;
-    struct Node *lh_Tail;
-    struct Node *lh_TailPred;
-    u_char lh_Type;
-    u_char l_pad;
-};
-
-struct MemChunk {
-     struct MemChunk *mc_Next; /* pointer to next chunk */
-     u_long mc_Bytes;          /* chunk byte size    */
-};
-
-#define MEMF_PUBLIC    (1<<0)
-#define MEMF_CHIP      (1<<1)
-#define MEMF_FAST      (1<<2)
-#define MEMF_LOCAL     (1<<8)
-#define MEMF_CLEAR     (1<<16)
-
-struct MemHeader {
-    struct Node mh_Node;
-    u_short mh_Attributes;     /* characteristics of this region */
-    struct MemChunk *mh_First; /* first free region */
-    void *mh_Lower;            /* lower memory bound */
-    void *mh_Upper;            /* upper memory bound+1 */
-    u_long mh_Free;            /* total number of free bytes */
-};
-
-struct ExecBase {
-    u_char fill1[20];
-    u_short Version;
-    u_char fill2[274];
-    u_short AttnFlags;
-    u_char fill3[24];
-    struct List MemList;
-    u_char fill4[194];
-    u_char VBlankFrequency;
-    u_char PowerSupplyFrequency;
-    u_char fill5[36];
-    u_long ex_EClockFrequency;
-    u_char fill6[60];
-};
-
-#define AFB_68020      (1)
-#define AFF_68020      (1<<AFB_68020)
-#define AFB_68030      (2)
-#define AFF_68030      (1<<AFB_68030)
-#define AFB_68040      (3)
-#define AFF_68040      (1<<AFB_68040)
-#define AFB_68881      (4)
-#define AFF_68881      (1<<AFB_68881)
-#define AFB_68882      (5)
-#define AFF_68882      (1<<AFB_68882)
-#define AFB_FPU40      (6)             /* ONLY valid if AFB_68040 or AFB_68060 */
-#define AFF_FPU40      (1<<AFB_FPU40)  /* is set; also set for 68060 FPU */
-#define AFB_68060      (7)
-#define AFF_68060      (1<<AFB_68060)
-
-struct Resident;
-
-
-    /*
-     * Graphics Library Definitions
-     */
-
-struct GfxBase {
-    u_char fill1[20];
-    u_short Version;
-    u_char fill2[194];
-    u_short NormalDisplayRows;
-    u_short NormalDisplayColumns;
-    u_char fill3[16];
-    u_char ChipRevBits0;
-    u_char fill4[307];
-};
-
-#define GFXB_HR_AGNUS  (0)
-#define GFXF_HR_AGNUS  (1<<GFXB_HR_AGNUS)
-#define GFXB_HR_DENISE (1)
-#define GFXF_HR_DENISE (1<<GFXB_HR_DENISE)
-#define GFXB_AA_ALICE  (2)
-#define GFXF_AA_ALICE  (1<<GFXB_AA_ALICE)
-#define GFXB_AA_LISA   (3)
-#define GFXF_AA_LISA   (1<<GFXB_AA_LISA)
-
-    /*
-     * HiRes(=Big) Agnus present; i.e. 
-     * 1MB chipmem, big blits (none of interest so far) and programmable sync
-     */
-#define GFXG_OCS       (GFXF_HR_AGNUS)
-    /*
-     * HiRes Agnus/Denise present; we are running on ECS
-     */
-#define GFXG_ECS       (GFXF_HR_AGNUS|GFXF_HR_DENISE)
-    /*
-     * Alice and Lisa present; we are running on AGA
-     */
-#define GFXG_AGA       (GFXF_AA_ALICE|GFXF_AA_LISA)
-
-#define SETCHIPREV_BEST        (0xffffffff)
-#define HIRES          (0x8000)
-
-struct View;
-
-
-    /*
-     * Amiga Shared Library/Device Functions
-     */
-
-extern const struct ExecBase *SysBase;
-
-#define LVOAllocMem            (-0xc6)
-#define LVOAllocVec            (-0x2ac)
-#define LVOCacheControl                (-0x288)
-#define LVODisable             (-0x78)
-#define LVOEnable              (-0x7e)
-#define LVOFindResident                (-0x60)
-#define LVOFreeMem             (-0xd2)
-#define LVOFreeVec             (-0x2b2)
-#define LVOOpenresource                (-0x1f2)
-#define LVOSuperState          (-0x96)
-#define LVOSupervisor          (-0x1e)
-
-static __inline void *AllocMem(u_long byteSize, u_long requirements)
-{
-    register void *_res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register u_long d0 __asm("d0") = byteSize;
-    register u_long d1 __asm("d1") = requirements;
-
-    __asm __volatile ("jsr a6@(-0xc6)"
-                     : "=r" (_res)
-                     : "r" (_base), "r" (d0), "r" (d1)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-static __inline void *AllocVec(u_long byteSize, u_long requirements)
-{
-    register void *_res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register u_long d0 __asm("d0") = byteSize;
-    register u_long d1 __asm("d1") = requirements;
-
-    __asm __volatile ("jsr a6@(-0x2ac)"
-                     : "=r" (_res)
-                     : "r" (_base), "r" (d0), "r" (d1)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-static __inline u_long CacheControl(u_long cacheBits, u_long cacheMask)
-{
-    register u_long _res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register u_long d0 __asm("d0") = cacheBits;
-    register u_long d1 __asm("d1") = cacheMask;
-
-    __asm __volatile ("jsr a6@(-0x288)"
-                     : "=r" (_res)
-                     : "r" (_base), "r" (d0), "r" (d1)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-static __inline void Disable(void)
-{
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-
-    __asm __volatile ("jsr a6@(-0x78)"
-                     : /* no output */
-                     : "r" (_base)
-                     : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void Enable(void)
-{
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-
-    __asm __volatile ("jsr a6@(-0x7e)"
-                     : /* no output */
-                     : "r" (_base)
-                     : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline struct Resident *FindResident(const u_char *name)
-{
-    register struct Resident *_res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register const u_char *a1 __asm("a1") = name;
-
-    __asm __volatile ("jsr a6@(-0x60)"
-                     : "=r" (_res)
-                     : "r" (_base), "r" (a1)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return _res;
-}
-
-static __inline void FreeMem(void *memoryBlock, u_long byteSize)
-{
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register void *a1 __asm("a1") = memoryBlock;
-    register u_long d0 __asm("d0") = byteSize;
-
-    __asm __volatile ("jsr a6@(-0xd2)"
-                     : /* no output */
-                     : "r" (_base), "r" (a1), "r" (d0)
-                     : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void FreeVec(void *memoryBlock)
-{
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register void *a1 __asm("a1") = memoryBlock;
-
-    __asm __volatile ("jsr a6@(-0x2b2)"
-                     : /* no output */
-                     : "r" (_base), "r" (a1)
-                     : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void *OpenResource(const u_char *resName)
-{
-    register void *_res  __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register const u_char *a1 __asm("a1") = resName;
-
-    __asm __volatile ("jsr a6@(-0x1f2)"
-                     : "=r" (_res)
-                     : "r" (_base), "r" (a1)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return _res;
-}
-
-static __inline void *SuperState(void)
-{
-    register void *_res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-
-    __asm __volatile ("jsr a6@(-0x96)"
-                     : "=r" (_res)
-                     : "r" (_base)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-static __inline u_long Supervisor(u_long (*userfunc)(void))
-{
-    register u_long _res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register u_long (*d7)() __asm("d7") = userfunc;
-
-    __asm __volatile ("exg d7,a5;"
-                     "jsr a6@(-0x1e);"
-                     "exg d7,a5"
-                     : "=r" (_res)
-                     : "r" (_base), "r" (d7)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-
-extern const struct ExpansionBase *ExpansionBase;
-
-#define LVOFindConfigDev       (-0x48)
-
-static __inline struct ConfigDev *FindConfigDev(struct ConfigDev *oldConfigDev,
-                                               long manufacturer, long product)
-{
-    register struct ConfigDev *_res __asm("d0");
-    register const struct ExpansionBase *_base __asm("a6") = ExpansionBase;
-    register struct ConfigDev *a0 __asm("a0") = oldConfigDev;
-    register long d0 __asm("d0") = manufacturer;
-    register long d1 __asm("d1") = product;
-
-    __asm __volatile ("jsr a6@(-0x48)"
-                     : "=r" (_res)
-                     : "r" (_base), "r" (a0), "r" (d0), "r" (d1)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-
-extern const struct GfxBase *GfxBase;
-
-#define LVOLoadView            (-0xde)
-#define LVOSetChipRev          (-0x378)
-
-static __inline void LoadView(struct View *view)
-{
-    register const struct GfxBase *_base __asm("a6") = GfxBase;
-    register struct View *a1 __asm("a1") = view;
-
-    __asm __volatile ("jsr a6@(-0xde)"
-                     : /* no output */
-                     : "r" (_base), "r" (a1)
-                     : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline u_long SetChipRev(u_long want)
-{
-    register u_long _res __asm("d0");
-    register const struct GfxBase *_base __asm("a6") = GfxBase;
-    register u_long d0 __asm("d0") = want;
-
-    __asm __volatile ("jsr a6@(-0x378)"
-                     : "=r" (_res)
-                     : "r" (_base), "r" (d0)
-                     : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-
-    /*
-     * Bootstrap Support Functions
-     */
-
-static __inline void disable_mmu(void)
-{
-    if (SysBase->AttnFlags & AFF_68040)
-       __asm __volatile ("moveq #0,d0;"
-                         ".long 0x4e7b0003;"   /* movec d0,tc */
-                         ".long 0x4e7b0004;"   /* movec d0,itt0 */
-                         ".long 0x4e7b0005;"   /* movec d0,itt1 */
-                         ".long 0x4e7b0006;"   /* movec d0,dtt0 */
-                         ".long 0x4e7b0007"    /* movec d0,dtt1 */
-                         : /* no outputs */
-                         : /* no inputs */
-                         : "d0");
-    else {
-       __asm __volatile ("subl #4,sp;"
-                         "pmove tc,sp@;"
-                         "bclr #7,sp@;"
-                         "pmove sp@,tc;"
-                         "addl #4,sp");
-       if (SysBase->AttnFlags & AFF_68030)
-           __asm __volatile ("clrl sp@-;"
-                             ".long 0xf0170800;"       /* pmove sp@,tt0 */
-                             ".long 0xf0170c00;"       /* pmove sp@,tt1 */
-                             "addql #4,sp");
-    }
-}
diff --git a/arch/m68k/boot/atari/bootp.c b/arch/m68k/boot/atari/bootp.c
deleted file mode 100644 (file)
index affe636..0000000
+++ /dev/null
@@ -1,814 +0,0 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bootp.h"
-
-
-/* --------------------------------------------------------------------- */
-/*                                               Protocol Header Structures                                     */
-
-struct etherhdr {
-       HWADDR                  dst_addr;
-       HWADDR                  src_addr;
-       unsigned short  type;
-};
-
-struct arphdr {
-       unsigned short  hrd;            /* format of hardware address   */
-       unsigned short  pro;            /* format of protocol address   */
-       unsigned char   hln;            /* length of hardware address   */
-       unsigned char   pln;            /* length of protocol address   */
-       unsigned short  op;                     /* ARP opcode (command)                 */
-       unsigned char   addr[0];        /* addresses (var len)                  */
-};
-       
-struct iphdr {
-       unsigned char   version : 4;
-       unsigned char   ihl : 4;
-       unsigned char   tos;
-       unsigned short  tot_len;
-       unsigned short  id;
-       unsigned short  frag_off;
-       unsigned char   ttl;
-       unsigned char   protocol;
-       unsigned short  chksum;
-       IPADDR                  src_addr;
-       IPADDR                  dst_addr;
-};
-
-struct udphdr {
-       unsigned short  src_port;
-       unsigned short  dst_port;
-       unsigned short  len;
-       unsigned short  chksum;
-};
-
-struct bootp {
-       unsigned char   op;                     /* packet opcode type */
-       unsigned char   htype;          /* hardware addr type */
-       unsigned char   hlen;           /* hardware addr length */
-       unsigned char   hops;           /* gateway hops */
-       unsigned long   xid;            /* transaction ID */
-       unsigned short  secs;           /* seconds since boot began */
-       unsigned short  unused;
-       IPADDR                  ciaddr;         /* client IP address */
-       IPADDR                  yiaddr;         /* 'your' IP address */
-       IPADDR                  siaddr;         /* server IP address */
-       IPADDR                  giaddr;         /* gateway IP address */
-       unsigned char   chaddr[16];     /* client hardware address */
-       unsigned char   sname[64];      /* server host name */
-       unsigned char   file[128];      /* boot file name */
-       unsigned char   vend[64];       /* vendor-specific area */
-};
-
-struct tftp_req {
-       unsigned short  opcode;
-       char                    name[512];
-};
-
-struct tftp_data {
-       unsigned short  opcode;
-       unsigned short  nr;
-       unsigned char   data[512];
-};
-
-struct tftp_ack {
-       unsigned short  opcode;
-       unsigned short  nr;
-};
-
-struct tftp_error {
-       unsigned short  opcode;
-       unsigned short  errcode;
-       char                    str[512];
-};
-
-
-typedef struct {
-       struct etherhdr         ether;
-       struct arphdr           arp;
-} ARP;
-
-typedef struct {
-       struct etherhdr         ether;
-       struct iphdr            ip;
-       struct udphdr           udp;
-} UDP;
-
-#define        UDP_BOOTPS      67
-#define        UDP_BOOTPC      68
-#define        UDP_TFTP        69
-
-typedef struct {
-       struct etherhdr         ether;
-       struct iphdr            ip;
-       struct udphdr           udp;
-       struct bootp            bootp;
-} BOOTP;
-
-#define        BOOTREQUEST             1
-#define        BOOTREPLY               2
-#define        BOOTP_RETRYS    5
-
-typedef struct {
-       struct etherhdr         ether;
-       struct iphdr            ip;
-       struct udphdr           udp;
-       union tftp {
-               unsigned short          opcode;
-               struct tftp_req         req;
-               struct tftp_data        data;
-               struct tftp_ack         ack;
-               struct tftp_error       error;
-       } tftp;
-} TFTP;
-       
-#define        TFTP_RRQ        1
-#define        TFTP_WRQ        2
-#define        TFTP_DATA       3
-#define        TFTP_ACK        4
-#define        TFTP_ERROR      5
-
-
-/* --------------------------------------------------------------------- */
-/*                                                               Addresses                                                              */
-
-static HWADDR  MyHwaddr;
-static HWADDR  ServerHwaddr;
-static IPADDR  MyIPaddr;
-static IPADDR  ServerIPaddr;
-
-static IPADDR  IP_Unknown_Addr =   0x00000000;
-static IPADDR  IP_Broadcast_Addr = 0xffffffff;
-static HWADDR  Eth_Broadcast_Addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-
-#define        HZ      200
-#define        _hz_200 (*(volatile unsigned long *)0x4ba)
-
-
-/* --------------------------------------------------------------------- */
-/*                                                             Error Strings                                                    */
-
-static char *ErrStr[] = {
-       "timeout",
-       "general Ethernet transmit error",
-       "general Ethernet receive error",
-       "Ethernet framing error",
-       "Ethernet overflow error",
-       "Ethernet CRC error"
-};
-
-
-/* --------------------------------------------------------------------- */
-/*                                              Kfile Emulation Definitions                                     */
-
-#define        KFILE_CHUNK_BITS        16  /* chunk is 64 KB */
-#define        KFILE_CHUNK_SIZE        (1 << KFILE_CHUNK_BITS)
-#define        KFILE_CHUNK_MASK        (KFILE_CHUNK_SIZE-1)
-#define        KFILE_N_CHUNKS          (2*1024*1024/KFILE_CHUNK_SIZE)
-
-char *KFile[KFILE_N_CHUNKS];
-int  KFileSize = 0;
-int     KFpos = 0;
-
-
-
-
-/***************************** Prototypes *****************************/
-
-static void free_kfile( void );
-static int bootp( char *image_name );
-static int tftp( char *image_name );
-static int udp_send( UDP *pkt, int len, int fromport, int toport );
-static unsigned short ip_checksum( struct iphdr *buf );
-static int udp_rcv( UDP *pkt, int *len, int fromport, int atport );
-static void print_ip( IPADDR addr );
-static void print_hw( HWADDR addr );
-static int check_ethif( void );
-static int eth_send( Packet *pkt, int len );
-static int eth_rcv( Packet *pkt, int *len );
-
-/************************* End of Prototypes **************************/
-
-
-
-
-/* --------------------------------------------------------------------- */
-/*                                                Interface to bootstrap.c                                              */
-
-/* get_remote_kernel():
- * Perform all necessary steps to get the kernel image
- * from the boot server. If successfull (retval == 0), subsequent calls to
- * kread() can access the data. Fatal errors (i.e., retrying is useless)
- * return -2, others -1.
- */
-
-int get_remote_kernel( const char *kname /* optional */ )
-
-{      char    image_name[256];
-       int             rv;
-
-       /* Check if a Ethernet interface is present and determine the Ethernet
-        * address */
-       if (check_ethif() < 0) {
-               printf( "No Ethernet interface found -- no remote boot possible.\n" );
-               return( -2 );
-       }
-       
-       /* Do a BOOTP request to find out our IP address and the kernel image's
-        * name; we also learn the IP and Ethernet address of our server */
-       if (kname)
-               strcpy( image_name, kname );
-       else
-               *image_name = 0;
-       if ((rv = bootp( image_name )) < 0)
-               return( rv );
-       
-       /* Now start a TFTP connection to receive the kernel image */
-       if ((rv = tftp( image_name )) < 0)
-               return( rv );
-
-       return( 0 );
-}
-
-
-/* ll_read(), ll_lseek(), ll_close():
- * Functions for accessing the received kernel image like with read(),
- * lseek(), close().
- */
-
-int ll_read( int fd, void *buf, unsigned cnt )
-
-{      unsigned done = 0;
-       
-       if (!KFileSize)
-               return( read( fd, buf, cnt ) );
-
-       if (KFpos + cnt > KFileSize)
-               cnt = KFileSize - KFpos;
-       
-       while( cnt > 0 ) {
-               unsigned chunk = KFpos >> KFILE_CHUNK_BITS;
-               unsigned endchunk = (chunk+1) << KFILE_CHUNK_BITS;
-               unsigned n = cnt;
-
-               if (KFpos + n > endchunk)
-                       n = endchunk - KFpos;
-               memcpy( buf, KFile[chunk] + (KFpos & KFILE_CHUNK_MASK), n );
-               cnt -= n;
-               buf += n;
-               done += n;
-               KFpos += n;
-
-               if (KFpos == endchunk) {
-                       free( KFile[chunk] );
-                       KFile[chunk] = NULL;
-               }
-       }
-
-       return( done );
-}
-
-
-int ll_lseek( int fd, int where, int whence )
-
-{
-    unsigned oldpos, oldchunk, newchunk;
-
-       if (!KFileSize)
-               return( lseek( fd, where, whence ) );
-
-    oldpos = KFpos;
-       switch( whence ) {
-         case SEEK_SET:
-               KFpos = where;
-               break;
-         case SEEK_CUR:
-               KFpos += where;
-               break;
-         case SEEK_END:
-               KFpos = KFileSize + where;
-               break;
-         default:
-               return( -1 );
-       }
-       if (KFpos < 0) {
-               KFpos = 0;
-               return( -1 );
-       }
-       else if (KFpos > KFileSize) {
-               KFpos = KFileSize;
-               return( -1 );
-       }
-
-    /* free memory of skipped-over data */
-    oldchunk = oldpos >> KFILE_CHUNK_BITS;
-    newchunk = KFpos  >> KFILE_CHUNK_BITS;
-    while( oldchunk < newchunk ) {
-               if (KFile[oldchunk]) {
-                       free( KFile[oldchunk] );
-                       KFile[oldchunk] = NULL;
-               }
-               ++oldchunk;
-    }
-    
-       return( KFpos );
-}
-
-
-int ll_close( int fd )
-
-{
-       if (!KFileSize)
-               return( close( fd ) );
-
-       free_kfile();
-       return( 0 );
-}
-
-
-static void free_kfile( void )
-
-{      int             i;
-
-       for( i = 0; i < KFILE_N_CHUNKS; ++i )
-               if (KFile[i]) free( KFile[i] );
-}
-
-
-
-/* --------------------------------------------------------------------- */
-/*                                                        BOOTP Procedure                                                       */
-
-
-static int bootp( char *image_name )
-
-{      BOOTP   req;
-       Packet  _reply;
-       BOOTP   *reply = (BOOTP *)_reply;
-       static unsigned char mincookie[] = { 99, 130, 83, 99, 255 };
-       unsigned long   starttime, rancopy;
-       int                             err, len, retry;
-       
-       memset( (char *)&req, 0, sizeof(req) );
-       /* Now fill in the packet... */
-       req.bootp.op = BOOTREQUEST;
-       req.bootp.htype = 1; /* 10Mb/s Ethernet */
-       req.bootp.hlen = 6;
-       memcpy( req.bootp.chaddr, &MyHwaddr, ETHADDRLEN );
-
-       /* Put in the minimal RFC1497 Magic cookie */
-       memcpy( req.bootp.vend, mincookie, sizeof(mincookie) );
-       /* Put the user precified bootfile name in place */
-       memcpy( req.bootp.file, image_name, strlen(image_name)+1);
-
-       starttime = _hz_200;
-       for( retry = 0; retry < BOOTP_RETRYS; ++retry ) {
-
-               /* Initialize server addresses and own IP to defaults */
-               ServerIPaddr = IP_Broadcast_Addr;  /* 255.255.255.255 */
-               MyIPaddr     = IP_Unknown_Addr;    /* 0.0.0.0 */
-               memcpy( ServerHwaddr, Eth_Broadcast_Addr, ETHADDRLEN );
-
-               if (retry)
-                       sleep( 3 );
-               
-               req.bootp.xid = rancopy = _hz_200;
-               req.bootp.secs = (_hz_200 - starttime) / HZ;
-
-               if ((err = udp_send( (UDP *)&req, sizeof(req.bootp),
-                                                        UDP_BOOTPC, UDP_BOOTPS )) < 0) {
-                       printf( "bootp send: %s\n", ErrStr[-err-1] );
-                       continue;
-               }
-               
-               if ((err = udp_rcv( (UDP *)reply, &len,
-                                                       UDP_BOOTPS, UDP_BOOTPC )) < 0) {
-                       printf( "bootp rcv: %s\n", ErrStr[-err-1] );
-                       continue;
-               }
-               if (len < sizeof(struct bootp)) {
-                       printf( "received short BOOTP packet (%d bytes)\n", len );
-                       continue;
-               }
-
-               if (reply->bootp.xid == rancopy)
-                       /* Ok, got the answer */
-                       break;
-               printf( "bootp: xid mismatch\n" );
-       }
-       if (retry >= BOOTP_RETRYS) {
-               printf( "No response from a bootp server\n" );
-               return( -2 );
-       }
-       
-       ServerIPaddr = reply->bootp.siaddr;
-       memcpy( ServerHwaddr, reply->ether.src_addr, ETHADDRLEN );
-       printf( "\nBoot server is " );
-       if (strlen(reply->bootp.sname) > 0)
-               printf( "%s, IP ", reply->bootp.sname );
-       print_ip( ServerIPaddr );
-       printf( ", HW address " );
-       print_hw( ServerHwaddr );
-       printf( "\n" );
-
-       MyIPaddr = reply->bootp.yiaddr;
-       printf( "My IP address is " );
-       print_ip( MyIPaddr );
-       printf( "\n" );
-
-       strcpy( image_name, reply->bootp.file );
-       return( 0 );
-}
-
-
-/* --------------------------------------------------------------------- */
-/*                                                             TFTP Procedure                                                   */
-
-
-static int tftp( char *image_name )
-
-{      TFTP    spkt;
-       Packet  _rpkt;
-       TFTP    *rpkt = (TFTP *)&_rpkt;
-       unsigned short  mytid, rtid = 0;
-       int                             blk, retries, i, wpos, err, len, datalen;
-       static char             rotchar[4] = { '|', '/', '-', '\\' };
-       
-       retries = 5;
-       /* Construct and send a read request */
-  repeat_req:
-       spkt.tftp.req.opcode = TFTP_RRQ;
-       strcpy( spkt.tftp.req.name, image_name );
-       strcpy( spkt.tftp.req.name + strlen(spkt.tftp.req.name) + 1, "octet" );
-       mytid = _hz_200 & 0xffff;
-       
-       if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.req.opcode) +
-                                                                          strlen(image_name) + 1 +
-                                                                          strlen( "octect" ) +1,
-                                                mytid, UDP_TFTP )) < 0) {
-               printf( "TFTP RREQ: %s\n", ErrStr[-err-1] );
-               if (--retries > 0)
-                       goto repeat_req;
-               return( err == ETIMEO ? -2 : -1 );
-       }
-
-       retries = 5;
-       for( i = 0; i < KFILE_N_CHUNKS; ++i )
-               KFile[i] = NULL;
-       wpos = 0;
-       printf( "Receiving kernel image %s:\n", image_name );
-
-       for( blk = 1; ; ++blk ) {
-
-         repeat_data:
-               if ((err = udp_rcv( (UDP *)rpkt, &len, rtid, mytid )) < 0) {
-                       printf( "TFTP rcv: %s\n", ErrStr[-err-1] );
-                       if (--retries > 0)
-                               goto repeat_data;
-                       goto err;
-               }
-               if (rtid == 0)
-                       /* Store the remote port at the first packet received */
-                       rtid = rpkt->udp.src_port;
-
-               if (rpkt->tftp.opcode == TFTP_ERROR) {
-                       if (strlen(rpkt->tftp.error.str) > 0)
-                               printf( "TFTP error: %s\n", rpkt->tftp.error.str );
-                       else
-                               printf( "TFTP error #%d (no description)\n",
-                                               rpkt->tftp.error.errcode );
-                       goto err;
-               }
-               else if (rpkt->tftp.opcode != TFTP_DATA) {
-                       printf( "Bad TFTP packet type: %d\n", rpkt->tftp.opcode );
-                       if (--retries > 0)
-                               goto repeat_data;
-                       goto err;
-               }
-
-               if (rpkt->tftp.data.nr != blk) {
-                       /* doubled data packet; ignore it */
-                       goto repeat_data;
-               }
-               datalen = len - sizeof(rpkt->tftp.data.opcode) -
-                                   sizeof(rpkt->tftp.data.nr);
-               
-               /* store data */
-               if (datalen > 0) {
-                       int chunk = wpos >> KFILE_CHUNK_BITS;
-                       if (chunk >= KFILE_N_CHUNKS) {
-                               printf( "TFTP: file too large! Aborting.\n" );
-                         out_of_mem:
-                               spkt.tftp.error.opcode = TFTP_ERROR;
-                               spkt.tftp.error.errcode = 3;
-                               strcpy( spkt.tftp.error.str, "Out of memory" );
-                               udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack), mytid, rtid );
-                               goto err;
-                       }
-                       if (!KFile[chunk]) {
-                               if (!(KFile[chunk] = malloc( KFILE_CHUNK_SIZE ))) {
-                                       printf( "TFTP: Out of memory for kernel image\n" );
-                                       goto out_of_mem;
-                               }
-                       }
-                       memcpy( KFile[chunk] + (wpos & KFILE_CHUNK_MASK),
-                                       rpkt->tftp.data.data, datalen );
-                       wpos += datalen;
-
-#define        DISPLAY_BITS 13
-                       if ((wpos & ((1 << DISPLAY_BITS)-1)) == 0) {
-                               printf( "\r %c %7d Bytes ",
-                                               rotchar[(wpos>>DISPLAY_BITS)&3], wpos );
-                               fflush( stdout );
-                       }
-               }
-
-               /* Send ACK packet */
-         repeat_ack:
-               spkt.tftp.ack.opcode = TFTP_ACK;
-               spkt.tftp.ack.nr = blk;
-               if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack),
-                                                        mytid, rtid )) < 0) {
-                       printf( "TFTP ACK: %s\n", ErrStr[-err-1] );
-                       if (--retries > 0)
-                               goto repeat_ack;
-                       goto err;
-               }
-
-               if (datalen < 512) {
-                       /* This was the last packet */
-                       printf( "\r   %7d Bytes done\n\n", wpos );
-                       break;
-               }
-
-               retries = 5;
-       }
-
-       KFileSize = wpos;
-       return( 0 );
-
-  err:
-       free_kfile();
-       return( -1 );
-}
-
-
-
-/* --------------------------------------------------------------------- */
-/*                               UDP/IP Protocol Quick Hack Implementation                              */
-
-
-static int udp_send( UDP *pkt, int len, int fromport, int toport )
-
-{
-       /* UDP layer */
-       pkt->udp.src_port = fromport;
-       pkt->udp.dst_port = toport;
-       pkt->udp.len      = (len += sizeof(struct udphdr));
-       pkt->udp.chksum   = 0; /* Too lazy to calculate :-) */
-
-       /* IP layer */
-       pkt->ip.version  = 4;
-       pkt->ip.ihl      = 5;
-       pkt->ip.tos      = 0;
-       pkt->ip.tot_len  = (len += sizeof(struct iphdr));
-       pkt->ip.id       = 0;
-       pkt->ip.frag_off = 0;
-       pkt->ip.ttl      = 255;
-       pkt->ip.protocol = 17; /* UDP */
-       pkt->ip.src_addr = MyIPaddr;
-       pkt->ip.dst_addr = ServerIPaddr;
-       pkt->ip.chksum   = 0;
-       pkt->ip.chksum   = ip_checksum( &pkt->ip );
-
-       /* Ethernet layer */
-       memcpy( &pkt->ether.dst_addr, ServerHwaddr, ETHADDRLEN );
-       memcpy( &pkt->ether.src_addr, MyHwaddr, ETHADDRLEN );
-       pkt->ether.type     = 0x0800;
-       len += sizeof(struct etherhdr);
-
-       return( eth_send( (Packet *)pkt, len ) );
-}
-
-
-static unsigned short ip_checksum( struct iphdr *buf )
-
-{      unsigned long sum = 0, wlen = 5;
-
-       __asm__ ("subqw #1,%2\n"
-                        "1:\t"
-                        "movel %1@+,%/d0\n\t"
-                        "addxl %/d0,%0\n\t"
-                        "dbra %2,1b\n\t"
-                        "movel %0,%/d0\n\t"
-                        "swap %/d0\n\t"
-                        "addxw %/d0,%0\n\t"
-                        "clrw %/d0\n\t"
-                        "addxw %/d0,%0"
-                        : "=d" (sum), "=a" (buf), "=d" (wlen)
-                        : "0" (sum), "1" (buf), "2" (wlen)
-                        : "d0");
-       return( (~sum) & 0xffff );
-}
-
-
-static int udp_rcv( UDP *pkt, int *len, int fromport, int atport )
-
-{      int                             err;
-
-  repeat:
-       if ((err = eth_rcv( (Packet *)pkt, len )))
-               return( err );
-       
-       /* Ethernet layer */
-       if (pkt->ether.type == 0x0806) {
-               /* ARP */
-               ARP *pk = (ARP *)pkt;
-               unsigned char *shw, *sip, *thw, *tip;
-
-               if (pk->arp.hrd != 1 || pk->arp.pro != 0x0800 ||
-                       pk->arp.op != 1 || MyIPaddr == IP_Unknown_Addr)
-                       /* Wrong hardware type or protocol; or reply -> ignore */
-                       goto repeat;
-               shw = pk->arp.addr;
-               sip = shw + pk->arp.hln;
-               thw = sip + pk->arp.pln;
-               tip = thw + pk->arp.hln;
-               
-               if (memcmp( tip, &MyIPaddr, pk->arp.pln ) == 0) {
-                       memcpy( thw, shw, pk->arp.hln );
-                       memcpy( tip, sip, pk->arp.pln );
-                       memcpy( shw, &MyHwaddr, pk->arp.hln );
-                       memcpy( sip, &MyIPaddr, pk->arp.pln );
-
-                       memcpy( &pk->ether.dst_addr, thw, ETHADDRLEN );
-                       memcpy( &pk->ether.src_addr, &MyHwaddr, ETHADDRLEN );
-                       eth_send( (Packet *)pk, *len );
-               }
-               goto repeat;
-       }
-       else if (pkt->ether.type != 0x0800) {
-               printf( "Unknown Ethernet packet type %04x received\n",
-                               pkt->ether.type );
-               goto repeat;
-       }
-
-       /* IP layer */
-       if (MyIPaddr != IP_Unknown_Addr && pkt->ip.dst_addr != MyIPaddr) {
-               printf( "Received packet for wrong IP address\n" );
-               goto repeat;
-       }
-       if (ServerIPaddr != IP_Unknown_Addr &&
-               ServerIPaddr != IP_Broadcast_Addr &&
-               pkt->ip.src_addr != ServerIPaddr) {
-               printf( "Received packet from wrong server\n" );
-               goto repeat;
-       }
-       /* If IP header is longer than 5 longs, delete the options */
-       if (pkt->ip.ihl > 5) {
-               char *udpstart = (char *)((long *)&pkt->ip + pkt->ip.ihl);
-               memmove( &pkt->udp, udpstart, *len - (udpstart-(char *)pkt) );
-       }
-       
-       /* UDP layer */
-       if (fromport != 0 && pkt->udp.src_port != fromport) {
-               printf( "Received packet from wrong port %d\n", pkt->udp.src_port );
-               goto repeat;
-       }
-       if (pkt->udp.dst_port != atport) {
-               printf( "Received packet at wrong port %d\n", pkt->udp.dst_port );
-               goto repeat;
-       }
-
-       *len = pkt->udp.len - sizeof(struct udphdr);
-       return( 0 );
-}
-
-
-/* --------------------------------------------------------------------- */
-/*                                                        Address Printing                                                      */
-
-
-static void print_ip( IPADDR addr )
-
-{
-       printf( "%ld.%ld.%ld.%ld",
-                       (addr >> 24) & 0xff,
-                       (addr >> 16) & 0xff,
-                       (addr >>  8) & 0xff,
-                       addr & 0xff );
-}
-
-
-static void print_hw( HWADDR addr )
-
-{
-       printf( "%02x:%02x:%02x:%02x:%02x:%02x",
-                       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] );
-}
-
-
-/* --------------------------------------------------------------------- */
-/*                                      Ethernet Interface Abstraction Layer                            */
-
-
-#ifdef ETHLL_LANCE
-#include "ethlance.h"
-#endif
-
-static ETHIF_SWITCH *PossibleInterfaces[] = {
-#ifdef ETHLL_LANCE
-       &LanceSwitch,
-#endif
-};
-
-#define        N_PossibleInterfaces (sizeof(PossibleInterfaces)/sizeof(*PossibleInterfaces))
-
-/* Detected interface */
-static ETHIF_SWITCH *Ethif = NULL;
-
-
-static int check_ethif( void )
-
-{      int i;
-
-       /* Check for configured interfaces */
-       Ethif = NULL;
-       for( i = 0; i < N_PossibleInterfaces; ++i ) {
-               if (PossibleInterfaces[i]->probe() >= 0) {
-                       Ethif = PossibleInterfaces[i];
-                       break;
-               }
-       }
-       if (!Ethif)
-               return( -1 );
-
-       if (Ethif->init() < 0) {
-               printf( "Ethernet interface initialization failed\n" );
-               return( -1 );
-       }
-       Ethif->get_hwaddr( &MyHwaddr );
-       return( 0 );
-}
-
-
-static int eth_send( Packet *pkt, int len )
-
-{
-       return( Ethif->snd( pkt, len ));
-}
-
-
-static int eth_rcv( Packet *pkt, int *len )
-
-{
-       return( Ethif->rcv( pkt, len ));
-}
-
-
-#if 0
-static void dump_packet( UDP *pkt )
-
-{      int             i, l;
-       unsigned char *p;
-       
-       printf( "Packet dump:\n" );
-
-       printf( "Ethernet header:\n" );
-       printf( "  dst addr: " ); print_hw( pkt->ether.dst_addr ); printf( "\n" );
-       printf( "  src addr: " ); print_hw( pkt->ether.src_addr ); printf( "\n" );
-       printf( "  type: %04x\n", pkt->ether.type );
-
-       printf( "IP header:\n" );
-       printf( "  version: %d\n", pkt->ip.version );
-       printf( "  hdr len: %d\n", pkt->ip.ihl );
-       printf( "  tos: %d\n", pkt->ip.tos );
-       printf( "  tot_len: %d\n", pkt->ip.tot_len );
-       printf( "  id: %d\n", pkt->ip.id );
-       printf( "  frag_off: %d\n", pkt->ip.frag_off );
-       printf( "  ttl: %d\n", pkt->ip.ttl );
-       printf( "  prot: %d\n", pkt->ip.protocol );
-       printf( "  src addr: " ); print_ip( pkt->ip.src_addr ); printf( "\n" );
-       printf( "  dst addr: " ); print_ip( pkt->ip.dst_addr ); printf( "\n" );
-
-       printf( "UDP header:\n" );
-       printf( "  src port: %d\n", pkt->udp.src_port );
-       printf( "  dst port: %d\n", pkt->udp.dst_port );
-       printf( "  len: %d\n", pkt->udp.len );
-
-       printf( "Data:" );
-       l = pkt->udp.len - sizeof(pkt->udp);
-       p = (unsigned char *)&pkt->udp + sizeof(pkt->udp);
-       for( i = 0; i < l; ++i ) {
-               if ((i % 32) == 0)
-                       printf( "\n  %04x ", i );
-               printf( "%02x ", *p );
-       }
-       printf( "\n" );
-}
-#endif
diff --git a/arch/m68k/boot/atari/bootp.h b/arch/m68k/boot/atari/bootp.h
deleted file mode 100644 (file)
index 0ee96cd..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _bootp_h
-#define _bootp_h
-
-/* --------------------------------------------------------------------- */
-/*                                                      Ethernet Definitions                                            */
-
-#define        PKTLEN                  1544
-typedef unsigned char  Packet[PKTLEN];
-
-#define        ETHADDRLEN              6
-typedef unsigned char  HWADDR[ETHADDRLEN];
-
-typedef struct {
-       int             (*probe)( void );
-       int             (*init)( void );
-       void    (*get_hwaddr)( HWADDR *addr );
-       int             (*snd)( Packet *pkt, int len );
-       int             (*rcv)( Packet *pkt, int *len );
-} ETHIF_SWITCH;
-
-
-/* error codes */
-#define        ETIMEO  -1              /* Timeout */
-#define        ESEND   -2              /* General send error (carrier, abort, ...) */
-#define        ERCV    -3              /* General receive error */
-#define        EFRAM   -4              /* Framing error */
-#define        EOVERFL -5              /* Overflow (too long packet) */
-#define        ECRC    -6              /* CRC error */
-
-
-typedef unsigned long IPADDR;
-
-
-/***************************** Prototypes *****************************/
-
-int get_remote_kernel( const char *kname );
-int ll_read( int fd, void *buf, unsigned cnt );
-int ll_lseek( int fd, int where, int whence );
-int ll_close( int fd );
-
-/************************* End of Prototypes **************************/
-
-#endif  /* _bootp_h */
-
diff --git a/arch/m68k/boot/atari/bootstrap.c b/arch/m68k/boot/atari/bootstrap.c
deleted file mode 100644 (file)
index 84c6a6e..0000000
+++ /dev/null
@@ -1,1602 +0,0 @@
-/*
-** bootstrap.c -- Load and launch the Atari Linux kernel
-**
-** Copyright 1993 by Arjan Knor
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-** History:
-**     01 Feb 1997 Implemented kernel decompression (Roman)
-**     28 Nov 1996 Fixed and tested previous change (James)
-**     27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
-**     12 Nov 1996 Fixed and tested previous change (Andreas)
-**     18 Aug 1996 Updated for the new boot information structure (untested!)
-**                 (Geert)
-**     10 Dec 1995 BOOTP/TFTP support (Roman)
-**     03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas)
-**     11 Jul 1995 Add support for ELF format kernel (Andreas)
-**     16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram
-**                 (Andreas)
-**      14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
-**                 start address is KSTART_ADDR + PAGE_SIZE, this
-**                 does not need the ugly kludge with
-**                 -fwritable-strings (++andreas)
-**      09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
-**                  mentions all ST-Ram and the mover is located somewhere
-**                  in the middle of memory (roman)
-**                  Added the default arguments file known from the other
-**                  bootstrap version
-**      19 Feb 1994 Changed everything so that it works? (rdv)
-**      14 Mar 1994 New mini-copy routine used (rdv)
-*/
-
-
-#define BOOTINFO_COMPAT_1_0    /* bootinfo interface version 1.0 compatible */
-/* support compressed kernels? */
-#define ZKERNEL
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
-#include <string.h>
-#include <ctype.h>
-#include "sysvars.h"
-#include <osbind.h>
-#include <sys/types.h>
-#include <sys/file.h>
-
-/* linux specific include files */
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <asm/page.h>
-
-#define _LINUX_TYPES_H         /* Hack to prevent including <linux/types.h> */
-#include <asm/bootinfo.h>
-#include <asm/setup.h>
-
-/* Atari bootstrap include file */
-#include "bootstrap.h"
-
-#define MIN_RAMSIZE     (3)    /* 3 MB */
-#define TEMP_STACKSIZE 256
-
-extern char *optarg;
-extern int optind;
-static void get_default_args( int *argc, char ***argv );
-static int create_bootinfo(void);
-#ifdef BOOTINFO_COMPAT_1_0
-static int create_compat_bootinfo(void);
-#endif /* BOOTINFO_COMPAT_1_0 */
-static int add_bi_record(u_short tag, u_short size, const void *data);
-static int add_bi_string(u_short tag, const u_char *s);
-/* This is missing in <unistd.h> */
-extern int sync (void);
-
-/* Bootinfo */
-static struct atari_bootinfo bi;
-
-#ifdef BOOTINFO_COMPAT_1_0
-static struct compat_bootinfo compat_bootinfo;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-#define MAX_BI_SIZE     (4096)
-static u_long bi_size;
-static union {
-struct bi_record record;
-    u_char fake[MAX_BI_SIZE];
-} bi_union;
-
-u_long *cookiejar;
-u_long userstk;
-
-/* getcookie -- function to get the value of the given cookie. */
-static int getcookie(char *cookie, u_long *value)
-{
-    int i = 0;
-
-    while(cookiejar[i] != 0L) {
-       if(cookiejar[i] == *(u_long *)cookie) {
-           *value = cookiejar[i + 1];
-           return 1;
-       }
-       i += 2;
-    }
-    return -1;
-}
-
-static void usage(void)
-{
-    fprintf(stderr, "Usage:\n"
-           "\tbootstrap [-dst] [-k kernel_executable] [-r ramdisk_file]"
-           " [option...]\n");
-    exit(EXIT_FAILURE);
-}
-
-/*
- * Copy the kernel and the ramdisk to their final resting places.
- *
- * I assume that the kernel data and the ramdisk reside somewhere
- * in the middle of the memory.
- *
- * This program itself should be somewhere in the first 4096 bytes of memory
- * where the kernel never will be. In this way it can never be overwritten
- * by itself.
- *
- * At this point the registers have:
- * a0: the start of the final kernel
- * a1: the start of the current kernel
- * a2: the end of the final ramdisk
- * a3: the end of the current ramdisk
- * d0: the kernel size
- * d1: the ramdisk size 
- */
-asm ("
-.text
-.globl _copyall, _copyallend
-_copyall:
-
-       movel   a0,a4           /* save the start of the kernel for booting */
-
-1:     movel   a1@+,a0@+       /* copy the kernel starting at the beginning */
-       subql   #4,d0
-       jcc     1b
-
-       tstl    d1
-       beq             3f
-
-2:     movel   a3@-,a2@-       /* copy the ramdisk starting at the end */
-       subql   #4,d1
-       jcc     2b
-
-3:     jmp     a4@             /* jump to the start of the kernel */
-_copyallend:
-");
-
-extern char copyall, copyallend;
-
-
-/* Test for a Medusa: This is the only machine on which address 0 is
- * writeable!
- * ...err! On the Afterburner040 (for the Falcon) it's the same... So we do
- * another test with 0x00ff82fe, that gives a bus error on the Falcon, but is
- * in the range where the Medusa always asserts DTACK.
- * On the Hades address 0 is writeable as well and it asserts DTACK on
- * address 0x00ff82fe. To test if the machine is a Hades, address 0xb0000000
- * is tested. On the Medusa this gives a bus error.
- */
-
-int test_medusa( void )
-
-{      int             rv = 0;
-
-       __asm__ __volatile__
-               ( "movel        0x8,a0\n\t"
-                 "movel        sp,a1\n\t"
-                 "moveb        0x0,d1\n\t"
-                 "movel        #Lberr,0x8\n\t"
-                 "moveq        #0,%0\n\t"
-                 "clrb         0x0\n\t"
-                 "nop          \n\t"
-                 "moveb        d1,0x0\n\t"
-                 "nop          \n\t"
-                 "tstb         0x00ff82fe\n\t"
-                 "nop          \n\t"
-                 "moveq        #1,%0\n\t"
-                 "tstb         0xb0000000\n\t"
-                 "nop          \n\t"
-                 "moveq        #0,%0\n"
-               "Lberr:\t"
-                 "movel        a1,sp\n\t"
-                 "movel        a0,0x8"
-                 : "=d" (rv)
-                 : /* no inputs */
-                 : "d1", "a0", "a1", "memory" );
-
-       return( rv );
-}
-
-
-/* Test if FPU instructions are executed in hardware, or if they're
-   emulated in software.  For this, the F-line vector is temporarily
-   replaced. */
-
-int test_software_fpu(void)
-{
-       int rv = 0;
-
-       __asm__ __volatile__
-               ( "movel        0x2c,a0\n\t"
-                 "movel        sp,a1\n\t"
-                 "movel        #Lfline,0x2c\n\t"
-                 "moveq        #1,%0\n\t"
-                 "fnop         \n\t"
-                 "nop          \n\t"
-                 "moveq        #0,%0\n"
-               "Lfline:\t"
-                 "movel        a1,sp\n\t"
-                 "movel        a0,0x2c"
-                 : "=d" (rv)
-                 : /* no inputs */
-                 : "a0", "a1" );
-
-       return rv;
-}
-
-
-void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 )
-
-{      static u_long   save_addr;
-       u_long                  test_base, saved_contents[16];
-#define        TESTADDR(i)     (*((u_long *)((char *)test_base + i*8*MB)))
-#define        TESTPAT         0x12345678
-       unsigned short  oldflags;
-       int                             i;
-
-       /* This ensures at least that none of the test addresses conflicts
-        * with the test code itself */
-       test_base = ((unsigned long)&save_addr & 0x007fffff) | 0x20000000;
-       *bank1 = *bank2 = 0;
-       
-       /* Interrupts must be disabled because arbitrary addresses may be
-        * temporarily overwritten, even code of an interrupt handler */
-       __asm__ __volatile__ ( "movew sr,%0; oriw #0x700,sr" : "=g" (oldflags) : );
-       disable_cache();
-       
-       /* save contents of the test addresses */
-       for( i = 0; i < 16; ++i )
-               saved_contents[i] = TESTADDR(i);
-       
-       /* write 0s into all test addresses */
-       for( i = 0; i < 16; ++i )
-               TESTADDR(i) = 0;
-
-       /* test for bank 1 */
-#if 0
-       /* This is Freddi's original test, but it didn't work. */
-       TESTADDR(0) = TESTADDR(1) = TESTPAT;
-       if (TESTADDR(1) == TESTPAT) {
-               if (TESTADDR(2) == TESTPAT)
-                       *bank1 = 8*MB;
-               else if (TESTADDR(3) == TESTPAT)
-                       *bank1 = 16*MB;
-               else
-                       *bank1 = 32*MB;
-       }
-       else {
-               if (TESTADDR(2) == TESTPAT)
-                       *bank1 = 0;
-               else
-                       *bank1 = 16*MB;
-       }
-#else
-       TESTADDR(0) = TESTPAT;
-       if (TESTADDR(1) == TESTPAT)
-               *bank1 = 8*MB;
-       else if (TESTADDR(2) == TESTPAT)
-               *bank1 = 16*MB;
-       else if (TESTADDR(4) == TESTPAT)
-               *bank1 = 32*MB;
-       else
-               *bank1 = 64*MB;
-#endif
-
-       /* test for bank2 */
-       if (TESTADDR(8) != 0)
-               *bank2 = 0;
-       else {
-               TESTADDR(8) = TESTPAT;
-               if (TESTADDR(9) != 0) {
-                       if (TESTADDR(10) == TESTPAT)
-                               *bank2 = 8*MB;
-                       else
-                               *bank2 = 32*MB;
-               }
-               else {
-                       TESTADDR(9) = TESTPAT;
-                       if (TESTADDR(10) == TESTPAT)
-                               *bank2 = 16*MB;
-                       else
-                               *bank2 = 64*MB;
-               }
-       }
-       
-       /* restore contents of the test addresses and restore interrupt mask */
-       for( i = 0; i < 16; ++i )
-               TESTADDR(i) = saved_contents[i];
-       __asm__ __volatile__ ( "movew %0,sr" : : "g" (oldflags) );
-}
-
-#undef TESTADDR
-#undef TESTPAT
-
-
-static int check_bootinfo_version(char *memptr)
-{
-    struct bootversion *bv = (struct bootversion *)memptr;
-    unsigned long version = 0;
-    int i, kernel_major, kernel_minor, boots_major, boots_minor;
-
-    printf( "\n" );
-    if (bv->magic == BOOTINFOV_MAGIC) {
-       for( i = 0; bv->machversions[i].machtype != 0; ++i ) {
-           if (bv->machversions[i].machtype == MACH_ATARI) {
-               version = bv->machversions[i].version;
-               break;
-           }
-       }
-    }
-    if (!version)
-       printf("Kernel has no bootinfo version info, assuming 0.0\n");
-
-    kernel_major = BI_VERSION_MAJOR(version);
-    kernel_minor = BI_VERSION_MINOR(version);
-    boots_major  = BI_VERSION_MAJOR(ATARI_BOOTI_VERSION);
-    boots_minor  = BI_VERSION_MINOR(ATARI_BOOTI_VERSION);
-    printf("Bootstrap's bootinfo version: %d.%d\n",
-          boots_major, boots_minor);
-    printf("Kernel's bootinfo version   : %d.%d\n",
-          kernel_major, kernel_minor);
-    
-    switch (kernel_major) {
-       case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
-           if (kernel_minor > boots_minor) {
-               printf("Warning: Bootinfo version of bootstrap and kernel "
-                      "differ!\n");
-               printf("         Certain features may not work.\n");
-           }
-           break;
-
-#ifdef BOOTINFO_COMPAT_1_0
-       case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
-           printf("(using backwards compatibility mode)\n");
-           break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-       default:
-           printf("\nThis bootstrap is too %s for this kernel!\n",
-                  boots_major < kernel_major ? "old" : "new");
-           return 0;
-    }
-    return kernel_major;
-}
-
-
-#ifdef USE_BOOTP
-# include "bootp.h"
-#else
-# define ll_read       read
-# define ll_lseek      lseek
-# define ll_close      close
-#endif
-
-#ifdef ZKERNEL
-static int load_zkernel( int fd );
-static int kread( int fd, void *buf, unsigned cnt );
-static int klseek( int fd, int where, int whence );
-static int kclose( int fd );
-#else
-# define kread         read
-# define klseek                lseek
-# define kclose                close
-#endif
-
-/* ++andreas: this must be inline due to Super */
-static inline void boot_exit (int) __attribute__ ((noreturn));
-static inline void boot_exit(int status)
-{
-    /* first go back to user mode */
-    (void)Super(userstk);
-       getchar();
-    exit(status);
-}
-
-int main(int argc, char *argv[])
-{
-    int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0;
-    int load_to_stram = 0;
-    char *ramdisk_name, *kernel_name, *memptr;
-    u_long ST_ramsize, TT_ramsize, memreq;
-    u_long cpu_type, fpu_type, mch_type, mint;
-    struct exec kexec;
-    int elf_kernel = 0;
-    Elf32_Ehdr kexec_elf;
-    Elf32_Phdr *kernel_phdrs = NULL;
-    u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size;
-    int prefer_bootp = 1, kname_set = 0, n_knames;
-#ifdef USE_BOOTP
-    int err;
-#endif
-    char kname_list[5][64];
-    void *bi_ptr;
-
-    ramdisk_name = NULL;
-    kernel_name = "vmlinux";
-
-    /* print the startup message */
-    puts("\fLinux/68k Atari Bootstrap version 2.2"
-#ifdef USE_BOOTP
-        " (with BOOTP)"
-#endif
-        );
-    puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");
-
-       /* ++roman: If no arguments on the command line, read them from
-        * file */
-       if (argc == 1)
-               get_default_args( &argc, &argv );
-
-    /* machine is Atari */
-    bi.machtype = MACH_ATARI;
-
-    /* check arguments */
-    while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF)
-       switch (ch) {
-         case 'd':
-           debugflag = 1;
-           break;
-         case 't':
-           ignore_ttram = 1;
-           break;
-         case 's':
-           load_to_stram = 1;
-           break;
-         case 'k':
-           kernel_name = optarg;
-           kname_set = 1;
-           break;
-         case 'r':
-           ramdisk_name = optarg;
-           break;
-         case 'b':
-           prefer_bootp = 0;
-           break;
-         case '?':
-         default:
-           usage();
-       }
-
-    argc -= optind;
-    argv += optind;
-  
-    /* We have to access some system variables to get
-     * the information we need, so we must switch to
-     * supervisor mode first.
-     */
-    userstk = Super(0L);
-
-    /* get the info we need from the cookie-jar */
-    cookiejar = *_p_cookies;
-    if(cookiejar == 0L) {
-       /* if we find no cookies, it's probably an ST */
-       fprintf(stderr, "Error: No cookiejar found. Is this an ST?\n");
-       boot_exit(EXIT_FAILURE);
-    }
-
-    /* Exit if MiNT/MultiTOS is running.  */
-    if(getcookie("MiNT", &mint) != -1)
-    {
-       puts("Warning: MiNT is running\n");
-#if 0
-       puts("Linux cannot be started when MiNT is running. Aborting...\n");
-       boot_exit(EXIT_FAILURE);
-#endif
-    }
-
-    /* get _CPU, _FPU and _MCH */
-    getcookie("_CPU", &cpu_type);
-    getcookie("_FPU", &fpu_type);
-    getcookie("_MCH", &mch_type);
-
-    /* check if we are on a 68030/40 with FPU */
-    if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60))
-    {
-       puts("Machine type currently not supported. Aborting...");
-       boot_exit(EXIT_FAILURE);
-    }
-
-    switch(cpu_type) {
-      case  0:
-      case 10: break;
-      case 20: bi.cputype = CPU_68020; bi.mmutype = MMU_68851; break;
-      case 30: bi.cputype = CPU_68030; bi.mmutype = MMU_68030; break;
-      case 40: bi.cputype = CPU_68040; bi.mmutype = MMU_68040; break;
-      case 60: bi.cputype = CPU_68060; bi.mmutype = MMU_68060; break;
-      default:
-       fprintf(stderr, "Error: Unknown CPU type. Aborting...\n");
-       boot_exit(EXIT_FAILURE);
-       break;
-    }
-
-    printf("CPU: %ld; ", cpu_type + 68000);
-    printf("FPU: ");
-
-    /* check for FPU; in case of a '040 or '060, don't look at _FPU itself,
-     * some software may set it to wrong values (68882 or the like) */
-       if (cpu_type == 40) {
-               bi.fputype = FPU_68040;
-               puts( "68040\n" );
-       }
-       else if (cpu_type == 60) {
-               bi.fputype = FPU_68060;
-               puts( "68060\n" );
-       }
-       else {
-               switch ((fpu_type >> 16) & 7) {
-                 case 0:
-                       puts("not present\n");
-                       break;
-                 case 1:
-                       puts("SFP004 not supported. Assuming no FPU.");
-                       break;
-                 case 2:
-                       /* try to determine real type */
-                       if (fpu_idle_frame_size () != 0x18)
-                               goto m68882;
-                       /* fall through */
-                 case 4:
-                       bi.fputype = FPU_68881;
-                       puts("68881\n");
-                       break;
-                 case 6:
-                 m68882:
-                       bi.fputype = FPU_68882;
-                       puts("68882\n");
-                       break;
-                 default:
-                       puts("Unknown FPU type. Assuming no FPU.");
-                       break;
-               }
-       }
-       /* ++roman: If an FPU was announced in the cookie, test
-          whether it is a real hardware FPU or a software emulator!  */
-       if (bi.fputype) {
-               if (test_software_fpu()) {
-                       bi.fputype = 0;
-                       puts("FPU: software emulated. Assuming no FPU.");
-               }
-       }
-
-    /* Get the amounts of ST- and TT-RAM. */
-    /* The size must be a multiple of 1MB. */
-    i = 0;
-       
-    if (!test_medusa()) {
-       struct {
-               unsigned short version;   /* version - currently 1 */
-               unsigned long fr_start; /* start addr FastRAM */
-               unsigned long fr_len;   /* length FastRAM */
-       } *magn_cookie;
-       struct {
-               unsigned long version;
-               unsigned long fr_start; /* start addr */
-               unsigned long fr_len;   /* length */
-       } *fx_cookie;
-
-        TT_ramsize = 0;
-        if (!ignore_ttram) {
-           /* "Original" or properly emulated TT-Ram */
-           if (*ramtop) {
-               /* the 'ramtop' variable at 0x05a4 is not
-                * officially documented. We use it anyway
-                * because it is the only way to get the TTram size.
-                * (It is zero if there is no TTram.)
-                */
-               bi.memory[i].addr = TT_RAM_BASE;
-               bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1);
-               TT_ramsize = bi.memory[i].size / MB;
-               i++;
-               printf("TT-RAM: %ld Mb; ", TT_ramsize);
-           }
-
-           /* test for MAGNUM alternate RAM
-            * added 26.9.1995 M. Schwingen, rincewind@discworld.oche.de
-            */
-           if (getcookie("MAGN", (u_long *)&magn_cookie) != -1) {
-               bi.memory[i].addr = magn_cookie->fr_start;
-               bi.memory[i].size = magn_cookie->fr_len & ~(MB - 1);
-               TT_ramsize += bi.memory[i].size / MB;
-               printf("MAGNUM alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
-               i++;
-           }
-
-           /* BlowUps FX */
-           if (getcookie("BPFX", (u_long *)&fx_cookie) != -1 && fx_cookie) {
-               /* if fx is set (cookie call above),
-                * we assume that BlowUps FX-card
-                * is installed. (Nat!)
-                */
-               bi.memory[i].addr = fx_cookie->fr_start;
-               bi.memory[i].size = fx_cookie->fr_len & ~(MB - 1);
-               printf("FX alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
-               i++;
-           }
-       }
-
-        bi.memory[i].addr = 0;
-        bi.memory[i].size = *phystop & ~(MB - 1);
-        ST_ramsize = bi.memory[i].size / MB;
-        i++;
-        printf("ST-RAM: %ld Mb\n", ST_ramsize );
-
-        bi.num_memory = i;
-
-       if (load_to_stram && i > 1) {
-           /* Put ST-RAM first in the list of mem blocks */
-           struct mem_info temp = bi.memory[i - 1];
-           bi.memory[i - 1] = bi.memory[0];
-           bi.memory[0] = temp;
-       }
-    }
-    else {
-        u_long bank1, bank2, medusa_st_ram;
-
-        get_medusa_bank_sizes( &bank1, &bank2 );
-       medusa_st_ram = *phystop & ~(MB - 1);
-        bank1 -= medusa_st_ram;
-        TT_ramsize = 0;
-
-        bi.memory[i].addr = 0;
-        bi.memory[i].size = medusa_st_ram;
-        ST_ramsize = bi.memory[i].size / MB;
-        i++;
-        printf("Medusa pseudo ST-RAM from bank 1: %ld Mb; ", ST_ramsize );
-
-        if (!ignore_ttram && bank1 > 0) {
-            bi.memory[i].addr = 0x20000000 + medusa_st_ram;
-            bi.memory[i].size = bank1;
-            TT_ramsize += bank1;
-            i++;
-            printf("TT-RAM bank 1: %ld Mb; ", bank1/MB );
-        }
-                       
-        if (!ignore_ttram && bank2 > 0) {
-            bi.memory[i].addr = 0x24000000;
-            bi.memory[i].size = bank2;
-            TT_ramsize += bank2;
-            i++;
-            printf("TT-RAM bank 2: %ld Mb; ", bank2/MB );
-        }
-                       
-        bi.num_memory = i;
-        printf("\n");
-    }
-
-    /* verify that there is enough RAM; ST- and TT-RAM combined */
-    if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
-       puts("Not enough RAM. Aborting...");
-       boot_exit(10);
-    }
-
-#if 0  
-    /* Get language/keyboard info */
-    /* TODO: do we need this ? */
-    /* Could be used to auto-select keyboard map later on. (rdv) */
-    if (getcookie("_AKP",&language) == -1)
-    {
-       /* Get the language info from the OS-header */
-       os_header = *_sysbase;
-       os_header = os_header->os_beg;
-       lang = (os_header->os_conf) >> 1;
-       printf("Language: ");
-       switch(lang) {
-         case HOL: puts("Dutch"); break; /* Own country first :-) */
-         case USA: puts("American"); break;
-         case SWG: puts("Switzerland (German)"); break;
-         case FRG: puts("German"); break;
-         case FRA: puts("French"); break;
-         case SWF: puts("Switzerland (French)"); break;
-         case UK:  puts("English"); break;
-         case SPA: puts("Spanish"); break;
-         case ITA: puts("Italian"); break;
-         case SWE: puts("Swedish"); break;
-         case TUR: puts("Turkey"); break;
-         case FIN: puts("Finnish"); break;
-         case NOR: puts("Norwegian"); break;
-         case DEN: puts("Danish"); break;
-         case SAU: puts("Saudi-Arabian"); break;
-         default:  puts("Unknown"); break;
-       }
-    }
-    else
-    {
-       printf("Language: ");
-       switch(language & 0x0F)
-       {
-         case 1: printf("German "); break;
-         case 2: printf("French "); break;
-         case 4: printf("Spanish "); break;
-         case 5: printf("Italian "); break;
-         case 7: printf("Swiss French "); break;
-         case 8: printf("Swiss German "); break;
-         default: printf("English ");
-       }
-       printf("Keyboard type :");
-       switch(language >> 8)
-       {
-         case 1: printf("German "); break;
-         case 2: printf("French "); break;
-         case 4: printf("Spanish "); break;
-         case 5: printf("Italian "); break;
-         case 7: printf("Swiss French "); break;
-         case 8: printf("Swiss German "); break;
-         default: printf("English ");
-       }
-       printf("\n");
-    }
-#endif
-       
-    /* Pass contents of the _MCH cookie to the kernel */
-    bi.mch_cookie = mch_type;
-    
-    /*
-     * Copy command line options into the kernel command line.
-     */
-    i = 0;
-    while (argc--) {
-       if ((i+strlen(*argv)+1) < CL_SIZE) {
-           i += strlen(*argv) + 1;
-           if (bi.command_line[0])
-               strcat (bi.command_line, " ");
-           strcat (bi.command_line, *argv++);
-       }
-    }
-    printf ("Command line is '%s'\n", bi.command_line);
-
-    start_mem = bi.memory[0].addr;
-    mem_size = bi.memory[0].size;
-
-    /* tell us where the kernel will go */
-    printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
-
-#ifdef TEST
-    /*
-    ** Temporary exit point for testing
-    */
-    boot_exit(-1);
-#endif /* TEST */
-
-    i = 0;
-#ifdef USE_BOOTP
-    if (!kname_set)
-       kname_list[i++][0] = '\0'; /* default kernel which BOOTP server says */
-#endif
-#ifdef ZKERNEL
-    strcpy( kname_list[i], kernel_name );
-    strcat( kname_list[i], ".gz" );
-    ++i;
-#endif
-    strcpy( kname_list[i++], kernel_name );
-#ifdef ZKERNEL
-    if (!kname_set)
-       strcpy( kname_list[i++], "vmlinuz" );
-#endif
-    n_knames = i;
-
-    kfd = -1;
-#ifdef USE_BOOTP
-    if (prefer_bootp) {
-       for( i = 0; i < n_knames; ++i ) {
-           if ((err = get_remote_kernel( kname_list[i] )) >= 0)
-               goto kernel_open;
-           if (err < -1) /* fatal error; retries don't help... */
-               break;
-       }
-       printf( "\nremote boot failed; trying local kernel\n" );
-    }
-#endif
-    for( i = 0; i < n_knames; ++i ) {
-       if ((kfd = open( kname_list[i], O_RDONLY )) != -1)
-           goto kernel_open;
-    }
-#ifdef USE_BOOTP
-    if (!prefer_bootp) {
-       printf( "\nlocal kernel failed; trying remote boot\n" );
-       for( i = 0; i < n_knames; ++i ) {
-           if ((err = get_remote_kernel( kname_list[i] )) >= 0)
-               goto kernel_open;
-           if (err < -1) /* fatal error; retries don't help... */
-               break;
-       }
-    }
-#endif
-    fprintf( stderr, "Unable to open any kernel file\n(Tried " );
-    for( i = 0; i < n_knames; ++i ) {
-       fprintf( stderr, "%s%s", kname_list[i],
-                i <  n_knames-2 ? ", " :
-                i == n_knames-2 ? ", and " :
-                ")\n" );
-    }
-    boot_exit( EXIT_FAILURE );
-    
-  kernel_open:
-
-    if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
-    {
-       fprintf (stderr, "Unable to read exec header from %s\n", kernel_name);
-       boot_exit (EXIT_FAILURE);
-    }
-
-#ifdef ZKERNEL
-    if (((unsigned char *)&kexec)[0] == 037 &&
-       (((unsigned char *)&kexec)[1] == 0213 ||
-        ((unsigned char *)&kexec)[1] == 0236)) {
-       /* That's a compressed kernel */
-       printf( "Kernel is compressed\n" );
-       if (load_zkernel( kfd )) {
-           printf( "Decompression error -- aborting\n" );
-           boot_exit( EXIT_FAILURE );
-       }
-    }
-#endif
-    
-    switch (N_MAGIC(kexec)) {
-    case ZMAGIC:
-       text_offset = N_TXTOFF(kexec);
-       break;
-    case QMAGIC:
-       text_offset = sizeof(kexec);
-       /* the text size includes the exec header; remove this */
-       kexec.a_text -= sizeof(kexec);
-       break;
-    default:
-       /* Try to parse it as an ELF header */
-       klseek (kfd, 0, SEEK_SET);
-       if (kread (kfd, (void *)&kexec_elf, sizeof (kexec_elf)) == sizeof (kexec_elf)
-           && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
-         {
-           elf_kernel = 1;
-           /* A few plausibility checks */
-           if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
-               || kexec_elf.e_version != EV_CURRENT)
-             {
-               fprintf (stderr, "Invalid ELF header contents in kernel\n");
-               boot_exit (EXIT_FAILURE);
-             }
-           /* Load the program headers */
-           kernel_phdrs = (Elf32_Phdr *) Malloc (kexec_elf.e_phnum * sizeof (Elf32_Phdr));
-           if (kernel_phdrs == NULL)
-             {
-               fprintf (stderr, "Unable to allocate memory for program headers\n");
-               boot_exit (EXIT_FAILURE);
-             }
-           klseek (kfd, kexec_elf.e_phoff, SEEK_SET);
-           if (kread (kfd, (void *) kernel_phdrs,
-                     kexec_elf.e_phnum * sizeof (*kernel_phdrs))
-               != kexec_elf.e_phnum * sizeof (*kernel_phdrs))
-             {
-               fprintf (stderr, "Unable to read program headers from %s\n",
-                        kernel_name);
-               boot_exit (EXIT_FAILURE);
-             }
-           break;
-         }
-       fprintf (stderr, "Wrong magic number %lo in kernel header\n",
-                N_MAGIC(kexec));
-       boot_exit (EXIT_FAILURE);
-    }
-
-    /* Load the kernel one page after start of mem */
-    start_mem += PAGE_SIZE;
-    mem_size -= PAGE_SIZE;
-    /* Align bss size to multiple of four */
-    if (!elf_kernel)
-      kexec.a_bss = (kexec.a_bss + 3) & ~3;
-
-    /* init ramdisk */
-    if(ramdisk_name) {
-       if((rfd = open(ramdisk_name, O_RDONLY)) == -1) {
-           fprintf(stderr, "Unable to open ramdisk file %s\n",
-                   ramdisk_name);
-           boot_exit(EXIT_FAILURE);
-       }
-       bi.ramdisk.size = lseek(rfd, 0, SEEK_END);
-    }
-    else
-       bi.ramdisk.size = 0;
-    /* calculate the total required amount of memory */
-    if (elf_kernel)
-      {
-       u_long min_addr = 0xffffffff, max_addr = 0;
-       for (i = 0; i < kexec_elf.e_phnum; i++)
-         {
-           if (min_addr > kernel_phdrs[i].p_vaddr)
-             min_addr = kernel_phdrs[i].p_vaddr;
-           if (max_addr < kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz)
-             max_addr = kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz;
-         }
-       /* This is needed for newer linkers that include the header in
-          the first segment.  */
-       if (min_addr == 0)
-         {
-           min_addr = PAGE_SIZE;
-           kernel_phdrs[0].p_vaddr += PAGE_SIZE;
-           kernel_phdrs[0].p_offset += PAGE_SIZE;
-           kernel_phdrs[0].p_filesz -= PAGE_SIZE;
-           kernel_phdrs[0].p_memsz -= PAGE_SIZE;
-         }
-       kernel_size = max_addr - min_addr;
-      }
-    else
-      kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;
-
-    rd_size = bi.ramdisk.size;
-    if (rd_size + kernel_size > mem_size - MB/2 && bi.num_memory > 1)
-      /* If running low on ST ram load ramdisk into alternate ram.  */
-      bi.ramdisk.addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
-    else
-      /* Else hopefully there is enough ST ram. */
-      bi.ramdisk.addr = (u_long)start_mem + mem_size - rd_size;
-
-    /* create the bootinfo structure */
-    if (!create_bootinfo())
-       boot_exit (EXIT_FAILURE);
-
-    memreq = kernel_size + bi_size;
-#ifdef BOOTINFO_COMPAT_1_0
-    if (sizeof(compat_bootinfo) > bi_size)
-       memreq = kernel_size+sizeof(compat_bootinfo);
-#endif /* BOOTINFO_COMPAT_1_0 */
-    /* align load address of ramdisk image, read() is sloooow on odd addr. */
-    memreq = ((memreq + 3) & ~3) + rd_size;
-       
-    /* allocate RAM for the kernel */
-    if (!(memptr = (char *)Malloc (memreq)))
-    {
-       fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n");
-       boot_exit (EXIT_FAILURE);
-    }
-    else
-       fprintf(stderr, "kernel at address %lx\n", (u_long) memptr);
-
-    (void)memset(memptr, 0, memreq);
-
-    /* read the text and data segments from the kernel image */
-    if (elf_kernel)
-      {
-       for (i = 0; i < kexec_elf.e_phnum; i++)
-         {
-           if (klseek (kfd, kernel_phdrs[i].p_offset, SEEK_SET) == -1)
-             {
-               fprintf (stderr, "Failed to seek to segment %d\n", i);
-               boot_exit (EXIT_FAILURE);
-             }
-           if (kread (kfd, memptr + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
-                     kernel_phdrs[i].p_filesz)
-               != kernel_phdrs[i].p_filesz)
-             {
-               fprintf (stderr, "Failed to read segment %d\n", i);
-               boot_exit (EXIT_FAILURE);
-             }
-         }
-      }
-    else
-      {
-       if (klseek (kfd, text_offset, SEEK_SET) == -1)
-       {
-           fprintf (stderr, "Failed to seek to text\n");
-           Mfree ((void *)memptr);
-           boot_exit (EXIT_FAILURE);
-       }
-
-       if (kread (kfd, memptr, kexec.a_text) != kexec.a_text)
-       {
-           fprintf (stderr, "Failed to read text\n");
-           Mfree ((void *)memptr);
-           boot_exit (EXIT_FAILURE);
-       }
-
-       /* data follows immediately after text */
-       if (kread (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data)
-       {
-           fprintf (stderr, "Failed to read data\n");
-           Mfree ((void *)memptr);
-           boot_exit (EXIT_FAILURE);
-       }
-      }
-    kclose (kfd);
-
-    /* Check kernel's bootinfo version */
-    switch (check_bootinfo_version(memptr)) {
-       case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
-           bi_ptr = &bi_union.record;
-           break;
-
-#ifdef BOOTINFO_COMPAT_1_0
-       case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
-           if (!create_compat_bootinfo()) {
-               Mfree ((void *)memptr);
-               boot_exit (EXIT_FAILURE);
-           }
-           bi_ptr = &compat_bootinfo;
-           bi_size = sizeof(compat_bootinfo);
-           break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-       default:
-           Mfree ((void *)memptr);
-           boot_exit (EXIT_FAILURE);
-    }
-
-    /* copy the boot_info struct to the end of the kernel image */
-    memcpy ((void *)(memptr + kernel_size), bi_ptr, bi_size);
-
-    /* read the ramdisk image */
-    if (rfd != -1)
-    {
-       if (lseek (rfd, 0, SEEK_SET) == -1)
-       {
-           fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
-           Mfree ((void *)memptr);
-           boot_exit (EXIT_FAILURE);
-       }
-       if (read (rfd, memptr + memreq - rd_size,
-                 rd_size) != rd_size)
-       {
-           fprintf (stderr, "Failed to read ramdisk file\n");
-           Mfree ((void *)memptr);
-           boot_exit (EXIT_FAILURE);
-       }
-       close (rfd);
-    }
-
-    /* for those who want to debug */
-    if (debugflag)
-    {
-       if (bi.ramdisk.size)
-           printf ("RAM disk at %#lx, size is %ld\n",
-                   (u_long)(memptr + memreq - rd_size),
-                   bi.ramdisk.size);
-
-       if (elf_kernel)
-         {
-           for (i = 0; i < kexec_elf.e_phnum; i++)
-             {
-               printf ("Kernel segment %d at %#lx, size %ld\n", i,
-                       start_mem + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
-                       kernel_phdrs[i].p_memsz);
-             }
-         }
-       else
-         {
-           printf ("\nKernel text at %#lx, code size %d\n",
-                   start_mem, kexec.a_text);
-           printf ("Kernel data at %#lx, data size %d\n",
-                   start_mem + kexec.a_text, kexec.a_data );
-           printf ("Kernel bss  at %#lx, bss  size %d\n",
-                   start_mem + kexec.a_text + kexec.a_data, kexec.a_bss );
-         }
-       printf ("\nboot_info is at %#lx\n",
-               start_mem + kernel_size);
-       printf ("\nKernel entry is %#lx\n",
-               elf_kernel ? kexec_elf.e_entry : kexec.a_entry);
-       printf ("ramdisk dest top is %#lx\n", bi.ramdisk.addr + rd_size);
-       printf ("ramdisk lower limit is %#lx\n",
-               (u_long)(memptr + memreq - rd_size));
-       printf ("ramdisk src top is %#lx\n", (u_long)(memptr + memreq));
-
-       printf ("Type a key to continue the Linux boot...");
-       fflush (stdout);
-       getchar();
-    }
-
-    printf("Booting Linux...\n");
-
-    sync ();
-
-    /* turn off interrupts... */
-    disable_interrupts();
-
-    /* turn off caches... */
-    disable_cache();
-
-    /* ..and any MMU translation */
-    disable_mmu();
-
-    /* ++guenther: allow reset if launched with MiNT */
-    *(long*)0x426 = 0;
-
-    /* copy mover code to a safe place if needed */
-    memcpy ((void *) 0x400, &copyall, &copyallend - &copyall);
-
-    /* setup stack */
-    change_stack ((void *) PAGE_SIZE);
-
-    /*
-     * On the Atari you can have two situations:
-     * 1. One piece of contiguous RAM (Falcon)
-     * 2. Two pieces of contiguous RAM (TT)
-     * In case 2 you can load your program into ST-ram and load your data in
-     * any old RAM you have left.
-     * In case 1 you could overwrite your own program when copying the
-     * kernel and ramdisk to their final positions.
-     * To solve this the mover code is copied to a safe place first.
-     * Then this program jumps to the mover code. After the mover code
-     * has finished it jumps to the start of the kernel in its new position.
-     * I thought the memory just after the interrupt vector table was a safe
-     * place because it is used by TOS to store some system variables.
-     * This range goes from 0x400 to approx. 0x5B0.
-     * This is more than enough for the miniscule mover routine (16 bytes).
-     */
-
-    jump_to_mover((char *) start_mem, memptr,
-                 (char *) bi.ramdisk.addr + rd_size, memptr + memreq,
-                 kernel_size + bi_size, rd_size,
-                 (void *) 0x400);
-
-    for (;;);
-    /* NOTREACHED */
-}
-
-
-
-#define        MAXARGS         30
-
-static void get_default_args( int *argc, char ***argv )
-
-{      FILE            *f;
-       static char     *nargv[MAXARGS];
-       char            arg[256], *p;
-       int                     c, quote, state;
-
-       if (!(f = fopen( "bootargs", "r" )))
-               return;
-       
-       *argc = 1;
-       if (***argv)
-         nargv[0] = **argv;
-       else
-         nargv[0] = "bootstrap";
-       *argv = nargv;
-
-       quote = state = 0;
-       p = arg;
-       while( (c = fgetc(f)) != EOF ) {                
-
-               if (state == 0) {
-                       /* outside args, skip whitespace */
-                       if (!isspace(c)) {
-                               state = 1;
-                               p = arg;
-                       }
-               }
-               
-               if (state) {
-                       /* inside an arg: copy it into 'arg', obeying quoting */
-                       if (!quote && (c == '\'' || c == '"'))
-                               quote = c;
-                       else if (quote && c == quote)
-                               quote = 0;
-                       else if (!quote && isspace(c)) {
-                               /* end of this arg */
-                               *p = 0;
-                               nargv[(*argc)++] = strdup(arg);
-                               state = 0;
-                       }
-                       else
-                               *p++ = c;
-               }
-       }
-       if (state) {
-               /* last arg finished by EOF! */
-               *p = 0;
-               nargv[(*argc)++] = strdup(arg);
-       }
-       fclose( f );
-       
-       nargv[*argc] = 0;
-}    
-
-
-    /*
-     *  Create the Bootinfo Structure
-     */
-
-static int create_bootinfo(void)
-{
-    int i;
-    struct bi_record *record;
-
-    /* Initialization */
-    bi_size = 0;
-
-    /* Generic tags */
-    if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
-       return(0);
-    if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
-       return(0);
-    if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
-       return(0);
-    if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
-       return(0);
-    for (i = 0; i < bi.num_memory; i++)
-       if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
-           return(0);
-    if (bi.ramdisk.size)
-       if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
-           return(0);
-    if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
-       return(0);
-
-    /* Atari tags */
-    if (!add_bi_record(BI_ATARI_MCH_COOKIE, sizeof(bi.mch_cookie),
-                      &bi.mch_cookie))
-       return(0);
-
-    /* Trailer */
-    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
-    record->tag = BI_LAST;
-    bi_size += sizeof(bi_union.record.tag);
-
-    return(1);
-}
-
-
-    /*
-     *  Add a Record to the Bootinfo Structure
-     */
-
-static int add_bi_record(u_short tag, u_short size, const void *data)
-{
-    struct bi_record *record;
-    u_short size2;
-
-    size2 = (sizeof(struct bi_record)+size+3)&-4;
-    if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
-       fprintf (stderr, "Can't add bootinfo record. Ask a wizard to enlarge me.\n");
-       return(0);
-    }
-    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
-    record->tag = tag;
-    record->size = size2;
-    memcpy(record->data, data, size);
-    bi_size += size2;
-    return(1);
-}
-
-
-    /*
-     *  Add a String Record to the Bootinfo Structure
-     */
-
-static int add_bi_string(u_short tag, const u_char *s)
-{
-    return add_bi_record(tag, strlen(s)+1, (void *)s);
-}
-
-
-#ifdef BOOTINFO_COMPAT_1_0
-
-    /*
-     *  Create the Bootinfo structure for backwards compatibility mode
-     */
-
-static int create_compat_bootinfo(void)
-{
-    u_int i;
-
-    compat_bootinfo.machtype = bi.machtype;
-    if (bi.cputype & CPU_68020)
-       compat_bootinfo.cputype = COMPAT_CPU_68020;
-    else if (bi.cputype & CPU_68030)
-       compat_bootinfo.cputype = COMPAT_CPU_68030;
-    else if (bi.cputype & CPU_68040)
-       compat_bootinfo.cputype = COMPAT_CPU_68040;
-    else if (bi.cputype & CPU_68060)
-       compat_bootinfo.cputype = COMPAT_CPU_68060;
-    else {
-       printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
-       return(0);
-    }
-    if (bi.fputype & FPU_68881)
-       compat_bootinfo.cputype |= COMPAT_FPU_68881;
-    else if (bi.fputype & FPU_68882)
-       compat_bootinfo.cputype |= COMPAT_FPU_68882;
-    else if (bi.fputype & FPU_68040)
-       compat_bootinfo.cputype |= COMPAT_FPU_68040;
-    else if (bi.fputype & FPU_68060)
-       compat_bootinfo.cputype |= COMPAT_FPU_68060;
-    else {
-       printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
-       return(0);
-    }
-    compat_bootinfo.num_memory = bi.num_memory;
-    if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
-       printf("Warning: using only %d blocks of memory\n",
-              COMPAT_NUM_MEMINFO);
-       compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
-    }
-    for (i = 0; i < compat_bootinfo.num_memory; i++) {
-       compat_bootinfo.memory[i].addr = bi.memory[i].addr;
-       compat_bootinfo.memory[i].size = bi.memory[i].size;
-    }
-    if (bi.ramdisk.size) {
-       compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
-       compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
-    } else {
-       compat_bootinfo.ramdisk_size = 0;
-       compat_bootinfo.ramdisk_addr = 0;
-    }
-    strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
-    compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
-
-    compat_bootinfo.bi_atari.hw_present = 0;
-    compat_bootinfo.bi_atari.mch_cookie = bi.mch_cookie;
-    return(1);
-}
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
-#ifdef ZKERNEL
-
-#define        ZFILE_CHUNK_BITS        16  /* chunk is 64 KB */
-#define        ZFILE_CHUNK_SIZE        (1 << ZFILE_CHUNK_BITS)
-#define        ZFILE_CHUNK_MASK        (ZFILE_CHUNK_SIZE-1)
-#define        ZFILE_N_CHUNKS          (2*1024*1024/ZFILE_CHUNK_SIZE)
-
-/* variables for storing the uncompressed data */
-static char *ZFile[ZFILE_N_CHUNKS];
-static int ZFileSize = 0;
-static int ZFpos = 0;
-static int Zwpos = 0;
-
-static int Zinfd = 0;       /* fd of compressed file */
-
-/*
- * gzip declarations
- */
-
-#define OF(args)  args
-
-#define memzero(s, n)     memset ((s), 0, (n))
-
-typedef unsigned char  uch;
-typedef unsigned short ush;
-typedef unsigned long  ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000    /* window size--must be a power of two, and */
-                       /*  at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize = 0;  /* valid bytes in inbuf */
-static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0;  /* bytes in output buffer */
-static int exit_code = 0;
-static long bytes_out = 0;
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-               
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int  fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#include "../../../../lib/inflate.c"
-
-static void gzip_mark( void **ptr )
-{
-}
-
-static void gzip_release( void **ptr )
-{
-}
-
-
-/*
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf( void )
-{
-    if (exit_code)
-       return -1;
-
-    insize = ll_read( Zinfd, inbuf, INBUFSIZ );
-    if (insize <= 0)
-       return -1;
-
-    inptr = 1;
-    return( inbuf[0] );
-}
-
-/*
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window( void )
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in, ch;
-    int chunk = Zwpos >> ZFILE_CHUNK_BITS;
-
-    if (chunk >= ZFILE_N_CHUNKS) {
-       fprintf( stderr, "compressed image too large! Aborting.\n" );
-       boot_exit( EXIT_FAILURE );
-    }
-    if (!ZFile[chunk]) {
-       if (!(ZFile[chunk] = (char *)Malloc( ZFILE_CHUNK_SIZE ))) {
-           fprintf( stderr, "Out of memory for decompresing kernel image\n" );
-           boot_exit( EXIT_FAILURE );
-       }
-    }
-    memcpy( ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt );
-    Zwpos += outcnt;
-    
-#define        DISPLAY_BITS 13
-    if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0) {
-       printf( "." );
-       fflush( stdout );
-    }
-    
-    in = window;
-    for (n = 0; n < outcnt; n++) {
-           ch = *in++;
-           c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    outcnt = 0;
-}
-
-static void error( char *x )
-{
-    fprintf( stderr, "\n%s", x);
-    exit_code = 1;
-}
-
-static int load_zkernel( int fd )
-{
-    int i, err;
-    
-    for( i = 0; i < ZFILE_N_CHUNKS; ++i )
-       ZFile[i] = NULL;
-    Zinfd = fd;
-    ll_lseek( fd, 0, SEEK_SET );
-    
-    if (!(inbuf = (uch *)Malloc( INBUFSIZ ))) {
-       fprintf( stderr, "Couldn't allocate gunzip buffer\n" );
-       boot_exit( EXIT_FAILURE );
-    }
-    if (!(window = (uch *)Malloc( WSIZE ))) {
-       fprintf( stderr, "Couldn't allocate gunzip window\n" );
-       boot_exit( EXIT_FAILURE );
-    }
-
-    printf( "Uncompressing kernel image " );
-    fflush( stdout );
-    makecrc();
-    if (!(err = gunzip()))
-       printf( "done\n" );
-    ZFileSize = Zwpos;
-    ll_close( Zinfd ); /* input file not needed anymore */
-    
-    Mfree( inbuf );
-    Mfree( window );
-    return( err );
-}
-
-/* Note about the read/lseek wrapper and its memory management: It assumes
- * that all seeks are only forward, and thus data already read or skipped can
- * be freed. This is true for current organization of bootstrap and kernels.
- * Little exception: The struct kexec at the start of the file. After reading
- * it, there may be a seek back to the end of the file. But this currently
- * doesn't hurt. Same considerations apply to the TFTP file buffers. (Roman)
- */
-
-static int kread( int fd, void *buf, unsigned cnt )
-{
-    unsigned done = 0;
-       
-    if (!ZFileSize)
-       return( ll_read( fd, buf, cnt ) );
-    
-    if (ZFpos + cnt > ZFileSize)
-       cnt = ZFileSize - ZFpos;
-    
-    while( cnt > 0 ) {
-       unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
-       unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
-       unsigned n = cnt;
-
-       if (ZFpos + n > endchunk)
-           n = endchunk - ZFpos;
-       memcpy( buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n );
-       cnt -= n;
-       buf += n;
-       done += n;
-       ZFpos += n;
-
-       if (ZFpos == endchunk) {
-           Mfree( ZFile[chunk] );
-           ZFile[chunk] = NULL;
-       }
-    }
-
-    return( done );
-}
-
-
-static int klseek( int fd, int where, int whence )
-{
-    unsigned oldpos, oldchunk, newchunk;
-
-    if (!ZFileSize)
-       return( ll_lseek( fd, where, whence ) );
-
-    oldpos = ZFpos;
-    switch( whence ) {
-      case SEEK_SET:
-       ZFpos = where;
-       break;
-      case SEEK_CUR:
-       ZFpos += where;
-       break;
-      case SEEK_END:
-       ZFpos = ZFileSize + where;
-       break;
-      default:
-       return( -1 );
-    }
-    if (ZFpos < 0) {
-       ZFpos = 0;
-       return( -1 );
-    }
-    else if (ZFpos > ZFileSize) {
-       ZFpos = ZFileSize;
-       return( -1 );
-    }
-
-    /* free memory of skipped-over data */
-    oldchunk = oldpos >> ZFILE_CHUNK_BITS;
-    newchunk = ZFpos  >> ZFILE_CHUNK_BITS;
-    while( oldchunk < newchunk ) {
-       if (ZFile[oldchunk]) {
-           Mfree( ZFile[oldchunk] );
-           ZFile[oldchunk] = NULL;
-       }
-       ++oldchunk;
-    }
-    
-    return( ZFpos );
-}
-
-
-static void free_zfile( void )
-{
-    int i;
-
-    for( i = 0; i < ZFILE_N_CHUNKS; ++i )
-       if (ZFile[i]) Mfree( ZFile[i] );
-}
-
-static int kclose( int fd )
-{
-    if (ZFileSize) {
-       free_zfile();
-       return( 0 );
-    }
-    else
-       return( ll_close( fd ) );
-}
-
-
-
-#endif /* ZKERNEL */
diff --git a/arch/m68k/boot/atari/bootstrap.h b/arch/m68k/boot/atari/bootstrap.h
deleted file mode 100644 (file)
index 594916d..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-** bootstrap.h -- This file is a part of the Atari bootloader.
-**
-** Copyright 1993 by Arjan Knor
-**
-** Modified by Andreas Schwab
-**     - clear transparent translation registers
-** Modified 18-Aug-96 by Geert Uytterhoeven
-**     - Updated for the new boot information structure (untested!)
-** Modified 1996-11-12 by Andreas Schwab
-**     - Fixed and tested previous change
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-#ifndef BOOTSTRAP_H
-#define BOOTSTRAP_H
-
-     /*
-     *  Atari Bootinfo Definitions
-     *
-     *  All limits herein are `soft' limits, i.e. they don't put constraints
-     *  on the actual parameters in the kernel.
-     */
-
-struct atari_bootinfo {
-    unsigned long machtype;                /* machine type */
-    unsigned long cputype;                 /* system CPU */
-    unsigned long fputype;                 /* system FPU */
-    unsigned long mmutype;                 /* system MMU */
-    int num_memory;                        /* # of memory blocks found */
-    struct mem_info memory[NUM_MEMINFO];    /* memory description */
-    struct mem_info ramdisk;               /* ramdisk description */
-    char command_line[CL_SIZE];                    /* kernel command line parameters */
-    unsigned long mch_cookie;              /* _MCH cookie from TOS */
-};
-
-
-/* _MCH cookie values */
-#define MACH_ST  0
-#define MACH_STE 1
-#define MACH_TT  2
-#define MACH_FALCON 3
-
-/* some constants for memory handling */
-#define ST_RAM 0
-#define TT_RAM 1
-#define TT_RAM_BASE  (u_long)(0x01000000)
-#define MB           (1024 * 1024)
-#define START_MEM    (bi.memory[0].addr)
-#define MEM_SIZE     (bi.memory[0].size)
-
-/* the various CPU- and FPU-types */
-#define AFF_68000 (1)
-#define AFF_68020 (2)
-#define AFF_68030 (4)
-#define AFF_68040 (8)
-#define AFF_68881 (16)
-#define AFF_68882 (32)
-
-/* the possible OS-languages */
-#define USA 0
-#define FRG 1
-#define FRA 2
-#define UK  3
-#define SPA 4
-#define ITA 5
-#define SWE 6
-#define SWF 7
-#define SWG 8
-#define TUR 9
-#define FIN 10
-#define NOR 11
-#define DEN 12
-#define SAU 13
-#define HOL 14
-
-/* some inline functions */
-
-static __inline int fpu_idle_frame_size (void)
-{
-  char fpu_frame[216];
-  __asm__ __volatile__ ("fnop"::);
-  __asm__ __volatile__ ("fsave %0@" : : "a" (fpu_frame));
-  return fpu_frame[1];
-}
-
-static __inline void change_stack (u_long *stackp)
-{
-    __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp");
-}
-
-static __inline void disable_interrupts (void)
-{
-  __asm__ volatile ("orw #0x700,sr":);
-}
-
-extern struct atari_bootinfo bi;
-static __inline void disable_cache (void)
-{
-    __asm__ volatile ("movec %0,cacr" :: "d" (0));
-    if (bi.cputype & CPU_68060) {
-       /* '060: clear branch cache after disabling it;
-        * disable superscalar operation (and enable FPU) */
-       __asm__ volatile ("movec %0,cacr" :: "d" (0x00400000));
-       __asm__ volatile ("moveq #0,d0;"
-                         ".long 0x4e7b0808"    /* movec d0,pcr */
-                         : /* no outputs */
-                         : /* no inputs */
-                         : "d0");
-    }
-}
-
-static __inline void disable_mmu (void)
-{
-       if (bi.cputype & (CPU_68040|CPU_68060)) {
-           __asm__ volatile ("moveq #0,d0;"
-                                                 ".long 0x4e7b0003;"   /* movec d0,tc */
-                                                 ".long 0x4e7b0004;"   /* movec d0,itt0 */
-                                                 ".long 0x4e7b0005;"   /* movec d0,itt1 */
-                                                 ".long 0x4e7b0006;"   /* movec d0,dtt0 */
-                                                 ".long 0x4e7b0007"    /* movec d0,dtt1 */
-                                                 : /* no outputs */
-                                                 : /* no inputs */
-                                                 : "d0");
-       }
-       else {
-               __asm__ volatile ("subl  #4,sp\n\t"
-                                                 "pmove tc,sp@\n\t"
-                                                 "bclr  #7,sp@\n\t"
-                                                 "pmove sp@,tc\n\t"
-                                                 "addl  #4,sp");
-               if (bi.cputype & CPU_68030) {
-                       __asm__ volatile ("clrl sp@-\n\t"
-                                                         ".long 0xf0170800\n\t" /* pmove sp@,tt0 */
-                                                         ".long 0xf0170c00\n\t" /* pmove sp@,tt1 */
-                                                         "addl  #4,sp\n");
-               }
-       }
-}
-
-static __inline void jump_to_mover (void *, void *, void *, void *, int, int,
-                                   void *) __attribute__ ((noreturn));
-static __inline void jump_to_mover (void *kernel_start, void *mem_start,
-                                   void *ramdisk_end, void *mem_end,
-                                   int kernel_size, int ramdisk_size,
-                                   void *mover_addr)
-{
-    asm volatile ("movel %0,a0\n\t"
-                 "movel %1,a1\n\t"
-                 "movel %2,a2\n\t"
-                 "movel %3,a3\n\t"
-                 "movel %4,d0\n\t"
-                 "movel %5,d1\n\t"
-                 "jmp   %6@\n"
-                 : /* no outputs */
-                 : "g" (kernel_start), "g" (mem_start),
-                   "g" (ramdisk_end), "g" (mem_end),
-                   "g" (kernel_size), "g" (ramdisk_size),
-                   "a" (mover_addr)
-                 : "a0", "a1", "a2", "a3", "d0", "d1");
-
-       /* Avoid warning that function may return */
-       for (;;) ;
-}
-
-#endif /* BOOTSTRAP_H */
-
diff --git a/arch/m68k/boot/atari/ethlance.c b/arch/m68k/boot/atari/ethlance.c
deleted file mode 100644 (file)
index 3b248c4..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-
-#include <stdio.h>
-#include <string.h>
-
-#include "bootp.h"
-#include "ethlance.h"
-
-
-struct {
-       volatile unsigned short *memaddr;
-       volatile unsigned short *ioaddr;
-} lance_addr_list[] = {
-       { (void *)0xfe010000, (void *)0xfe00fff0 },     /* RieblCard VME in TT */
-       { (void *)0xfec10000, (void *)0xfec0fff0 },     /* RieblCard VME in MegaSTE
-                                                                                                  (highest byte stripped) */
-       { (void *)0xfee00000, (void *)0xfeff7000 },     /* RieblCard in ST
-                                                                                                  (highest byte stripped) */
-       { (void *)0xfecf0000, (void *)0xfecffff0 },     /* PAMCard VME in TT and MSTE
-                                                                                                  (highest byte stripped) */
-};
-
-#define        N_LANCE_ADDR    (sizeof(lance_addr_list)/sizeof(*lance_addr_list))
-
-#define TX_RING_SIZE                   1
-#define TX_RING_LEN_BITS               0
-
-#define RX_RING_SIZE                   16
-#define RX_RING_LEN_BITS               (4 << 5)
-
-#define        offsetof(type,elt)      ((unsigned long)(&(((type *)0)->elt)))
-
-/* The LANCE Rx and Tx ring descriptors. */
-struct lance_rx_head {
-       unsigned short                  base;           /* Low word of base addr */
-       volatile unsigned char  flag;
-       unsigned char                   base_hi;        /* High word of base addr (unused) */
-       short                                   buf_length;     /* This length is 2s complement! */
-       short                                   msg_length;     /* This length is "normal". */
-};
-
-struct lance_tx_head {
-       unsigned short                  base;           /* Low word of base addr */
-       volatile unsigned char  flag;
-       unsigned char                   base_hi;        /* High word of base addr (unused) */
-       short                                   length;         /* Length is 2s complement! */
-       volatile short                  misc;
-};
-
-struct ringdesc {
-       unsigned short  adr_lo;         /* Low 16 bits of address */
-       unsigned char   len;            /* Length bits */
-       unsigned char   adr_hi;         /* High 8 bits of address (unused) */
-};
-
-struct lance_packet {
-       volatile unsigned char  data[PKTLEN];
-};
-
-/* The LANCE initialization block, described in databook. */
-struct lance_init_block {
-       unsigned short  mode;           /* Pre-set mode */
-       unsigned char   hwaddr[6];      /* Physical ethernet address */
-       unsigned                filter[2];      /* Multicast filter (unused). */
-       /* Receive and transmit ring base, along with length bits. */
-       struct ringdesc rx_ring;
-       struct ringdesc tx_ring;
-};
-
-/* The whole layout of the Lance shared memory */
-struct lance_memory {
-       struct lance_init_block init;
-       struct lance_tx_head    tx_head[TX_RING_SIZE];
-       struct lance_rx_head    rx_head[RX_RING_SIZE];
-       struct lance_packet             tx_packet[TX_RING_SIZE];
-       struct lance_packet             rx_packet[TX_RING_SIZE];
-};
-
-#define RIEBL_MAGIC                    0x09051990
-#define RIEBL_MAGIC_ADDR       ((unsigned long *)(((char *)MEM) + 0xee8a))
-#define RIEBL_HWADDR_ADDR      ((unsigned char *)(((char *)MEM) + 0xee8e))
-#define RIEBL_IVEC_ADDR                ((unsigned short *)(((char *)MEM) + 0xfffe))
-
-struct lance_ioreg {
-/* base+0x0 */ volatile unsigned short data;
-/* base+0x2 */ volatile unsigned short addr;
-                               unsigned char                   _dummy1[3];
-/* base+0x7 */ volatile unsigned char  ivec;
-                               unsigned char                   _dummy2[5];
-/* base+0xd */ volatile unsigned char  eeprom;
-                               unsigned char                   _dummy3;
-/* base+0xf */ volatile unsigned char  mem;
-};
-
-enum lance_type {
-       OLD_RIEBL,              /* old Riebl card without battery */
-       NEW_RIEBL,              /* new Riebl card with battery */
-       PAM_CARD                /* PAM card with EEPROM */
-} CardType;
-
-HWADDR dev_addr;
-
-/* This is a default address for the old RieblCards without a battery
- * that have no ethernet address at boot time. 00:00:36:04 is the
- * prefix for Riebl cards, the 00:00 at the end is arbitrary.
- */
-
-HWADDR OldRieblDefHwaddr = {
-       0x00, 0x00, 0x36, 0x04, 0x00, 0x00
-};
-
-struct lance_ioreg     *IO;
-struct lance_memory    *MEM;
-
-#define        DREG    IO->data
-#define        AREG    IO->addr
-#define        REGA(a) ( AREG = (a), DREG )
-
-int CurRx;
-
-
-/* Definitions for the Lance */
-
-/* tx_head flags */
-#define        TMD1_ENP                0x01
-#define TMD1_STP               0x02
-#define        TMD1_DEF                0x04
-#define TMD1_ONE               0x08
-#define        TMD1_MORE               0x10
-#define        TMD1_ERR                0x40
-#define TMD1_OWN               0x80
-
-#define TMD1_OWN_CHIP  TMD1_OWN
-#define TMD1_OWN_HOST  0
-
-/* tx_head misc field */
-#define TMD3_TDR               0x03FF
-#define TMD3_RTRY              0x0400
-#define TMD3_LCAR              0x0800
-#define TMD3_LCOL              0x1000
-#define TMD3_UFLO              0x4000
-#define TMD3_BUFF3             0x8000
-
-/* rx_head flags */
-#define        RMD1_ENP                0x01
-#define RMD1_STP               0x02
-#define RMD1_BUFF              0x04
-#define RMD1_CRC               0x08
-#define RMD1_OFLO              0x10
-#define RMD1_FRAM              0x20
-#define        RMD1_ERR                0x40
-#define RMD1_OWN               0x80
-
-#define RMD1_OWN_CHIP  RMD1_OWN
-#define RMD1_OWN_HOST  0
-
-/* register names */
-#define CSR0   0
-#define CSR1   1
-#define CSR2   2
-#define CSR3   3
-
-/* CSR0 */
-#define CSR0_INIT      0x0001          /* initialize */
-#define CSR0_STRT      0x0002          /* start */
-#define CSR0_STOP      0x0004          /* stop */
-#define CSR0_TDMD      0x0008          /* transmit demand */
-#define CSR0_TXON      0x0010          /* transmitter on */
-#define CSR0_RXON      0x0020          /* receiver on */
-#define CSR0_INEA      0x0040          /* interrupt enable */
-#define CSR0_INTR      0x0080          /* interrupt active */
-#define CSR0_IDON      0x0100          /* initialization done */
-#define CSR0_TINT      0x0200          /* transmitter interrupt */
-#define CSR0_RINT      0x0400          /* receiver interrupt */
-#define CSR0_MERR      0x0800          /* memory error */
-#define CSR0_MISS      0x1000          /* missed frame */
-#define CSR0_CERR      0x2000          /* carrier error (no heartbeat :-) */
-#define CSR0_BABL      0x4000          /* babble: tx-ed too many bits */
-#define CSR0_ERR       0x8000          /* error */
-
-/* CSR3 */
-#define CSR3_BCON      0x0001
-#define CSR3_ACON      0x0002
-#define CSR3_BSWP      0x0004
-
-
-#define        HZ      200
-#define        _hz_200 (*(volatile unsigned long *)0x4ba)
-
-
-
-
-/***************************** Prototypes *****************************/
-
-static int lance_probe( void );
-static int addr_readable( volatile void *regp, int wordflag );
-static int lance_init( void );
-static void lance_get_hwaddr( HWADDR *addr );
-static int lance_snd( Packet *pkt, int len );
-static int lance_rcv( Packet *pkt, int *len );
-
-/************************* End of Prototypes **************************/
-
-
-
-ETHIF_SWITCH LanceSwitch = {
-       lance_probe, lance_init, lance_get_hwaddr, 
-       lance_snd, lance_rcv
-};
-
-
-static int lance_probe( void )
-
-{      int             i;
-       
-       for( i = 0; i < N_LANCE_ADDR; ++i ) {
-               if (addr_readable( lance_addr_list[i].memaddr, 1 ) &&
-                       (lance_addr_list[i].memaddr[0] = 1,
-                        lance_addr_list[i].memaddr[0] == 1) &&
-                       (lance_addr_list[i].memaddr[0] = 0,
-                        lance_addr_list[i].memaddr[0] == 0) &&
-                       addr_readable( lance_addr_list[i].ioaddr, 1 )) {
-                       break;
-               }
-       }
-       if (i == N_LANCE_ADDR) return( -1 );
-
-       IO = (struct lance_ioreg *)lance_addr_list[i].ioaddr;
-       MEM = (struct lance_memory *)lance_addr_list[i].memaddr;
-       REGA( CSR0 ) = CSR0_STOP;
-
-       return( 0 );
-}
-
-
-static int addr_readable( volatile void *regp, int wordflag )
-
-{      int             ret;
-       long    *vbr, save_berr;
-
-       __asm__ __volatile__ ( "movec   %/vbr,%0" : "=r" (vbr) : );
-       save_berr = vbr[2];
-       
-       __asm__ __volatile__
-       (       "movel  %/sp,%/d1\n\t"
-               "movel  #Lberr,%2@\n\t"
-               "moveq  #0,%0\n\t"
-               "tstl   %3\n\t"
-               "bne    1f\n\t"
-               "tstb   %1@\n\t"
-               "bra    2f\n"
-"1:             tstw   %1@\n"
-"2:             moveq  #1,%0\n"
-"Lberr:         movel  %/d1,%/sp"
-               : "=&d" (ret)
-               : "a" (regp), "a" (&vbr[2]), "rm" (wordflag)
-               : "d1", "memory"
-       );
-
-       vbr[2] = save_berr;
-       
-       return( ret );
-}
-
-
-static int lance_init( void )
-
-{      int             i;
-       
-       /* Now test for type: If the eeprom I/O port is readable, it is a
-        * PAM card */
-       if (addr_readable( &(IO->eeprom), 0 )) {
-               /* Switch back to Ram */
-               i = IO->mem;
-               CardType = PAM_CARD;
-       }
-       else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
-               CardType = NEW_RIEBL;
-       }
-       else
-               CardType = OLD_RIEBL;
-               
-       /* Get the ethernet address */
-       switch( CardType ) {
-         case OLD_RIEBL:
-               /* No ethernet address! (Set some default address) */
-               memcpy( dev_addr, OldRieblDefHwaddr, ETHADDRLEN );
-               break;
-         case NEW_RIEBL:
-               memcpy( dev_addr, RIEBL_HWADDR_ADDR, ETHADDRLEN );
-               break;
-         case PAM_CARD:
-               i = IO->eeprom;
-               for( i = 0; i < ETHADDRLEN; ++i )
-                       dev_addr[i] = 
-                               ((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
-                               ((((unsigned short *)MEM)[i*2+1] & 0x0f));
-               i = IO->mem;
-               break;
-       }
-
-       MEM->init.mode = 0x0000;                /* Disable Rx and Tx. */
-       for( i = 0; i < ETHADDRLEN; i++ )
-               MEM->init.hwaddr[i] = dev_addr[i^1]; /* <- 16 bit swap! */
-       MEM->init.filter[0] = 0x00000000;
-       MEM->init.filter[1] = 0x00000000;
-       MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
-       MEM->init.rx_ring.adr_hi = 0;
-       MEM->init.rx_ring.len    = RX_RING_LEN_BITS;
-       MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
-       MEM->init.tx_ring.adr_hi = 0;
-       MEM->init.tx_ring.len    = TX_RING_LEN_BITS;
-       
-       REGA( CSR3 ) = CSR3_BSWP | (CardType == PAM_CARD ? CSR3_ACON : 0); 
-       REGA( CSR2 ) = 0;
-       REGA( CSR1 ) = 0;
-       REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
-
-       i = 1000000;
-       while( i-- > 0 )
-               if (DREG & CSR0_IDON)
-                       break;
-       if (i < 0 || (DREG & CSR0_ERR)) {
-               DREG = CSR0_STOP;
-               return( -1 );
-       }
-       DREG = CSR0_IDON;
-
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               MEM->tx_head[i].base = offsetof( struct lance_memory, tx_packet[i] );
-               MEM->tx_head[i].flag = TMD1_OWN_HOST;
-               MEM->tx_head[i].base_hi = 0;
-               MEM->tx_head[i].length = 0;
-               MEM->tx_head[i].misc = 0;
-       }
-
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               MEM->rx_head[i].base = offsetof( struct lance_memory, rx_packet[i] );
-               MEM->rx_head[i].flag = TMD1_OWN_CHIP;
-               MEM->rx_head[i].base_hi = 0;
-               MEM->rx_head[i].buf_length = -PKTLEN;
-               MEM->rx_head[i].msg_length = 0;
-       }
-       CurRx = 0;
-       
-       return( 0 );
-}
-
-
-static void lance_get_hwaddr( HWADDR *addr )
-
-{
-       memcpy( addr, dev_addr, ETHADDRLEN );
-}
-
-
-static int lance_snd( Packet *pkt, int len )
-
-{      unsigned long timeout;
-       
-       /* The old LANCE chips doesn't automatically pad buffers to min. size. */
-       len = (len < 60) ? 60 : len;
-       /* PAM-Card has a bug: Can only send packets with even number of bytes! */
-       if (CardType == PAM_CARD && (len & 1))
-               ++len;
-
-       MEM->tx_head[0].length = -len;
-       MEM->tx_head[0].misc = 0;
-       memcpy( (void *)&MEM->tx_packet[0].data, pkt, len );
-       MEM->tx_head[0].base = offsetof(struct lance_memory, tx_packet[0]);
-       MEM->tx_head[0].base_hi = 0;
-       MEM->tx_head[0].flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
-
-       /* Trigger an immediate send poll. */
-       REGA( CSR0 ) = CSR0_TDMD;
-
-       /* Wait for packet being sent */
-       timeout = _hz_200 + 3*HZ;
-       while( (MEM->tx_head[0].flag & TMD1_OWN_CHIP) &&
-                  !MEM->tx_head[0].misc &&
-                  _hz_200 < timeout )
-               ;
-
-       if ((MEM->tx_head[0].flag & TMD1_OWN) == TMD1_OWN_HOST &&
-               !(MEM->tx_head[0].misc & TMD1_ERR))
-               /* sent ok */
-               return( 0 );
-
-       /* failure */
-       if (_hz_200 >= timeout)
-               return( ETIMEO );
-       if (MEM->tx_head[0].misc & TMD3_UFLO) {
-               /* On FIFO errors, must re-turn on TX! */
-               DREG = CSR0_STRT;
-       }
-
-       return( ESEND );
-}
-
-
-static int lance_rcv( Packet *pkt, int *len )
-
-{      unsigned long   timeout;
-       int                             stat;
-       
-       /* Wait for a packet */
-       timeout = _hz_200 + 4*HZ;
-       while( (MEM->rx_head[CurRx].flag & TMD1_OWN_CHIP) &&
-                  _hz_200 < timeout )
-               ;
-       /* Not ours -> was a timeout */
-       if (((stat = MEM->rx_head[CurRx].flag) & TMD1_OWN) == TMD1_OWN_CHIP)
-               return( ETIMEO );
-
-       /* Check for errors */
-       if (stat != (RMD1_ENP|RMD1_STP)) {
-               MEM->rx_head[CurRx].flag &= (RMD1_ENP|RMD1_STP);
-               if (stat & RMD1_FRAM) return( EFRAM );
-               if (stat & RMD1_OFLO) return( EOVERFL );
-               if (stat & RMD1_CRC)  return( ECRC );
-               return( ERCV );
-       }
-
-       /* Get the packet */
-       *len = MEM->rx_head[CurRx].msg_length & 0xfff;
-       memcpy( pkt, (void *)&MEM->rx_packet[CurRx].data, *len );
-
-       /* Give the buffer back to the chip */
-       MEM->rx_head[CurRx].buf_length = -PKTLEN;
-       MEM->rx_head[CurRx].flag |= RMD1_OWN_CHIP;
-       CurRx = (CurRx + 1) % RX_RING_SIZE;
-
-       return( 0 );
-}
-
-
diff --git a/arch/m68k/boot/atari/ethlance.h b/arch/m68k/boot/atari/ethlance.h
deleted file mode 100644 (file)
index 4f9c902..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-
-#ifndef _ethlance_h
-#define _ethlance_h
-
-extern ETHIF_SWITCH LanceSwitch;
-
-#endif /* _ethlance_h */
diff --git a/arch/m68k/boot/atari/sysvars.h b/arch/m68k/boot/atari/sysvars.h
deleted file mode 100644 (file)
index 087d9f6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-typedef struct _osheader
-{
-  unsigned short os_entry;
-  unsigned short os_version;
-  void *reseth;
-  struct _osheader *os_beg;
-  void *os_end;
-  long os_rsv1;
-  void *os_magic;
-  long os_date;
-  unsigned short os_conf;
-  unsigned short os_dosdate;
-  char **p_root;
-  unsigned char **pkbshift;
-  void **p_run;
-  char *p_rsv2;
-} OSHEADER;
-
-#define phystop    ((unsigned long *)0x42e)
-#define _sysbase   ((OSHEADER **)0x4f2)
-#define _p_cookies ((unsigned long **)0x5a0)
-#define ramtop     ((unsigned long *)0x5a4)
index b963687aecb0a22c654daa25e60e7f993010f5db..2390fb6fc2a1e388f4db70aefa6753efdbbe8718 100644 (file)
@@ -218,6 +218,10 @@ define_bool CONFIG_VT y
 define_bool CONFIG_VT_CONSOLE y
 define_bool CONFIG_FB_CONSOLE y
 
+if [ "$CONFIG_ATARI" = "y" ]; then
+  define_bool CONFIG_NVRAM y
+fi
+
 tristate 'Parallel printer support' CONFIG_PRINTER
 if [ "$CONFIG_AMIGA" = "y" ]; then
   dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER
@@ -243,6 +247,7 @@ if [ "$CONFIG_AMIGA" = "y" ]; then
   dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
   dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+  bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
 fi
 if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
      "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
index 18763c58bfbea96f07f016c17a00d3662591ec31..65f71d5a9abd2e6cc2344ce4fea43eb142fb6975 100644 (file)
@@ -152,9 +152,6 @@ CONFIG_NETDEVICES=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=y
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=y
index 35542d4f11b1b7f4dfb6af7876206881d6db48e5..d068d5a161aea6d9735d304c343770515a712b48 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/linkage.h>
 #include <asm/entry.h>
 
+
 |################################
 | (1) EXAMPLE CALL-OUTS        #
 |                              #
index 204f4d3cc55e96c86ab79c7e42c89e49f5acac09..5e7b29717da58da6848d37efe8ff2fcf1e6831c8 100644 (file)
@@ -420,7 +420,10 @@ int vc_resize(unsigned long lines, unsigned long columns)
        set_scrmem(fg_console, 0);
        set_origin(fg_console);
 #endif /* XXX */
-       update_screen(fg_console);
+       /* don't update in graphics mode */
+       if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
+           update_screen(fg_console);
+
        set_cursor(fg_console);
 
        return 0;
@@ -512,8 +515,9 @@ void vc_resize_con(unsigned long lines, unsigned long columns,
            console_table[currcons]->winsize = ws;
        }
 
-   if (currcons == fg_console)
-      update_screen(fg_console);
+       /* don't update in graphics mode */
+       if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
+           update_screen(fg_console);
 }
 
 void vc_disallocate(unsigned int currcons)
index 33542ca9626431bf24812808d52d75eaea081000..459e9e93a73a51eaeae718918eae3046abe76562 100644 (file)
@@ -190,7 +190,7 @@ SYMBOL_NAME_LABEL(ret_from_interrupt)
        andw    #ALLOWINT,%sr
 
        /* check if we need to do software interrupts */
-       
+
        movel   SYMBOL_NAME(bh_active),%d0
        andl    SYMBOL_NAME(bh_mask),%d0
        jeq     SYMBOL_NAME(ret_from_exception)
index 36a4072ac59fe9a7e35fefcf62259d0f0f52c082..116c3cb2779e6ab6e8aa6af692dfc1b57d010fc5 100644 (file)
@@ -273,6 +273,9 @@ Ltest_berr:
        movel   %d2,%a0@
        lea     %pc@(SYMBOL_NAME(is_medusa)),%a0
        movel   %d3,%a0@
+       lea     %pc@(Liobase),%a0
+       movel   %d2,%a0@                /* On a Hades the iobase must be set
+                                          before opening the serial port. */
 Lnotypetest:
 #endif
 
index ad0662f22dc29d341eb95e4de1295cfc878cca1d..27883a86ef012888721bed09562badd51afc3838 100644 (file)
@@ -283,8 +283,9 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp)
        struct pt_regs *regs = (struct pt_regs *) &name;
 
        lock_kernel();
-       error = getname(name, &filename);
-       if (error)
+       filename = getname(name);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
                goto out;
        error = do_execve(filename, argv, envp, regs);
        putname(filename);
index e29509cac219c6531ccebb030a84afbfdf13b67e..9c56fed370a1f7cea5fe48c6e3d5bde7345f825f 100644 (file)
@@ -205,11 +205,10 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
   return -ENOSYS;
 }
 
-/* Convert virtual address VADDR to physical address PADDR, recording
-   in VALID whether the virtual address is actually mapped.  */
-#define virt_to_phys_040(vaddr, paddr, valid)                          \
-{                                                                      \
-  unsigned long _mmusr;                                                        \
+/* Convert virtual address VADDR to physical address PADDR */
+#define virt_to_phys_040(vaddr)                                                \
+({                                                                     \
+  unsigned long _mmusr, _paddr;                                                \
                                                                        \
   __asm__ __volatile__ (".chip 68040\n\t"                              \
                        "ptestr (%1)\n\t"                               \
@@ -217,20 +216,14 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
                        ".chip 68k"                                     \
                        : "=r" (_mmusr)                                 \
                        : "a" (vaddr));                                 \
-  if (!(_mmusr & MMU_R_040))                                           \
-    (valid) = 0;                                                       \
-  else                                                                 \
-    {                                                                  \
-      (valid) = 1;                                                     \
-      (paddr) = _mmusr & PAGE_MASK;                                    \
-    }                                                                  \
-}
+  _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;            \
+  _paddr;                                                              \
+})
 
 static inline int
 cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
 {
-  unsigned long paddr;
-  int valid;
+  unsigned long paddr, i;
 
   switch (scope)
     {
@@ -261,19 +254,31 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
       break;
 
     case FLUSH_SCOPE_LINE:
-      len >>= 4;
       /* Find the physical address of the first mapped page in the
         address range.  */
-      for (;;)
-       {
-         virt_to_phys_040 (addr, paddr, valid);
-         if (valid)
-           break;
-         if (len <= PAGE_SIZE / 16)
-           return 0;
-         len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
-         addr = (addr + PAGE_SIZE) & PAGE_MASK;
-       }
+      if ((paddr = virt_to_phys_040(addr))) {
+        paddr += addr & ~(PAGE_MASK | 15);
+        len = (len + (addr & 15) + 15) >> 4;
+      } else {
+       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+       if (len <= tmp)
+         return 0;
+       addr += tmp;
+       len -= tmp;
+       tmp = PAGE_SIZE;
+       for (;;)
+         {
+           if ((paddr = virt_to_phys_040(addr)))
+             break;
+           if (len <= tmp)
+             return 0;
+           addr += tmp;
+           len -= tmp;
+         }
+       len = (len + 15) >> 4;
+      }
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
       while (len--)
        {
          switch (cache)
@@ -301,36 +306,33 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
                                    : : "a" (paddr));
              break;
            }
-         addr += 16;
-         if (len)
+         if (!--i && len)
            {
-             if ((addr & (PAGE_SIZE-1)) < 16)
+             addr += PAGE_SIZE;
+             i = PAGE_SIZE / 16;
+             /* Recompute physical address when crossing a page
+                boundary. */
+             for (;;)
                {
-                 /* Recompute physical address when crossing a page
-                    boundary. */
-                 for (;;)
-                   {
-                     virt_to_phys_040 (addr, paddr, valid);
-                     if (valid)
-                       break;
-                     if (len <= PAGE_SIZE / 16)
-                       return 0;
-                     len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
-                     addr = (addr + PAGE_SIZE) & PAGE_MASK;
-                   }
+                 if ((paddr = virt_to_phys_040(addr)))
+                   break;
+                 if (len <= i)
+                   return 0;
+                 len -= i;
+                 addr += PAGE_SIZE;
                }
-             else
-               paddr += 16;
            }
+         else
+           paddr += 16;
        }
       break;
 
     default:
     case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
       for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
        {
-         virt_to_phys_040 (addr, paddr, valid);
-         if (!valid)
+         if (!(paddr = virt_to_phys_040(addr)))
            continue;
          switch (cache)
            {
@@ -363,21 +365,21 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
   return 0;
 }
 
-#define virt_to_phys_060(vaddr, paddr, valid)          \
-{                                                      \
+#define virt_to_phys_060(vaddr)                                \
+({                                                     \
+  unsigned long paddr;                                 \
   __asm__ __volatile__ (".chip 68060\n\t"              \
                        "plpar (%0)\n\t"                \
                        ".chip 68k"                     \
                        : "=a" (paddr)                  \
                        : "0" (vaddr));                 \
-  (valid) = 1; /* XXX */                               \
-}
+  (paddr); /* XXX */                                   \
+})
 
 static inline int
 cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
 {
-  unsigned long paddr;
-  int valid;
+  unsigned long paddr, i;
 
   switch (scope)
     {
@@ -407,19 +409,30 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
       break;
 
     case FLUSH_SCOPE_LINE:
-      len >>= 4;
       /* Find the physical address of the first mapped page in the
         address range.  */
-      for (;;)
-       {
-         virt_to_phys_060 (addr, paddr, valid);
-         if (valid)
-           break;
-         if (len <= PAGE_SIZE / 16)
-           return 0;
-         len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
-         addr = (addr + PAGE_SIZE) & PAGE_MASK;
-       }
+      len += addr & 15;
+      addr &= -16;
+      if (!(paddr = virt_to_phys_060(addr))) {
+       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+       if (len <= tmp)
+         return 0;
+       addr += tmp;
+       len -= tmp;
+       tmp = PAGE_SIZE;
+       for (;;)
+         {
+           if ((paddr = virt_to_phys_060(addr)))
+             break;
+           if (len <= tmp)
+             return 0;
+           addr += tmp;
+           len -= tmp;
+         }
+      }
+      len = (len + 15) >> 4;
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
       while (len--)
        {
          switch (cache)
@@ -447,36 +460,35 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
                                    : : "a" (paddr));
              break;
            }
-         addr += 16;
-         if (len)
+         if (!--i && len)
            {
-             if ((addr & (PAGE_SIZE-1)) < 16)
-               {
-                 /* Recompute the physical address when crossing a
-                    page boundary.  */
-                 for (;;)
-                   {
-                     virt_to_phys_060 (addr, paddr, valid);
-                     if (valid)
-                       break;
-                     if (len <= PAGE_SIZE / 16)
-                       return 0;
-                     len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
-                     addr = (addr + PAGE_SIZE) & PAGE_MASK;
-                   }
-               }
-             else
-               paddr += 16;
+             addr += PAGE_SIZE;
+             i = PAGE_SIZE / 16;
+             /* Recompute physical address when crossing a page
+                boundary. */
+             for (;;)
+               {
+                 if ((paddr = virt_to_phys_060(addr)))
+                   break;
+                 if (len <= i)
+                   return 0;
+                 len -= i;
+                 addr += PAGE_SIZE;
+               }
            }
+         else
+           paddr += 16;
        }
       break;
 
     default:
     case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+      addr &= PAGE_MASK;       /* Workaround for bug in some
+                                  revisions of the 68060 */
       for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
        {
-         virt_to_phys_060 (addr, paddr, valid);
-         if (!valid)
+         if (!(paddr = virt_to_phys_060(addr)))
            continue;
          switch (cache)
            {
index 78ab9c24538e702f82af49cf5a39619c345cad25..f9f93542f69857c7837467bf7bb88b926c33b56f 100644 (file)
@@ -80,7 +80,7 @@ bool 'System V IPC' CONFIG_SYSVIPC
 bool 'Sysctl support' CONFIG_SYSCTL
 
 if [ "$CONFIG_SGI" != "y" ]; then
-  tristate 'Parallel port support' CONFIG_PARPORT
+  tristate 'Parallel port support' CONFIG_PNP_PARPORT
 fi
 
 endmenu
index 9c6fb90739c051ba6d360d90dff5fa2bb772f178..099cb84069d1b12179434d0b742d0823f5a7349c 100644 (file)
@@ -86,6 +86,7 @@ CONFIG_INET=y
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
 
 #
 # (it is safe to leave these untouched)
index 87fd335db54c6692fbc7cea2ff1e9f75e2561446..971066c1aea4dde56fac09ee7346be797ed886c7 100644 (file)
@@ -278,7 +278,10 @@ loc_ethernet:      li      s1,~JAZZ_IE_ETHERNET
                b       loc_call
                li      t3,PTRSIZE*JAZZ_ETHERNET_IRQ    # delay slot
 
-loc_scsi:      PANIC("Unimplemented loc_scsi handler")
+loc_scsi:      li      s1,~JAZZ_IE_SCSI
+               li      a0,12         # JAZZ_SCSI_IRQ */
+               b       loc_call
+               li      t3,PTRSIZE*12 # JAZZ_ETHERNET_IRQ       # delay slot
 
 /*
  * Keyboard interrupt handler
index 4701852665a5a3868f7f47cc67d721e7f7e8385a..7d4f3b3e31195fee58a46de599ab5deb122cffec 100644 (file)
@@ -375,6 +375,7 @@ void vdma_enable(int channel)
      * Clear all interrupt flags
      */
     r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+                     r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) |
                       R4030_TC_INTR | R4030_MEM_INTR | R4030_ADDR_INTR);
 
     /*
index 805efa82186ec64025cd65e1383160235bae0130..e7550e7ad4b8c627cb1d69cd18da797a9afe288a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <asm/bootinfo.h>
 #include <asm/irq.h>
 #include <asm/jazz.h>
 #include <asm/ptrace.h>
@@ -36,11 +37,21 @@ extern void jazz_machine_restart(char *command);
 extern void jazz_machine_halt(void);
 extern void jazz_machine_power_off(void);
 
+void (*board_time_init)(struct irqaction *irq);
+
+__initfunc(static void jazz_time_init(struct irqaction *irq))
+{
+        /* set the clock to 100 Hz */
+        r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
+        setup_x86_irq(0, irq);
+}
+
 __initfunc(static void jazz_irq_setup(void))
 {
         set_except_vector(0, jazz_handle_int);
        r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
                          JAZZ_IE_ETHERNET |
+                         JAZZ_IE_SCSI     |
                          JAZZ_IE_SERIAL1  |
                          JAZZ_IE_SERIAL2  |
                          JAZZ_IE_PARALLEL |
@@ -57,14 +68,42 @@ __initfunc(static void jazz_irq_setup(void))
 
 __initfunc(void jazz_setup(void))
 {
+    tag *atag;
+
+    /*
+     * we just check if a tag_screen_info can be gathered
+     * in setup_arch(), if yes we don't proceed futher...
+     */
+    atag = bi_TagFind(tag_screen_info);
+    if (!atag) {
+       /*
+        * If no, we try to find the tag_arc_displayinfo which is
+        * always created by Milo for an ARC box (for now Milo only
+        * works on ARC boxes :) -Stoned.
+        */
+       atag = bi_TagFind(tag_arcdisplayinfo);
+       if (atag) {
+           screen_info.orig_x = 
+               ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x;
+           screen_info.orig_y = 
+               ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y;
+           screen_info.orig_video_cols  = 
+               ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns;
+           screen_info.orig_video_lines  = 
+               ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines;
+       }
+    }
+
        irq_setup = jazz_irq_setup;
        fd_cacheflush = jazz_fd_cacheflush;
        feature = &jazz_feature;                        // Will go away
+       port_base = JAZZ_PORT_BASE;
        isa_slot_offset = 0xe3000000;
        request_region(0x00,0x20,"dma1");
        request_region(0x40,0x20,"timer");
        request_region(0x80,0x10,"dma page reg");
        request_region(0xc0,0x20,"dma2");
+        board_time_init = jazz_time_init;
        /* The RTC is outside the port address space */
 
        _machine_restart = jazz_machine_restart;
index fc0d542fc154fffbd4a3a61eef818ad16ccd0aab..dabd917621cda405cfae6338b0c333a63316d2f9 100644 (file)
@@ -228,7 +228,7 @@ unsigned long * create_irix_tables(char * p, int argc, int envc,
  * an ELF header.
  */
 static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
-                                    struct inode * interpreter_inode,
+                                    struct dentry * interpreter_dentry,
                                     unsigned int *interp_load_addr)
 {
        struct file * file;
@@ -256,8 +256,8 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
        if((interp_elf_ex->e_type != ET_EXEC &&
            interp_elf_ex->e_type != ET_DYN) ||
            !elf_check_arch(interp_elf_ex->e_machine) ||
-          (!interpreter_inode->i_op ||
-           !interpreter_inode->i_op->default_file_ops->mmap)){
+          (!interpreter_dentry->d_inode->i_op ||
+           !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)) {
                printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type);
                return 0xffffffff;
        }
@@ -288,7 +288,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
                return 0xffffffff;
        }
 
-       retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
+       retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
                           (char *) elf_phdata,
                           sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
 
@@ -296,7 +296,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
        dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);
 #endif
 
-       elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+       elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
        if (elf_exec_fileno < 0) {
                printk("Could not open IRIX interp inode.\n");
                kfree(elf_phdata);
@@ -408,8 +408,9 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
        /* First of all, some simple consistency checks */
        if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || 
            !elf_check_arch(ehp->e_machine) ||
-          (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
-           !bprm->inode->i_op->default_file_ops->mmap)) {
+          (!bprm->dentry->d_inode->i_op ||
+           !bprm->dentry->d_inode->i_op->default_file_ops ||
+           !bprm->dentry->d_inode->i_op->default_file_ops->mmap)) {
                return -ENOEXEC;
        }
 
@@ -435,13 +436,14 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
 
 /* Look for an IRIX ELF interpreter. */
 static inline int look_for_irix_interpreter(char **name,
-                                           struct inode **interpreter_inode,
+                                           struct dentry **interpreter_dentry,
                                            struct elfhdr *interp_elf_ex,
                                            struct elf_phdr *epp,
                                            struct linux_binprm *bprm, int pnum)
 {
        int i, old_fs;
        int retval = -EINVAL;
+       struct dentry *dentry = NULL;
 
        *name = NULL;
        for(i = 0; i < pnum; i++, epp++) {
@@ -450,7 +452,7 @@ static inline int look_for_irix_interpreter(char **name,
 
                /* It is illegal to have two interpreters for one executable. */
                if(*name != NULL)
-                       goto losing;
+                       goto out;
 
                *name = (char *) kmalloc((epp->p_filesz +
                                          strlen(IRIX_INTERP_PREFIX)),
@@ -459,26 +461,31 @@ static inline int look_for_irix_interpreter(char **name,
                        return -ENOMEM;
 
                strcpy(*name, IRIX_INTERP_PREFIX);
-               retval = read_exec(bprm->inode, epp->p_offset, (*name + 16),
+               retval = read_exec(bprm->dentry, epp->p_offset, (*name + 16),
                                   epp->p_filesz, 1);
                if(retval < 0)
-                       goto losing;
+                       goto out;
 
                old_fs = get_fs(); set_fs(get_ds());
-               retval = namei(NAM_FOLLOW_LINK, *name, interpreter_inode);
+               dentry = namei(*name);
                set_fs(old_fs);
-               if(retval < 0)
-                       goto losing;
+               if(IS_ERR(dentry)) {
+                       retval = PTR_ERR(dentry);
+                       goto out;
+               }
 
-               retval = read_exec(*interpreter_inode, 0, bprm->buf, 128, 1);
-               if(retval < 0)
-                       goto losing;
+               retval = read_exec(dentry, 0, bprm->buf, 128, 1);
+               if(retval)
+                       goto dput_and_out;
 
                *interp_elf_ex = *((struct elfhdr *) bprm->buf);
        }
+       *interpreter_dentry = dentry;
        return 0;
 
-losing:
+dput_and_out:
+       dput(dentry);
+out:
        kfree(*name);
        return retval;
 }
@@ -538,7 +545,7 @@ static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnu
 }
 
 static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
-                                 struct inode *iino, unsigned int *iladdr,
+                                 struct dentry *identry, unsigned int *iladdr,
                                  int pnum, int old_fs,
                                  unsigned int *eentry)
 {
@@ -554,11 +561,11 @@ static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
                        return -1;
 
                set_fs(old_fs);
-               *eentry = load_irix_interp(ihp, iino, iladdr);
+               *eentry = load_irix_interp(ihp, identry, iladdr);
                old_fs = get_fs();
                set_fs(get_ds());
 
-               iput(iino);
+               dput(identry);
 
                if(*eentry == 0xffffffff)
                        return -1;
@@ -573,7 +580,7 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm,
                                      struct pt_regs * regs)
 {
        struct elfhdr elf_ex, interp_elf_ex;
-       struct inode *interpreter_inode;
+       struct dentry *interpreter_dentry;
        struct elf_phdr *elf_phdata, *elf_ihdr, *elf_ephdr;
        unsigned int load_addr, elf_bss, elf_brk;
        unsigned int elf_entry, interp_load_addr = 0;
@@ -599,7 +606,7 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm,
        if (elf_phdata == NULL)
                return -ENOMEM;
        
-       retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+       retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata,
                           elf_ex.e_phentsize * elf_ex.e_phnum, 1);
        if (retval < 0) {
                kfree (elf_phdata);
@@ -629,7 +636,7 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm,
 
        elf_bss = 0;
        elf_brk = 0;
-       elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+       elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY);
 
        if (elf_exec_fileno < 0) {
                kfree (elf_phdata);
@@ -642,7 +649,8 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm,
        end_code = 0;
        end_data = 0;
        
-       retval = look_for_irix_interpreter(&elf_interpreter, &interpreter_inode,
+       retval = look_for_irix_interpreter(&elf_interpreter,
+                                          &interpreter_dentry,
                                           &interp_elf_ex, elf_phdata, bprm,
                                           elf_ex.e_phnum);
        if(retval) {
@@ -703,7 +711,7 @@ static inline int do_load_irix_binary(struct linux_binprm * bprm,
 
        if(elf_interpreter) {
                retval = map_interpreter(elf_phdata, &interp_elf_ex,
-                                        interpreter_inode, &interp_load_addr,
+                                        interpreter_dentry, &interp_load_addr,
                                         elf_ex.e_phnum, old_fs, &elf_entry);
                kfree(elf_interpreter);
                if(retval) {
@@ -795,7 +803,8 @@ static inline int do_load_irix_library(int fd)
        struct file * file;
        struct elfhdr elf_ex;
        struct elf_phdr *elf_phdata  =  NULL;
-       struct  inode * inode;
+       struct dentry *dentry;
+       struct inode *inode;
        unsigned int len;
        int elf_bss;
        int retval;
@@ -805,7 +814,8 @@ static inline int do_load_irix_library(int fd)
 
        len = 0;
        file = current->files->fd[fd];
-       inode = file->f_inode;
+       dentry = file->f_dentry;
+       inode = dentry->d_inode;
        elf_bss = 0;
        
        if (!file || !file->f_op)
@@ -831,7 +841,8 @@ static inline int do_load_irix_library(int fd)
        /* First of all, some simple consistency checks. */
        if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
           !elf_check_arch(elf_ex.e_machine) ||
-          (!inode->i_op || !inode->i_op->default_file_ops->mmap))
+          (!dentry->d_inode->i_op ||
+           !dentry->d_inode->i_op->default_file_ops->mmap))
                return -ENOEXEC;
        
        /* Now read in all of the header information. */
@@ -843,7 +854,7 @@ static inline int do_load_irix_library(int fd)
        if (elf_phdata == NULL)
                return -ENOMEM;
        
-       retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+       retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata,
                           sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
        
        j = 0;
@@ -973,14 +984,13 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt)
  */
 static int dump_write(struct file *file, const void *addr, int nr)
 {
-       file->f_inode->i_status |= ST_MODIFIED;
-       return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+       return file->f_op->write(file->f_dentry->d_inode, file, addr, nr) == nr;
 }
 
 static int dump_seek(struct file *file, off_t off)
 {
        if (file->f_op->llseek) {
-               if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
+               if (file->f_op->llseek(file->f_dentry->d_inode, file, off, 0) != off)
                        return 0;
        } else
                file->f_pos = off;
@@ -1071,6 +1081,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
 {
        int has_dumped = 0;
        struct file file;
+       struct dentry *dentry;
        struct inode *inode;
        unsigned short fs;
        char corefile[6+sizeof(current->comm)];
@@ -1138,30 +1149,24 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
        
        fs = get_fs();
        set_fs(KERNEL_DS);
-       memcpy(corefile,"core.",5);
+       memcpy(corefile,"core.", 5);
 #if 0
        memcpy(corefile+5,current->comm,sizeof(current->comm));
 #else
        corefile[4] = '\0';
 #endif
-       if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+       dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600);
+       if (IS_ERR(dentry)) {
                inode = NULL;
                goto end_coredump;
        }
+       inode = dentry->d_inode;
        if (!S_ISREG(inode->i_mode))
                goto end_coredump;
        if (!inode->i_op || !inode->i_op->default_file_ops)
                goto end_coredump;
-       file.f_mode = 3;
-       file.f_flags = 0;
-       file.f_count = 1;
-       file.f_inode = inode;
-       file.f_pos = 0;
-       file.f_reada = 0;
-       file.f_op = inode->i_op->default_file_ops;
-       if (file.f_op->open)
-               if (file.f_op->open(inode,&file))
-                       goto end_coredump;
+       if (init_private_file(&file, dentry, 3))
+               goto end_coredump;
        if (!file.f_op->write)
                goto close_coredump;
        has_dumped = 1;
@@ -1330,11 +1335,11 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
 
  close_coredump:
        if (file.f_op->release)
-               file.f_op->release(inode,&file);
+               file.f_op->release(inode, &file);
 
  end_coredump:
        set_fs(fs);
-       iput(inode);
+       dput(dentry);
 #ifndef CONFIG_BINFMT_ELF
        MOD_DEC_USE_COUNT;
 #endif
index 2faf604c7f1c85c2e01da81db9cfdb93ca3f4369..f1b117a63c909d96cffa81fa666cf83d5e1bc1d4 100644 (file)
@@ -131,20 +131,21 @@ asmlinkage int sys_clone(struct pt_regs *regs)
  */
 asmlinkage int sys_execve(struct pt_regs *regs)
 {
-       int res;
+       int error;
        char * filename;
 
        lock_kernel();
-       res = getname((char *) (long)regs->regs[4], &filename);
-       if (res)
+       filename = getname((char *) (long)regs->regs[4]);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
                goto out;
-       res = do_execve(filename, (char **) (long)regs->regs[5],
-                       (char **) (long)regs->regs[6], regs);
+       error = do_execve(filename, (char **) (long)regs->regs[5],
+                         (char **) (long)regs->regs[6], regs);
        putname(filename);
 
 out:
        unlock_kernel();
-       return res;
+       return error;
 }
 
 /*
index c448ce99eee7d2af3f527af60ac01cca33b6fb65..c66b680755f368d088bf6f14b114c4f5b4d1e50c 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996 by Ralf Baechle
  *
- * $Id: syscalls.h,v 1.5 1997/06/25 17:08:35 ralf Exp $
+ * $Id: syscalls.h,v 1.6 1997/07/20 15:32:25 ralf Exp $
  */
 
 /*
@@ -208,3 +208,5 @@ SYS(sys_getresuid, 3)
 SYS(sys_query_module, 5)
 SYS(sys_poll, 3)
 SYS(sys_nfsservctl, 3)
+SYS(sys_setresgid, 3)                          /* 4190 */
+SYS(sys_getresgid, 3)
index 2e8363f41460dd8829304a21f74ba6716ea20a75..1036bfcc49d95f2d2dbbd2b0dce9de4a8ba16a27 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.2 1997/06/17 15:24:26 ralf Exp $
+/* $Id: sysirix.c,v 1.3 1997/07/20 15:32:25 ralf Exp $
  * sysirix.c: IRIX system call emulation.
  *
  * Copyright (C) 1996 David S. Miller
@@ -652,6 +652,7 @@ struct irix_statfs {
 asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
                           int len, int fs_type)
 {
+       struct dentry *dentry;
        struct inode *inode;
        struct statfs kbuf;
        int error, old_fs, i;
@@ -664,20 +665,19 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
        if (error)
                goto out;
-       error = namei(NAM_FOLLOW_LINK, path, &inode);
-       if (error)
-               goto out;
-       if (!inode->i_sb->s_op->statfs) {
-               iput(inode);
-               error = -ENOSYS;
+       dentry = namei(path);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
                goto out;
-       }
 
+       inode = dentry->d_inode;
        old_fs = get_fs(); set_fs(get_ds());
-       inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+                                         sizeof(struct statfs));
        set_fs(old_fs);
+       if (error)
+               goto dput_and_out;
 
-       iput(inode);
        __put_user(kbuf.f_type, &buf->f_type);
        __put_user(kbuf.f_bsize, &buf->f_bsize);
        __put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -691,6 +691,8 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
        }
        error = 0;
 
+dput_and_out:
+       dput(dentry);
 out:
        unlock_kernel();
        return error;
@@ -698,7 +700,8 @@ out:
 
 asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
 {
-       struct inode * inode;
+       struct dentry *dentry;
+       struct inode *inode;
        struct statfs kbuf;
        struct file *file;
        int error, old_fs, i;
@@ -711,18 +714,29 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
                error = -EBADF;
                goto out;
        }
-       if (!(inode = file->f_inode)) {
+       if (!(dentry = file->f_dentry)) {
+               error = -ENOENT;
+               goto out;
+       }
+       if (!(inode = dentry->d_inode)) {
                error = -ENOENT;
                goto out;
        }
+       if (!inode->i_sb) {
+               error = -ENODEV;
+               goto out;
+       }
        if (!inode->i_sb->s_op->statfs) {
                error = -ENOSYS;
                goto out;
        }
 
        old_fs = get_fs(); set_fs(get_ds());
-       inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+                                         sizeof(struct statfs));
        set_fs(old_fs);
+       if (error)
+               goto out;
 
        __put_user(kbuf.f_type, &buf->f_type);
        __put_user(kbuf.f_bsize, &buf->f_bsize);
@@ -789,13 +803,14 @@ out:
 asmlinkage int irix_exec(struct pt_regs *regs)
 {
        int error, base = 0;
-       char * filename;
+       char *filename;
 
        lock_kernel();
        if(regs->regs[2] == 1000)
                base = 1;
-       error = getname((char *) (long)regs->regs[base + 4], &filename);
-       if (error)
+       filename = getname((char *) (long)regs->regs[base + 4]);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
                goto out;
        error = do_execve(filename, (char **) (long)regs->regs[base + 5],
                          (char **) 0, regs);
@@ -809,13 +824,14 @@ out:
 asmlinkage int irix_exece(struct pt_regs *regs)
 {
        int error, base = 0;
-       char * filename;
+       char *filename;
 
        lock_kernel();
        if(regs->regs[2] == 1000)
                base = 1;
-       error = getname((char *) (long)regs->regs[base + 4], &filename);
-       if (error)
+       filename = getname((char *) (long)regs->regs[base + 4]);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
                goto out;
        error = do_execve(filename, (char **) (long)regs->regs[base + 5],
                          (char **) (long)regs->regs[base + 6], regs);
@@ -1380,6 +1396,7 @@ struct irix_statvfs {
 
 asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
 {
+       struct dentry *dentry;
        struct inode *inode;
        struct statfs kbuf;
        int error, old_fs, i;
@@ -1390,20 +1407,23 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
        if(error)
                goto out;
-       error = namei(NAM_FOLLOW_LINK, fname, &inode);
-       if(error)
-               goto out;
-       if(!inode->i_sb->s_op->statfs) {
-               iput(inode);
-               error = -ENOSYS;
+       dentry = namei(fname);
+       error = PTR_ERR(dentry);
+       if(!IS_ERR(dentry))
                goto out;
-       }
+       inode = dentry->d_inode;
+
+       error = -ENOSYS;
+       if(!inode->i_sb->s_op->statfs)
+               goto dput_and_out;
 
        old_fs = get_fs(); set_fs(get_ds());
-       inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+                                         sizeof(struct statfs));
        set_fs(old_fs);
+       if (error)
+               goto dput_and_out;
 
-       iput(inode);
        __put_user(kbuf.f_bsize, &buf->f_bsize);
        __put_user(kbuf.f_frsize, &buf->f_frsize);
        __put_user(kbuf.f_blocks, &buf->f_blocks);
@@ -1426,6 +1446,8 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
 
        error = 0;
 
+dput_and_out:
+       dput(dentry);
 out:
        unlock_kernel();
        return error;
@@ -1433,7 +1455,8 @@ out:
 
 asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
 {
-       struct inode * inode;
+       struct dentry *dentry;
+       struct inode *inode;
        struct statfs kbuf;
        struct file *file;
        int error, old_fs, i;
@@ -1449,7 +1472,11 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
                error = -EBADF;
                goto out;
        }
-       if (!(inode = file->f_inode)) {
+       if (!(dentry = file->f_dentry)) {
+               error = -ENOENT;
+               goto out;
+       }
+       if (!(inode = dentry->d_inode)) {
                error = -ENOENT;
                goto out;
        }
@@ -1459,8 +1486,11 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
        }
 
        old_fs = get_fs(); set_fs(get_ds());
-       inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+                                         sizeof(struct statfs));
        set_fs(old_fs);
+       if (error)
+               goto out;
 
        __put_user(kbuf.f_bsize, &buf->f_bsize);
        __put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -1489,26 +1519,28 @@ out:
        return error;
 }
 
-#define NOFOLLOW_LINKS  NAM_FOLLOW_TRAILSLASH
-#define FOLLOW_LINKS    NAM_FOLLOW_LINK
+#define NOFOLLOW_LINKS  0
+#define FOLLOW_LINKS    1
 
-static inline int chown_common(char *filename, uid_t user, gid_t group, int follow)
+static inline int chown_common(uid_t user, gid_t group, struct dentry *dentry)
 {
        struct inode * inode;
        int error;
        struct iattr newattrs;
 
-       error = namei(follow, filename,&inode);
-       if (error)
-               return error;
-       if (IS_RDONLY(inode)) {
-               iput(inode);
-               return -EROFS;
-       }
-       if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
-               iput(inode);
-               return -EPERM;
-       }
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
+               goto out;
+       inode = dentry->d_inode;
+
+       error = -EROFS;
+       if (IS_RDONLY(inode))
+               goto dput_and_out;
+
+       error = -EPERM;
+       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+               goto dput_and_out;
+
        if (user == (uid_t) -1)
                user = inode->i_uid;
        if (group == (gid_t) -1)
@@ -1534,38 +1566,45 @@ static inline int chown_common(char *filename, uid_t user, gid_t group, int foll
                newattrs.ia_mode &= ~S_ISGID;
                newattrs.ia_valid |= ATTR_MODE;
        }
-       inode->i_dirt = 1;
        if (inode->i_sb->dq_op) {
                inode->i_sb->dq_op->initialize(inode, -1);
+               error = -EDQUOT;
                if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
-                       return -EDQUOT;
+                       goto dput_and_out;
                error = notify_change(inode, &newattrs);
                if (error)
                        inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
        } else
                error = notify_change(inode, &newattrs);
-       iput(inode);
-       return(error);
+
+dput_and_out:
+       dput(dentry);
+out:
+       return error;
 }
 
-asmlinkage int irix_chown(char *fname, int uid, int gid)
+asmlinkage int irix_chown(const char *filename, int uid, int gid)
 {
        int retval;
+       struct dentry *dentry;
 
        lock_kernel();
        /* Do follow any and all links... */
-       retval = chown_common(fname, uid, gid, FOLLOW_LINKS);
+       dentry = namei(filename);
+       retval = chown_common(uid, gid, dentry);
        unlock_kernel();
        return retval;
 }
 
-asmlinkage int irix_lchown(char *fname, int uid, int gid)
+asmlinkage int irix_lchown(const char *filename, int uid, int gid)
 {
        int retval;
+       struct dentry *dentry;
 
        lock_kernel();
        /* Do _not_ follow any links... */
-       retval = chown_common(fname, uid, gid, NOFOLLOW_LINKS);
+       dentry = lnamei(filename);
+       retval = chown_common(uid, gid, dentry);
        unlock_kernel();
        return retval;
 }
@@ -1722,6 +1761,7 @@ struct irix_statvfs64 {
 
 asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
 {
+       struct dentry *dentry;
        struct inode *inode;
        struct statfs kbuf;
        int error, old_fs, i;
@@ -1731,20 +1771,22 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
        if(error)
                goto out;
-       error = namei(NAM_FOLLOW_LINK, fname, &inode);
-       if(error)
-               goto out;
-       if(!inode->i_sb->s_op->statfs) {
-               iput(inode);
-               error = -ENOSYS;
+       dentry = namei(fname);
+       error = PTR_ERR(dentry);
+       if(IS_ERR(dentry))
                goto out;
-       }
+       error = -ENOSYS;
+       inode = dentry->d_inode;
+       if(!inode->i_sb->s_op->statfs)
+               goto dput_and_out;
 
        old_fs = get_fs(); set_fs(get_ds());
-       inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+                                         sizeof(struct statfs));
        set_fs(old_fs);
+       if (error)
+               goto dput_and_out;
 
-       iput(inode);
        __put_user(kbuf.f_bsize, &buf->f_bsize);
        __put_user(kbuf.f_frsize, &buf->f_frsize);
        __put_user(kbuf.f_blocks, &buf->f_blocks);
@@ -1767,6 +1809,8 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
 
        error = 0;
 
+dput_and_out:
+       dput(dentry);
 out:
        unlock_kernel();
        return error;
@@ -1774,7 +1818,8 @@ out:
 
 asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
 {
-       struct inode * inode;
+       struct dentry *dentry;
+       struct inode *inode;
        struct statfs kbuf;
        struct file *file;
        int error, old_fs, i;
@@ -1790,7 +1835,11 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
                error = -EBADF;
                goto out;
        }
-       if (!(inode = file->f_inode)) {
+       if (!(dentry = file->f_dentry)) {
+               error = -ENOENT;
+               goto out;
+       }
+       if (!(inode = dentry->d_inode)) {
                error = -ENOENT;
                goto out;
        }
@@ -1800,8 +1849,11 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
        }
 
        old_fs = get_fs(); set_fs(get_ds());
-       inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+                                         sizeof(struct statfs));
        set_fs(old_fs);
+       if (error)
+               goto out;
 
        __put_user(kbuf.f_bsize, &buf->f_bsize);
        __put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -1927,6 +1979,8 @@ out:
 asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob)
 {
        struct file *file;
+       struct dentry *dentry;
+       struct inode *inode;
        struct irix_dirent32 *lastdirent;
        struct irix_dirent32_callback buf;
        int error;
@@ -1936,25 +1990,34 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count
        printk("[%s:%d] ngetdents(%d, %p, %d, %p) ", current->comm,
               current->pid, fd, dirent, count, eob);
 #endif
-       if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
-               error = -EBADF;
+       error = -EBADF;
+       if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
                goto out;
-       }
-       if (!file->f_op || !file->f_op->readdir) {
-               error = -ENOTDIR;
+
+       dentry = file->f_dentry;
+       if (!dentry)
                goto out;
-       }
-       if(verify_area(VERIFY_WRITE, dirent, count) ||
-          verify_area(VERIFY_WRITE, eob, sizeof(*eob))) {
-               error = -EFAULT;
+
+       inode = dentry->d_inode;
+       if (!inode)
                goto out;
-       }
+
+       error = -ENOTDIR;
+       if (!file->f_op || !file->f_op->readdir)
+               goto out;
+
+       error = -EFAULT;
+       if(!access_ok(VERIFY_WRITE, dirent, count) ||
+          !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
+               goto out;
+
        __put_user(0, eob);
        buf.current_dir = (struct irix_dirent32 *) dirent;
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;
-       error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir32);
+
+       error = file->f_op->readdir(inode, file, &buf, irix_filldir32);
        if (error < 0)
                goto out;
        lastdirent = buf.previous;
@@ -2027,6 +2090,8 @@ out:
 asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
 {
        struct file *file;
+       struct dentry *dentry;
+       struct inode *inode;
        struct irix_dirent64 *lastdirent;
        struct irix_dirent64_callback buf;
        int error;
@@ -2036,28 +2101,35 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
        printk("[%s:%d] getdents64(%d, %p, %d) ", current->comm,
               current->pid, fd, dirent, cnt);
 #endif
-       if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
-               error = -EBADF;
+       error = -EBADF;
+       if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
                goto out;
-       }
-       if (!file->f_op || !file->f_op->readdir) {
-               error = -ENOTDIR;
+
+       dentry = file->f_dentry;
+       if (!dentry)
                goto out;
-       }
-       if(verify_area(VERIFY_WRITE, dirent, cnt)) {
-               error = -EFAULT;
+
+       inode = dentry->d_inode;
+       if (!inode)
                goto out;
-       }
-       if(cnt < (sizeof(struct irix_dirent64) + 255)) {
-               error = -EINVAL;
+
+       error = -ENOTDIR;
+       if (!file->f_op || !file->f_op->readdir)
+               goto out;
+
+       error = -EFAULT;
+       if(!access_ok(VERIFY_WRITE, dirent, cnt))
+               goto out;
+
+       error = -EINVAL;
+       if(cnt < (sizeof(struct irix_dirent64) + 255))
                goto out;
-       }
 
        buf.curr = (struct irix_dirent64 *) dirent;
        buf.previous = NULL;
        buf.count = cnt;
        buf.error = 0;
-       error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir64);
+       error = file->f_op->readdir(inode, file, &buf, irix_filldir64);
        if (error < 0)
                goto out;
        lastdirent = buf.previous;
@@ -2079,6 +2151,8 @@ out:
 asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob)
 {
        struct file *file;
+       struct dentry *dentry;
+       struct inode *inode;
        struct irix_dirent64 *lastdirent;
        struct irix_dirent64_callback buf;
        int error;
@@ -2088,30 +2162,37 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob)
        printk("[%s:%d] ngetdents64(%d, %p, %d) ", current->comm,
               current->pid, fd, dirent, cnt);
 #endif
-       if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
-               error = -EBADF;
+       error = -EBADF;
+       if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
                goto out;
-       }
-       if (!file->f_op || !file->f_op->readdir) {
-               error = -ENOTDIR;
+
+       dentry = file->f_dentry;
+       if (!dentry)
                goto out;
-       }
-       if(verify_area(VERIFY_WRITE, dirent, cnt) ||
-          verify_area(VERIFY_WRITE, eob, sizeof(*eob))) {
-               error = -EFAULT;
+
+       inode = dentry->d_inode;
+       if (!inode)
                goto out;
-       }
-       if(cnt < (sizeof(struct irix_dirent64) + 255)) {
-               error = -EINVAL;
+
+       error = -ENOTDIR;
+       if (!file->f_op || !file->f_op->readdir)
+               goto out;
+
+       error = -EFAULT;
+       if(!access_ok(VERIFY_WRITE, dirent, cnt) ||
+          !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
+               goto out;
+
+       error = -EINVAL;
+       if(cnt < (sizeof(struct irix_dirent64) + 255))
                goto out;
-       }
 
        *eob = 0;
        buf.curr = (struct irix_dirent64 *) dirent;
        buf.previous = NULL;
        buf.count = cnt;
        buf.error = 0;
-       error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir64);
+       error = file->f_op->readdir(inode, file, &buf, irix_filldir64);
        if (error < 0)
                goto out;
        lastdirent = buf.previous;
index 32dce029d2e55f27ed61109686408a216b8bcafd..0b128f1b34d31d47b1a38d0e5a6a3c3c20d49e95 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: sysmips.c,v 1.4 1997/06/30 15:52:37 ralf Exp $
+ * $Id: sysmips.c,v 1.5 1997/07/20 15:32:27 ralf Exp $
  */
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -57,18 +57,21 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3)
        switch(cmd)
        {
        case SETNAME:
-               if (!suser()) {
-                       retval = -EPERM;
+               retval = -EPERM;
+               if (!suser())
                        goto out;
-               }
+
                name = (char *) arg1;
                len = strlen_user(name);
+
+               retval = len;
                if (len < 0)
-                       retval = len;
                        goto out;
+
+               retval = -EINVAL;
                if (len == 0 || len > __NEW_UTS_LEN)
-                       retval = -EINVAL;
                        goto out;
+
                copy_from_user(system_utsname.nodename, name, len);
                system_utsname.nodename[len] = '\0';
                retval = 0;
index 3ad703b1fbf3c81406afe67929a99fb7b8c79115..f1ebab648617209df9fc047e79a3b39b1bc28958 100644 (file)
@@ -81,17 +81,6 @@ good_area:
  */
 bad_area:
        up(&mm->mmap_sem);
-       /* Did we have an exception handler installed? */
-
-       fixup = search_exception_table(regs->cp0_epc);
-       if (fixup) {
-               long new_epc;
-               new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
-               printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n",
-                      regs->cp0_epc, new_epc);
-               regs->cp0_epc = new_epc;
-               goto out;
-       }
 
        if (user_mode(regs)) {
                tsk->tss.cp0_badvaddr = address;
@@ -111,6 +100,18 @@ bad_area:
                force_sig(SIGSEGV, tsk);
                goto out;
        }
+
+       /* Did we have an exception handler installed? */
+       fixup = search_exception_table(regs->cp0_epc);
+       if (fixup) {
+               long new_epc;
+               new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
+               printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+                      tsk->comm, regs->cp0_epc, new_epc);
+               regs->cp0_epc = new_epc;
+               goto out;
+       }
+
        /*
         * Oops. The kernel tried to access some bad page. We'll have to
         * terminate things with extreme prejudice.
index 7a4b6df4bb69bf281a99326e45f0c27a70688a2f..b62e571d60cccbf40fd5233d84a006bff60edd00 100644 (file)
@@ -156,7 +156,6 @@ static inline void
 zeropage(unsigned long page)
 {
        flush_page_to_ram(page);
-       sync_mem();
        __zeropage(page);
 }
 
index af577c5ae8ac048627452557f046a79b54f997b7..ac271997766721757f2b6300b191dedb2947e612 100644 (file)
@@ -25,61 +25,62 @@ HOSTCC              = gcc
 CC             = gcc$(SUFFIX)
 CFLAGSINC      = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
 CFLAGS         = $(CFLAGSINC) \
-               -Wstrict-prototypes \
-               -fomit-frame-pointer \
+               -Wstrict-prototypes -fomit-frame-pointer \
                -fno-builtin \
-               -finhibit-size-directive -fno-strength-reduce\
-               -O2 -fsigned-char -pipe -mstring -mmultiple
+               -finhibit-size-directive \
+               -O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
+# -fverbose-asm 
 CPP            = $(CC) -E $(CFLAGS)
 AR             = ar$(SUFFIX)
 RANLIB         = ranlib$(SUFFIX)
 STRIP          = strip$(SUFFIX)
 NM             = nm$(SUFFIX)
 
-ifdef CONFIG_603
-CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
+ifdef CONFIG_601
+CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
 endif
 
-ifdef CONFIG_603e
-CFLAGS := $(CFLAGS) -mcpu=603e -DCPU=603e
+ifdef CONFIG_603
+CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
 endif
 
 ifdef CONFIG_604
 CFLAGS := $(CFLAGS) -mcpu=604 -DCPU=604
 endif
 
-#
-# NFS_ROOT_NAME specifies the default name of the directory to mount
-# as root via NFS, if the kernel does not get the "root=" option from
-# the boot loader. The "%s" will be replaced by the IP-number of the
-# local system.
-#
-NFS_ROOT = -DNFS_ROOT="\"/joplin/ppc/root\""
-
 HEAD := arch/ppc/kernel/head.o
 
 ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib
 SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
 ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
-
+CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
-netboot: vmlinux
+checks:
+       @$(MAKE) -C arch/$(ARCH)/kernel checks
+
+netboot: checks vmlinux
        @$(MAKEBOOT) netboot
 
-znetboot: vmlinux
+znetboot: checks vmlinux
        @$(MAKEBOOT) znetboot
 
-zImage: vmlinux
+#rcpboot: checks vmlinux
+#      @$(MAKEBOOT) rcpboot
+
+zImage: checks vmlinux
        @$(MAKEBOOT) zImage
 
-floppy: vmlinux
+floppy: checks vmlinux
        @$(MAKEBOOT) floppy
 
-install: vmlinux
+install: checks vmlinux
        @$(MAKEBOOT) install
 
+vmlinux.coff : checks vmlinux
+       $(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
+
 arch/ppc/kernel: dummy
        $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
 
@@ -89,12 +90,24 @@ arch/ppc/mm: dummy
 arch/ppc/lib: dummy
        $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
 
+diffs:
+       arch/ppc/mkdiff
+
+tar:
+       arch/ppc/mktar
 
 archclean:
-       rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h TAGS
+       rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
+       rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+       rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
        @$(MAKEBOOT) clean
 
 archdep:
+       $(MAKE) -C arch/ppc/boot fastdep
+       $(MAKE) -C arch/ppc/kernel fastdep
+       $(MAKE) -C arch/ppc/mm fastdep
+       $(MAKE) -C arch/ppc/lib fastdep
+
+tags :
+       etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c 
 
-corttags :
-       etags arch/ppc/*/*.c include/asm/* */*.c drivers/*/*.c net/*.c
index 7b4ed71f6480d633fd5a7e70d3fe0649bbd41a8d..5dcac750e4136d1c586594f203e25ac2659b00e1 100644 (file)
@@ -7,6 +7,7 @@
 #
 # Copyright (C) 1994 by Linus Torvalds
 # Adapted for PowerPC by Gary Thomas
+# modified by Cort (cort@cs.nmt.edu)
 #
 
 .c.s:
@@ -22,7 +23,7 @@
 
 
 ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
-GZIP_FLAGS = -9
+GZIP_FLAGS = -v9
 
 SYSTEM = $(TOPDIR)/vmlinux
 
@@ -32,49 +33,51 @@ CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include
 
 all:   $(TOPDIR)/zImage
 
-mkboot : cortstrip.c
-       $(HOSTCC) $(CFLAGSINC) -Wl,-static -o mkboot cortstrip.c
+mkprep : mkprep.c
+       $(HOSTCC) $(CFLAGSINC) -o mkprep mkprep.c
+
+find_name : find_name.c
+       $(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
 
 mk_type41: mk_type41.c
-       $(HOSTCC) $(CFLAGSINC) -Wl,-static -o mk_type41 mk_type41.c
+       $(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
+
+piggyback: piggyback.c
+       $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
 
-floppy: zImage $(TOPDIR)/vmlinux
+floppy: $(TOPDIR)/vmlinux zImage 
        dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
 
-netboot : $(TOPDIR)/vmlinux mkboot
-       mkboot $(TOPDIR)/vmlinux $(TOPDIR)/netboot
-#      rcp $(TOPDIR)/netboot charon:/usr/tftpboot/vmlinux
+netboot : $(TOPDIR)/vmlinux mkprep
+       mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+
+znetboot : zvmlinux mkprep
+       mkprep zvmlinux $(TOPDIR)/znetboot
+       cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
 
-znetboot : mkboot zvmlinux
-       mkboot zvmlinux $(TOPDIR)/znetboot
+rcpboot : znetboot
        rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
 
-zImage: mk_type41 zvmlinux
-# make znetboot ourselves since using the normal dep
-# will rcp it -- Cort
-       mkboot zvmlinux $(TOPDIR)/znetboot
-       mk_type41 $(TOPDIR)/znetboot $(TOPDIR)/zImage
+zImage: zvmlinux mkprep
+       mkprep -pbp zvmlinux $(TOPDIR)/zImage
 
 install: zImage
        dd if=$(TOPDIR)/zImage of=/dev/sda4
        ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
        cp $(TOPDIR)/System.map $(INSTALL_PATH)/        
 
-zvmlinux: $(OBJECTS) $(SYSTEM) piggyback netboot $(TOPDIR)/vmlinux
-       gzip ${GZIP_FLAGS} <$(TOPDIR)/netboot | ./piggyback | $(AS) -o piggy.o
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep  find_name
+       mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
        $(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
-       rm -f piggy.o xx_boot
-
-head.o:        head.s
-
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
-       $(CPP) -traditional head.S -o head.s
-
-piggyback: piggyback.c
-       $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
+       rm -f piggy.o
 
 clean:
-       rm -f piggyback zvmlinux mk_type41 mkprep mkboot
+       rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
        rm -f $(TOPDIR)/{zImage,znetboot,netboot}
 
+fastdep:
+       $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
 dep:
+       $(CPP) -M *.S *.c > .depend
+
diff --git a/arch/ppc/boot/cortstrip.c b/arch/ppc/boot/cortstrip.c
deleted file mode 100644 (file)
index 78856d2..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/* amount to skip */
-#define PLACE 65536
-
-/* size of read buffer */
-#define SIZE 0x100000
-
-/* crude program to strip the elf header to make a bootable
-   image via tftp
- */
-
-
-int main(int argc, char **argv )
-{
-  int fd, fdo;
-  unsigned char data[SIZE];
-  int i, n, skip;
-
-#if 0
-  if ( argc != 3 )
-  {
-    fprintf(stderr,"%s infile outfile\n", argv[0]);
-    exit(-1);
-  }
-#endif
-
-
-  fd = open(argv[1], O_RDONLY);
-  if ( fd == -1 )
-  {
-    fprintf(stderr,"Couldn't open %s\n", argv[1]);
-    perror("open()");
-    exit(-1);
-  }
-  
-  fdo = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC,0755);
-  if ( fdo == -1 )
-  {
-    fprintf(stderr,"Couldn't open %s\n", argv[2]);
-    perror("open()");
-    exit(-1);
-  }
-
-#if 0
-  skip = atoi(argv[3]);
-#else
-  skip = PLACE;
-#endif
-  i = lseek(fd, skip, SEEK_SET);
- /*printf("lseek'd %d bytes\n", i);*/
-  if ( i == -1 )
-  {
-      perror("lseek()");
-  }
-
-  while ( (n = read(fd, data, SIZE)) > 0 )
-  {
-    /*printf("Read %d bytes\n", n);*/
-    i = write(fdo, data, n);
-    /*printf("Wrote %d bytes\n", i);    */
-  }
-
-
-  close(fdo);
-  close(fd);
-  return(0);
-}
-
-
diff --git a/arch/ppc/boot/find_name.c b/arch/ppc/boot/find_name.c
new file mode 100644 (file)
index 0000000..23646fb
--- /dev/null
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <asm/page.h>
+#include <sys/mman.h>
+/*
+ * Finds a given address in the System.map and prints it out
+ * with its neighbors.  -- Cort
+ */
+
+void main(int argc, char **argv)
+{
+       unsigned long addr, cmp, i;
+       FILE *f;
+       char *ptr;
+       char s[256], last[256];
+       
+       if ( argc < 2 )
+       {
+               fprintf(stderr, "Usage: %s <address>\n", argv[0]);
+               exit(-1);
+       }
+
+       for ( i = 1 ; argv[i] ; i++ )
+       {
+               sscanf( argv[i], "%0x", &addr );
+               /* adjust if addr is relative to kernelbase */
+               if ( addr < PAGE_OFFSET )
+                       addr += PAGE_OFFSET;
+               
+               if ( (f = fopen( "System.map", "r" )) == NULL )
+               {
+                       perror("fopen()\n");
+                       exit(-1);
+               }
+               
+               while ( !feof(f) )
+               {
+                       fgets(s, 255 , f);
+                       sscanf( s, "%0x", &cmp );
+                       if ( addr < cmp )
+                               break;
+                       strcpy( last, s);
+               }
+               
+               printf( "%s", last);
+       }               
+       fclose(f);
+}
index 2f738b945155b531815458c0c620264debb25fb9..9d8e54a4b8b34f2d54ffa4dd85292558e111449a 100644 (file)
@@ -271,7 +271,7 @@ extern int  fill_inbuf    OF((void));
 extern void flush_outbuf  OF((void));
 extern void flush_window  OF((void));
 extern char *strlwr       OF((char *s));
-extern char *basename     OF((char *fname));
+/*extern char *basename     OF((char *fname));*/
 extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
 extern void error         OF((char *m));
 extern void warn          OF((char *a, char *b));
index 35dacd514f2c7b1ea025e9fd1d5006617105d7c7..6b25cb15736ffe278fd95b443036abac85f40b15 100644 (file)
@@ -1,5 +1,6 @@
 #include "../kernel/ppc_defs.h"
 #include "../kernel/ppc_asm.tmpl"
+#include <asm/processor.h>
 
        .text
 
index 848fef6aef672c54dbcbef66fdc9aff80237a0d2..1beecacdb908b9a670464ff918864be21a8df6e8 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
+static char rcsid[] = "$Id: inflate.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $";
 #endif
 
 #include "gzip.h"
index 0b1638562a375a946000feb530f5ffade3793e20..a983ea106ee7e49f7b374302fd87a795c2c04ee5 100644 (file)
@@ -327,7 +327,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
   _put_MSR(_get_MSR() & ~0x0030);
 
   vga_init(0xC0000000);
-  clear_screen();
+  /*clear_screen();*/
 
   output_ptr = 0;
 
@@ -373,93 +373,6 @@ show_residual_data(RESIDUAL *res)
 #endif
 }
 
-#if 0
-verify_ram()
-{
-  unsigned long loc;
-  puts("Clearing memory:");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = 0x0;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != 0x0)
-      {
-       puts(" - failed at ");
-       puthex(loc);
-       puts(": ");
-       puthex(*(unsigned long *)loc);
-       while (1);
-      }
-  }
-  puts("0");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = 0xFFFFFFFF;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != 0xFFFFFFFF)
-      {
-       puts(" - failed at ");
-       puthex(loc);
-       puts(": ");
-       puthex(*(unsigned long *)loc);
-       while (1);
-      }
-  }
-  puts("1");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = loc;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != loc)
-      {
-       puts(" - failed at ");
-       puthex(loc);
-       puts(": ");
-       puthex(*(unsigned long *)loc);
-       while (1);
-      }
-  }
-  puts("?");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = 0xDEADB00B;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != 0xDEADB00B)
-      {
-       puts(" - failed at ");
-       puthex(loc);
-       puts(": ");
-       puthex(*(unsigned long *)loc);
-       while (1);
-      }
-  }
-  puts(">");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = 0x0;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != 0x0)
-      {
-       puts(" - failed at ");
-       puthex(loc);
-       puts(": ");
-       puthex(*(unsigned long *)loc);
-       while (1);
-      }
-  }
-  puts("\n");
-}
-
 do_cksum(unsigned long loc)
 {
   unsigned int ptr, cksum;
@@ -582,7 +495,6 @@ test_data(unsigned long load_addr)
   }
   return (errors == 0);
 }
-#endif
 
 void puthex(unsigned long val)
 {
diff --git a/arch/ppc/boot/mk_type41.c b/arch/ppc/boot/mk_type41.c
deleted file mode 100644 (file)
index 4e2a7b3..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * This program will make a type 0x41 load image from an
- * executable file.  Note:  assumes that the executable has
- * already been "flattened" by 'mkboot'.
- *
- * usage: mk_type41 flat-file image
- */
-
-#include <stdio.h>
-#include <errno.h>
-#ifdef linux
-#include <asm/stat.h>
-#else
-#include <sys/stat.h>
-#endif
-
-_LE(long val, unsigned char *le)
-{
-       le[0] = val;
-       le[1] = val >> 8;
-       le[2] = val >> 16;
-       le[3] = val >> 24;
-}
-
-main(int argc, char *argv[])
-{
-       int in_fd, out_fd, len, size;
-       struct stat info;
-       char buf[8192];
-       struct hdr
-       {
-               unsigned long entry_point;
-               unsigned long image_length;
-       } hdr;
-       if (argc != 3)
-       {
-               fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
-               exit(1);
-       }
-       if ((in_fd = open(argv[1], 0)) < 0)
-       {
-               fprintf(stderr, "Can't open input file: '%s': %s\n", argv[1], strerror(errno));
-               exit(2);
-       }
-       if ((out_fd = creat(argv[2], 0666)) < 0)
-       {
-               fprintf(stderr, "Can't create output file: '%s': %s\n", argv[2], strerror(errno));
-               exit(2);
-       }
-       if (fstat(in_fd, &info) < 0)
-       {
-               fprintf(stderr, "Can't get info on input file: %s\n", strerror(errno));
-               exit(4);
-       }
-       write_prep_boot_partition(out_fd);
-       _LE(0x400, &hdr.entry_point);
-       _LE(info.st_size+0x400, &hdr.image_length);
-       lseek(out_fd, 0x200, 0);
-       if (write(out_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
-       {
-               fprintf(stderr, "Can't write output file: %s\n", strerror(errno));
-               exit(5);
-       }
-       lseek(out_fd, 0x400, 0);
-       while ((len = read(in_fd, buf, sizeof(buf))) > 0)
-       {
-               if (write(out_fd, buf, len) != len)
-               {
-                       fprintf(stderr, "Can't write output file: %s\n", strerror(errno));
-                       exit(5);
-               }
-       }
-       if (len < 0)
-       {
-               fprintf(stderr, "Can't read input file: %s\n", strerror(errno));
-               exit(6);
-       }
-       close(in_fd);
-       close(out_fd);
-}
-
-/* Adapted from IBM Naked Application Package (NAP) */
-
-#define Align(value,boundary)                                          \
-       (((value) + (boundary) - 1) & ~((boundary) - 1))
-
-#define HiByte(word)           ((word_t)(word) >> 8)
-#define LoByte(word)           ((word_t)(word) & 0xFF)
-
-#define HiWord(dword)          ((dword_t)(dword) >> 16)
-#define LoWord(dword)          ((dword_t)(dword) & 0xFFFF)
-
-/*
- * Little-endian stuff
- */
-#define LeWord(word)                                                   \
-       (((word_t)(word) >> 8) | ((word_t)(word) << 8))
-
-#define LeDword(dword)                                                 \
-       (LeWord(LoWord(dword)) << 16) | LeWord(HiWord(dword))
-
-#define PcDword(dword)                                                 \
-       (LeWord(LoWord(dword)) << 16) | LeWord(HiWord(dword))
-
-
-typedef unsigned long dword_t;
-typedef unsigned short word_t;
-typedef unsigned char byte_t;
-typedef byte_t block_t[512];
-typedef byte_t page_t[4096];
-
-/*
- * Partition table entry
- *  - from the PReP spec
- */
-typedef struct partition_entry {
-    byte_t     boot_indicator;
-    byte_t     starting_head;
-    byte_t     starting_sector;
-    byte_t     starting_cylinder;
-
-    byte_t     system_indicator;
-    byte_t     ending_head;
-    byte_t     ending_sector;
-    byte_t     ending_cylinder;
-
-    dword_t    beginning_sector;
-    dword_t    number_of_sectors;
-} partition_entry_t;
-
-#define BootActive     0x80
-#define SystemPrep     0x41
-
-
-/*
- * Writes the "boot record", which contains the partition table, to the
- * diskette, followed by the dummy PC boot block and load image descriptor
- * block.  It returns the number of bytes it has written to the load
- * image.
- *
- * The boot record is the first block of the diskette and identifies the
- * "PReP" partition.  The "PReP" partition contains the "load image" starting
- * at offset zero within the partition.  The first block of the load image is
- * a dummy PC boot block.  The second block is the "load image descriptor"
- * which contains the size of the load image and the entry point into the
- * image.  The actual boot image starts at offset 1024 bytes (third sector)
- * in the partition.
- */
-void
-write_prep_boot_partition(int out_fd)
-{
-    block_t block;
-    partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
-    dword_t *entry  = (dword_t *)&block[0];
-    dword_t *length = (dword_t *)&block[4];
-
-    bzero( &block, sizeof block );
-
-    /*
-     * Magic marker
-     */
-    block[510] = 0x55;
-    block[511] = 0xAA;
-
-    /*
-     * Build a "PReP" partition table entry in the boot record
-     *  - "PReP" may only look at the system_indicator
-     */
-    pe->boot_indicator   = BootActive;
-    pe->system_indicator = SystemPrep;
-
-    /*
-     * The first block of the diskette is used by this "boot record" which
-     * actually contains the partition table. (The first block of the
-     * partition contains the boot image, but I digress...)  We'll set up
-     * one partition on the diskette and it shall contain the rest of the
-     * diskette.
-     */
-    pe->starting_head     = 0;         /* zero-based                        */
-    pe->starting_sector   = 2;         /* one-based                         */
-    pe->starting_cylinder = 0;         /* zero-based                        */
-
-    pe->ending_head       = 1;         /* assumes two heads                 */
-    pe->ending_sector     = 18;                /* assumes 18 sectors/track          */
-    pe->ending_cylinder   = 79;                /* assumes 80 cylinders/diskette     */
-
-    /*
-     * The "PReP" software ignores the above fields and just looks at
-     * the next two.
-     *   - size of the diskette is (assumed to be)
-     *     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
-     *   - unlike the above sector numbers, the beginning sector is zero-based!
-     */
-#if 0
-    pe->beginning_sector  = LeDword(1);
-#else
-    /* This has to be 0 on the PowerStack? */   
-    pe->beginning_sector  = LeDword(0);
-#endif    
-    pe->number_of_sectors = LeDword(2*18*80-1);
-
-    /*
-     * Write the partition table
-     */
-    lseek( out_fd, 0, 0 );
-    write( out_fd, block, sizeof block );
-}
-
index a79ad98f2e880cce18762578b3a806fba206dcc4..4173346703a5583eea904153abfd4a05679171ac 100644 (file)
@@ -1,19 +1,54 @@
 /*
- * This program will make a type 0x41 load image from an
- * executable file.  Note:  assumes that the executable has
- * already been "flattened" by 'mkboot'.
- *
- * usage: mk_type41 flat-file image
+ * Makes a prep bootable image which can be dd'd onto
+ * a disk device to make a bootdisk.  Will take
+ * as input a elf executable, strip off the header
+ * and write out a boot image as:
+ * 1) default - strips elf header
+ *      suitable as a network boot image
+ * 2) -pbp - strips elf header and writes out prep boot partition image
+ *      cat or dd onto disk for booting
+ * 3) -asm - strips elf header and writes out as asm data
+ *      useful for generating data for a compressed image
+ *                  -- Cort
  */
 
-#include <stdio.h>
-#include <errno.h>
 #ifdef linux
+#include <linux/types.h>
 #include <asm/stat.h>
+/*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */
 #else
+#include <unistd.h>
 #include <sys/stat.h>
 #endif
-#include <asm/byteorder.h> /* use same as kernel -- Cort */
+
+#include <stdio.h>
+#include <errno.h>
+
+#define cpu_to_le32(x) le32_to_cpu((x))
+unsigned long le32_to_cpu(unsigned long x)
+{
+       return (((x & 0x000000ffU) << 24) |
+               ((x & 0x0000ff00U) <<  8) |
+               ((x & 0x00ff0000U) >>  8) |
+               ((x & 0xff000000U) >> 24));
+}
+
+
+#define cpu_to_le16(x) le16_to_cpu((x))
+unsigned short le16_to_cpu(unsigned short x)
+{
+       return (((x & 0x00ff) << 8) |
+               ((x & 0xff00) >> 8));
+}
+
+#define cpu_to_be32(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_be16(x) (x)
+#define be16_to_cpu(x) (x)
+
+/* size of read buffer */
+#define SIZE 0x1000
+
 
 typedef unsigned long dword_t;
 typedef unsigned short word_t;
@@ -21,119 +56,239 @@ typedef unsigned char byte_t;
 typedef byte_t block_t[512];
 typedef byte_t page_t[4096];
 
-_LE(long val, unsigned char *le)
-{
-       le[0] = val;
-       le[1] = val >> 8;
-       le[2] = val >> 16;
-       le[3] = val >> 24;
-}
 
 /*
  * Partition table entry
  *  - from the PReP spec
  */
 typedef struct partition_entry {
-    byte_t     boot_indicator;
-    byte_t     starting_head;
-    byte_t     starting_sector;
-    byte_t     starting_cylinder;
-
-    byte_t     system_indicator;
-    byte_t     ending_head;
-    byte_t     ending_sector;
-    byte_t     ending_cylinder;
-
-    dword_t    beginning_sector;
-    dword_t    number_of_sectors;
+  byte_t       boot_indicator;
+  byte_t       starting_head;
+  byte_t       starting_sector;
+  byte_t       starting_cylinder;
+
+  byte_t       system_indicator;
+  byte_t       ending_head;
+  byte_t       ending_sector;
+  byte_t       ending_cylinder;
+
+  dword_t      beginning_sector;
+  dword_t      number_of_sectors;
 } partition_entry_t;
 
 #define BootActive     0x80
 #define SystemPrep     0x41
 
+void copy_image(int , int);
+void write_prep_partition(int , int );
+void write_asm_data( int in, int out );
+
+unsigned int elfhdr_size = 65536;
 
 int main(int argc, char *argv[])
 {
-  struct stat info;
-  char buf[8192];
-  int in_fd, out_fd,len;
+  int in_fd, out_fd;
+  int argptr = 1;
+  unsigned int prep = 0;
+  unsigned int asmoutput = 0;
+
+  if ( (argc < 3) || (argc > 4) )
+  {
+    fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",argv[0]);
+    exit(-1);
+  }
+
+  /* needs to handle args more elegantly -- but this is a small/simple program */
+  
+  /* check for -pbp */
+  if ( !strcmp( argv[argptr], "-pbp" ) )
+  {
+    prep = 1;
+    argptr++;
+  }
+  
+  /* check for -asm */
+  if ( !strcmp( argv[argptr], "-asm" ) )
+  {
+    asmoutput = 1;
+    argptr++;
+  }
+
+  /* input file */
+  if ( !strcmp( argv[argptr], "-" ) )
+    in_fd = 0;                 /* stdin */
+  else
+    if ((in_fd = open( argv[argptr] , 0)) < 0)
+      exit(-1);
+  argptr++;
+
+  /* output file */
+  if ( !strcmp( argv[argptr], "-" ) )
+    out_fd = 1;                        /* stdout */
+  else
+    if ((out_fd = creat( argv[argptr] , 0755)) < 0)
+      exit(-1);
+  argptr++;
+
+  /* skip elf header in input file */
+  lseek(in_fd, elfhdr_size, SEEK_SET);
+  
+  /* write prep partition if necessary */
+  if ( prep )
+    write_prep_partition( in_fd, out_fd );
+
+  /* write input image to bootimage */
+  if ( asmoutput )
+    write_asm_data( in_fd, out_fd );
+  else
+    copy_image(in_fd, out_fd);
+  
+  return 0;
+}
+
+void write_prep_partition(int in, int out)
+{
   unsigned char block[512];
   partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
-  dword_t *entry  = (dword_t *)&block[0x50];
-  dword_t *length = (dword_t *)&block[0x51];
+  dword_t *entry  = (dword_t *)&block[0];
+  dword_t *length = (dword_t *)&block[sizeof(long)];
+  struct stat info;
   
-  if (argc != 3)
-    {
-      fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
-      exit(1);
-    }
-  if ((in_fd = open(argv[1], 0)) < 0)
-    {
-      exit(2);
-    }
-  if ((out_fd = creat(argv[2], 0755)) < 0)
-    {
-      exit(2);
-    }
+  if (fstat(in, &info) < 0)
+  {
+    fprintf(stderr,"info failed\n");
+    exit(-1);
+  }
+  
+  bzero( block, sizeof block );
 
-  bzero( &block, sizeof block );
-    
+  /* set entry point and boot image size */
+  *entry = cpu_to_le32(0x400);
+  /* need use size - elfheader? */
+  *length = cpu_to_le32(info.st_size+0x400);
 
   /*
-   * Magic marker
+   * Writes the "boot record", which contains the partition table, to the
+   * diskette, followed by the dummy PC boot block and load image descriptor
+   * block.  It returns the number of bytes it has written to the load
+   * image.
+   *
+   * The boot record is the first block of the diskette and identifies the
+   * "PReP" partition.  The "PReP" partition contains the "load image" starting
+   * at offset zero within the partition.  The first block of the load image is
+   * a dummy PC boot block.  The second block is the "load image descriptor"
+   * which contains the size of the load image and the entry point into the
+   * image.  The actual boot image starts at offset 1024 bytes (third sector)
+   * in the partition.
    */
+  
+  /* sets magic number for msdos partition (used by linux) */
   block[510] = 0x55;
   block[511] = 0xAA;
   
+  /*
+   * Build a "PReP" partition table entry in the boot record
+   *  - "PReP" may only look at the system_indicator
+   */
   pe->boot_indicator   = BootActive;
   pe->system_indicator = SystemPrep;
-    pe->starting_head     = 0;         /* zero-based                        */
-    pe->starting_sector   = 2;         /* one-based                         */
-    pe->starting_cylinder = 0;         /* zero-based                        */
-
-    pe->ending_head       = 1;         /* assumes two heads                 */
-    pe->ending_sector     = 18;                /* assumes 18 sectors/track          */
-    pe->ending_cylinder   = 79;                /* assumes 80 cylinders/diskette     */
+  /*
+   * The first block of the diskette is used by this "boot record" which
+   * actually contains the partition table. (The first block of the
+   * partition contains the boot image, but I digress...)  We'll set up
+   * one partition on the diskette and it shall contain the rest of the
+   * diskette.
+   */
+  pe->starting_head     = 0;   /* zero-based                        */
+  pe->starting_sector   = 2;   /* one-based                         */
+  pe->starting_cylinder = 0;   /* zero-based                        */
+  pe->ending_head       = 1;   /* assumes two heads                 */
+  pe->ending_sector     = 18;  /* assumes 18 sectors/track          */
+  pe->ending_cylinder   = 79;  /* assumes 80 cylinders/diskette     */
 
+  /*
+   * The "PReP" software ignores the above fields and just looks at
+   * the next two.
+   *   - size of the diskette is (assumed to be)
+   *     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
+   *   - unlike the above sector numbers, the beginning sector is zero-based!
+   */
 #if 0
-#if 0    
-  pe->beginning_sector  = LeDword(1);
+  pe->beginning_sector  = cpu_to_le32(1);
 #else
-  /* This has to be 0 on the PowerStack? */
-  pe->beginning_sector  = LeDword(0);
-#endif
-  pe->number_of_sectors = LeDword(2*18*80-1);
-#endif
+  /* This has to be 0 on the PowerStack? */   
+  pe->beginning_sector  = cpu_to_le32(0);
+#endif    
+/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+
+  write( out, block, sizeof(block) );
+  write( out, entry, sizeof(*entry) );
+  write( out, length, sizeof(*length) );  
+  /* set file position to 2nd sector where image will be written */
+  lseek( out, 0x400, SEEK_SET );
+}
+
+
+
+void
+copy_image(int in, int out)
+{
+  char buf[SIZE];
+  int n;
+
+  while ( (n = read(in, buf, SIZE)) > 0 )
+    write(out, buf, n);
+}
+
+
+void
+write_asm_data( int in, int out )
+{
+  int i, cnt, pos, len;
+  unsigned int cksum, val;
+  unsigned char *lp;
+  unsigned char buf[SIZE];
+  unsigned char str[256];
   
-  if (fstat(in_fd, &info) < 0)
+  write( out, "\t.data\n\t.globl input_data\ninput_data:\n",
+        strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) );
+  pos = 0;
+  cksum = 0;
+  while ((len = read(in, buf, sizeof(buf))) > 0)
+  {
+    cnt = 0;
+    lp = (unsigned char *)buf;
+    len = (len + 3) & ~3;  /* Round up to longwords */
+    for (i = 0;  i < len;  i += 4)
     {
-      exit(4);
+      if (cnt == 0)
+      {
+       write( out, "\t.long\t", strlen( "\t.long\t" ) );
+      }
+      sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+      write( out, str, strlen(str) );
+      val = *(unsigned long *)lp;
+      cksum ^= val;
+      lp += 4;
+      if (++cnt == 4)
+      {
+       cnt = 0;
+       sprintf( str, " # %x \n", pos+i-12);
+       write( out, str, strlen(str) );
+      } else
+      {
+       write( out, ",", 1 );
+      }
     }
-  /* begin execution at 0x400 */
-  _LE(0x400,(unsigned char *)entry);
-  _LE(info.st_size+0x400,length);
-  
-  lseek( out_fd, 0, 0 );
-  /* write out 1st block */
-  write( out_fd, block, sizeof block );
-  
-  /* copy image */
-#if 1 
-       lseek(out_fd, 0x400, 0);
-       while ((len = read(in_fd, buf, sizeof(buf))) > 0)
-       {
-               if (write(out_fd, buf, len) != len)
-               {
-                       exit(5);
-               }
-       }
-       if (len < 0)
-       {
-               exit(6);
-       }
-       close(in_fd);
-       close(out_fd);
-#endif 
-  return 0;
-}
+    if (cnt)
+    {
+      write( out, "0\n", 2 );
+    }
+    pos += len;
+  }
+  sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
+  write( out, str, strlen(str) );
 
+  fprintf(stderr, "cksum = %x\n", cksum);
+}
diff --git a/arch/ppc/boot/piggyback.c b/arch/ppc/boot/piggyback.c
deleted file mode 100644 (file)
index ca9fc29..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#include <stdio.h>
-
-extern long ce_exec_config[];
-
-main(int argc, char *argv[])
-{
-       int i, cnt, pos, len;
-       unsigned int cksum, val;
-       unsigned char *lp;
-       unsigned char buf[8192];
-       if (argc != 1)
-       {
-               fprintf(stderr, "usage: %s <in-file >out-file\n", argv[0]);
-               exit(1);
-       }
-       fprintf(stdout, "#\n");
-       fprintf(stdout, "# Miscellaneous data structures:\n");
-       fprintf(stdout, "# WARNING - this file is automatically generated!\n");
-       fprintf(stdout, "#\n");
-       fprintf(stdout, "\n");
-       fprintf(stdout, "\t.data\n");
-       fprintf(stdout, "\t.globl input_data\n");
-       fprintf(stdout, "input_data:\n");
-       pos = 0;
-       cksum = 0;
-       while ((len = read(0, buf, sizeof(buf))) > 0)
-       {
-               cnt = 0;
-               lp = (unsigned char *)buf;
-               len = (len + 3) & ~3;  /* Round up to longwords */
-               for (i = 0;  i < len;  i += 4)
-               {
-                       if (cnt == 0)
-                       {
-                               fprintf(stdout, "\t.long\t");
-                       }
-                       fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
-                       val = *(unsigned long *)lp;
-                       cksum ^= val;
-                       lp += 4;
-                       if (++cnt == 4)
-                       {
-                               cnt = 0;
-                               fprintf(stdout, " # %x \n", pos+i-12);
-                               fflush(stdout);
-                       } else
-                       {
-                               fprintf(stdout, ",");
-                       }
-               }
-               if (cnt)
-               {
-                       fprintf(stdout, "0\n");
-               }
-               pos += len;
-       }
-       fprintf(stdout, "\t.globl input_len\n");
-       fprintf(stdout, "input_len:\t.long\t0x%x\n", pos);
-       fflush(stdout);
-       fclose(stdout);
-       fprintf(stderr, "cksum = %x\n", cksum);
-       exit(0);
-}
-
index 0c660adcf2600d766683235a0f6bf4ef7bc18310..fcebd9dd8de1326be300b26a22a58b542717b82c 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
+static char rcsid[] = "$Id: unzip.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $";
 #endif
 
 #include "gzip.h"
index 7da3670c803b5715df41f63d1da9b28cc8acc0b0..3bc3936c6e7b9df459c80d608efc4e1b26319804 100644 (file)
@@ -7,6 +7,864 @@
  *                                      Steve Sellgren
  *                                      San Francisco Indigo Company
  *                                      sfindigo!sellgren@uunet.uu.net
+ *
+ * Original concept by:
+ *                                      Gary Thomas <gdt@linuxppc.org>
+ * Adapted for Moto boxes by:
+ *                                      Pat Kane & Mark Scott, 1996
+ * Adapted for IBM portables by:
+ *                                      Takeshi Ishimoto
+ * Multi-console support:
+ *                                      Terje Malmedal <terje.malmedal@usit.uio.no>
+ */
+
+#include "iso_font.h"
+#include <linux/delay.h>
+
+extern char *vidmem;
+extern int lines, cols;
+/* estimate for delay */
+unsigned long loops_per_sec = 50000000;;
+/*
+ * VGA Register  
+ */
+struct VgaRegs
+{
+       unsigned short io_port;
+       unsigned char  io_index;
+       unsigned char  io_value;
+};
+
+/*
+ * Default console text mode registers  used to reset
+ * graphics adapter.
+ */
+#define NREGS 54
+#define ENDMK  0xFFFF  /* End marker */
+
+#define S3Vendor        0x5333
+#define CirrusVendor    0x1013
+#define DiamondVendor   0x100E
+#define MatroxVendor    0x102B
+#define ParadiseVendor  0x101C
+
+struct VgaRegs GenVgaTextRegs[NREGS+1] = {
+/*      port    index   value  */
+  /* SR Regs */
+        0x3c4,  0x1,    0x0,
+        0x3c4,  0x2,    0x3,
+        0x3c4,  0x3,    0x0,
+        0x3c4,  0x4,    0x2,
+   /* CR Regs */
+        0x3d4,  0x0,    0x5f,
+        0x3d4,  0x1,    0x4f,
+        0x3d4,  0x2,    0x50,
+        0x3d4,  0x3,    0x82,
+        0x3d4,  0x4,    0x55,
+        0x3d4,  0x5,    0x81,
+        0x3d4,  0x6,    0xbf,
+        0x3d4,  0x7,    0x1f,
+        0x3d4,  0x8,    0x00,
+        0x3d4,  0x9,    0x4f,
+        0x3d4,  0xa,    0x0d,
+        0x3d4,  0xb,    0x0e,
+        0x3d4,  0xc,    0x00,
+        0x3d4,  0xd,    0x00,
+        0x3d4,  0xe,    0x00,
+        0x3d4,  0xf,    0x00,
+        0x3d4,  0x10,   0x9c,
+        0x3d4,  0x11,   0x8e,
+        0x3d4,  0x12,   0x8f,
+        0x3d4,  0x13,   0x28,
+        0x3d4,  0x14,   0x1f,
+        0x3d4,  0x15,   0x96,
+        0x3d4,  0x16,   0xb9,
+        0x3d4,  0x17,   0xa3,
+   /* GR Regs */
+        0x3ce,  0x0,    0x0,
+        0x3ce,  0x1,    0x0,
+        0x3ce,  0x2,    0x0,
+        0x3ce,  0x3,    0x0,
+        0x3ce,  0x4,    0x0,
+        0x3ce,  0x5,    0x10,
+        0x3ce,  0x6,    0xe,
+        0x3ce,  0x7,    0x0,
+        0x3ce,  0x8,    0xff,
+        ENDMK
+};
+
+struct VgaRegs S3TextRegs[NREGS+1] = {
+/*     port    index   value  */
+  /* SR Regs */
+       0x3c4,  0x1,    0x0,
+       0x3c4,  0x2,    0x3,
+       0x3c4,  0x3,    0x0,
+       0x3c4,  0x4,    0x2,
+   /* CR Regs */
+       0x3d4,  0x0,    0x5f,
+       0x3d4,  0x1,    0x4f,
+       0x3d4,  0x2,    0x50,
+       0x3d4,  0x3,    0x82,
+       0x3d4,  0x4,    0x55,
+       0x3d4,  0x5,    0x81,
+       0x3d4,  0x6,    0xbf,
+       0x3d4,  0x7,    0x1f,
+       0x3d4,  0x8,    0x00,
+       0x3d4,  0x9,    0x4f,
+       0x3d4,  0xa,    0x0d,
+       0x3d4,  0xb,    0x0e,
+       0x3d4,  0xc,    0x00,
+       0x3d4,  0xd,    0x00,
+       0x3d4,  0xe,    0x00,
+       0x3d4,  0xf,    0x00,
+       0x3d4,  0x10,   0x9c,
+       0x3d4,  0x11,   0x8e,
+       0x3d4,  0x12,   0x8f,
+       0x3d4,  0x13,   0x28,
+       0x3d4,  0x14,   0x1f,
+       0x3d4,  0x15,   0x96,
+       0x3d4,  0x16,   0xb9,
+       0x3d4,  0x17,   0xa3,
+   /* GR Regs */
+       0x3ce,  0x0,    0x0,
+       0x3ce,  0x1,    0x0,
+       0x3ce,  0x2,    0x0,
+       0x3ce,  0x3,    0x0,
+       0x3ce,  0x4,    0x0,
+       0x3ce,  0x5,    0x10,
+       0x3ce,  0x6,    0xe,
+       0x3ce,  0x7,    0x0,
+       0x3ce,  0x8,    0xff,
+        ENDMK
+};
+
+struct RGBColors
+{
+  unsigned char r, g, b;
+};
+
+/*
+ * Default console text mode color table.
+ * These values were obtained by booting Linux with
+ * text mode firmware & then dumping the registers.  
+ */
+struct RGBColors TextCLUT[256] = 
+{
+  /*   red     green   blue  */
+       0x0,    0x0,    0x0,
+       0x0,    0x0,    0x2a,
+       0x0,    0x2a,   0x0,
+       0x0,    0x2a,   0x2a,
+       0x2a,   0x0,    0x0,
+       0x2a,   0x0,    0x2a,
+       0x2a,   0x2a,   0x0,
+       0x2a,   0x2a,   0x2a,
+       0x0,    0x0,    0x15,
+       0x0,    0x0,    0x3f,
+       0x0,    0x2a,   0x15,
+       0x0,    0x2a,   0x3f,
+       0x2a,   0x0,    0x15,
+       0x2a,   0x0,    0x3f,
+       0x2a,   0x2a,   0x15,
+       0x2a,   0x2a,   0x3f,
+       0x0,    0x15,   0x0,
+       0x0,    0x15,   0x2a,
+       0x0,    0x3f,   0x0,
+       0x0,    0x3f,   0x2a,
+       0x2a,   0x15,   0x0,
+       0x2a,   0x15,   0x2a,
+       0x2a,   0x3f,   0x0,
+       0x2a,   0x3f,   0x2a,
+       0x0,    0x15,   0x15,
+       0x0,    0x15,   0x3f,
+       0x0,    0x3f,   0x15,
+       0x0,    0x3f,   0x3f,
+       0x2a,   0x15,   0x15,
+       0x2a,   0x15,   0x3f,
+       0x2a,   0x3f,   0x15,
+       0x2a,   0x3f,   0x3f,
+       0x15,   0x0,    0x0,
+       0x15,   0x0,    0x2a,
+       0x15,   0x2a,   0x0,
+       0x15,   0x2a,   0x2a,
+       0x3f,   0x0,    0x0,
+       0x3f,   0x0,    0x2a,
+       0x3f,   0x2a,   0x0,
+       0x3f,   0x2a,   0x2a,
+       0x15,   0x0,    0x15,
+       0x15,   0x0,    0x3f,
+       0x15,   0x2a,   0x15,
+       0x15,   0x2a,   0x3f,
+       0x3f,   0x0,    0x15,
+       0x3f,   0x0,    0x3f,
+       0x3f,   0x2a,   0x15,
+       0x3f,   0x2a,   0x3f,
+       0x15,   0x15,   0x0,
+       0x15,   0x15,   0x2a,
+       0x15,   0x3f,   0x0,
+       0x15,   0x3f,   0x2a,
+       0x3f,   0x15,   0x0,
+       0x3f,   0x15,   0x2a,
+       0x3f,   0x3f,   0x0,
+       0x3f,   0x3f,   0x2a,
+       0x15,   0x15,   0x15,
+       0x15,   0x15,   0x3f,
+       0x15,   0x3f,   0x15,
+       0x15,   0x3f,   0x3f,
+       0x3f,   0x15,   0x15,
+       0x3f,   0x15,   0x3f,
+       0x3f,   0x3f,   0x15,
+       0x3f,   0x3f,   0x3f,
+       0x39,   0xc,    0x5,
+       0x15,   0x2c,   0xf,
+       0x26,   0x10,   0x3d,
+       0x29,   0x29,   0x38,
+       0x4,    0x1a,   0xe,
+       0x2,    0x1e,   0x3a,
+       0x3c,   0x25,   0x33,
+       0x3c,   0xc,    0x2c,
+       0x3f,   0x3,    0x2b,
+       0x1c,   0x9,    0x13,
+       0x25,   0x2a,   0x35,
+       0x1e,   0xa,    0x38,
+       0x24,   0x8,    0x3,
+       0x3,    0xe,    0x36,
+       0xc,    0x6,    0x2a,
+       0x26,   0x3,    0x32,
+       0x5,    0x2f,   0x33,
+       0x3c,   0x35,   0x2f,
+       0x2d,   0x26,   0x3e,
+       0xd,    0xa,    0x10,
+       0x25,   0x3c,   0x11,
+       0xd,    0x4,    0x2e,
+       0x5,    0x19,   0x3e,
+       0xc,    0x13,   0x34,
+       0x2b,   0x6,    0x24,
+       0x4,    0x3,    0xd,
+       0x2f,   0x3c,   0xc,
+       0x2a,   0x37,   0x1f,
+       0xf,    0x12,   0x38,
+       0x38,   0xe,    0x2a,
+       0x12,   0x2f,   0x19,
+       0x29,   0x2e,   0x31,
+       0x25,   0x13,   0x3e,
+       0x33,   0x3e,   0x33,
+       0x1d,   0x2c,   0x25,
+       0x15,   0x15,   0x5,
+       0x32,   0x25,   0x39,
+       0x1a,   0x7,    0x1f,
+       0x13,   0xe,    0x1d,
+       0x36,   0x17,   0x34,
+       0xf,    0x15,   0x23,
+       0x2,    0x35,   0xd,
+       0x15,   0x3f,   0xc,
+       0x14,   0x2f,   0xf,
+       0x19,   0x21,   0x3e,
+       0x27,   0x11,   0x2f,
+       0x38,   0x3f,   0x3c,
+       0x36,   0x2d,   0x15,
+       0x16,   0x17,   0x2,
+       0x1,    0xa,    0x3d,
+       0x1b,   0x11,   0x3f,
+       0x21,   0x3c,   0xd,
+       0x1a,   0x39,   0x3d,
+       0x8,    0xe,    0xe,
+       0x22,   0x21,   0x23,
+       0x1e,   0x30,   0x5,
+       0x1f,   0x22,   0x3d,
+       0x1e,   0x2f,   0xa,
+       0x0,    0x1c,   0xe,
+       0x0,    0x1c,   0x15,
+       0x0,    0x1c,   0x1c,
+       0x0,    0x15,   0x1c,
+       0x0,    0xe,    0x1c,
+       0x0,    0x7,    0x1c,
+       0xe,    0xe,    0x1c,
+       0x11,   0xe,    0x1c,
+       0x15,   0xe,    0x1c,
+       0x18,   0xe,    0x1c,
+       0x1c,   0xe,    0x1c,
+       0x1c,   0xe,    0x18,
+       0x1c,   0xe,    0x15,
+       0x1c,   0xe,    0x11,
+       0x1c,   0xe,    0xe,
+       0x1c,   0x11,   0xe,
+       0x1c,   0x15,   0xe,
+       0x1c,   0x18,   0xe,
+       0x1c,   0x1c,   0xe,
+       0x18,   0x1c,   0xe,
+       0x15,   0x1c,   0xe,
+       0x11,   0x1c,   0xe,
+       0xe,    0x1c,   0xe,
+       0xe,    0x1c,   0x11,
+       0xe,    0x1c,   0x15,
+       0xe,    0x1c,   0x18,
+       0xe,    0x1c,   0x1c,
+       0xe,    0x18,   0x1c,
+       0xe,    0x15,   0x1c,
+       0xe,    0x11,   0x1c,
+       0x14,   0x14,   0x1c,
+       0x16,   0x14,   0x1c,
+       0x18,   0x14,   0x1c,
+       0x1a,   0x14,   0x1c,
+       0x1c,   0x14,   0x1c,
+       0x1c,   0x14,   0x1a,
+       0x1c,   0x14,   0x18,
+       0x1c,   0x14,   0x16,
+       0x1c,   0x14,   0x14,
+       0x1c,   0x16,   0x14,
+       0x1c,   0x18,   0x14,
+       0x1c,   0x1a,   0x14,
+       0x1c,   0x1c,   0x14,
+       0x1a,   0x1c,   0x14,
+       0x18,   0x1c,   0x14,
+       0x16,   0x1c,   0x14,
+       0x14,   0x1c,   0x14,
+       0x14,   0x1c,   0x16,
+       0x14,   0x1c,   0x18,
+       0x14,   0x1c,   0x1a,
+       0x14,   0x1c,   0x1c,
+       0x14,   0x1a,   0x1c,
+       0x14,   0x18,   0x1c,
+       0x14,   0x16,   0x1c,
+       0x0,    0x0,    0x10,
+       0x4,    0x0,    0x10,
+       0x8,    0x0,    0x10,
+       0xc,    0x0,    0x10,
+       0x10,   0x0,    0x10,
+       0x10,   0x0,    0xc,
+       0x10,   0x0,    0x8,
+       0x10,   0x0,    0x4,
+       0x10,   0x0,    0x0,
+       0x10,   0x4,    0x0,
+       0x10,   0x8,    0x0,
+       0x10,   0xc,    0x0,
+       0x10,   0x10,   0x0,
+       0xc,    0x10,   0x0,
+       0x8,    0x10,   0x0,
+       0x4,    0x10,   0x0,
+       0x0,    0x10,   0x0,
+       0x0,    0x10,   0x4,
+       0x0,    0x10,   0x8,
+       0x0,    0x10,   0xc,
+       0x0,    0x10,   0x10,
+       0x0,    0xc,    0x10,
+       0x0,    0x8,    0x10,
+       0x0,    0x4,    0x10,
+       0x8,    0x8,    0x10,
+       0xa,    0x8,    0x10,
+       0xc,    0x8,    0x10,
+       0xe,    0x8,    0x10,
+       0x10,   0x8,    0x10,
+       0x10,   0x8,    0xe,
+       0x10,   0x8,    0xc,
+       0x10,   0x8,    0xa,
+       0x10,   0x8,    0x8,
+       0x10,   0xa,    0x8,
+       0x10,   0xc,    0x8,
+       0x10,   0xe,    0x8,
+       0x10,   0x10,   0x8,
+       0xe,    0x10,   0x8,
+       0xc,    0x10,   0x8,
+       0xa,    0x10,   0x8,
+       0x8,    0x10,   0x8,
+       0x8,    0x10,   0xa,
+       0x8,    0x10,   0xc,
+       0x8,    0x10,   0xe,
+       0x8,    0x10,   0x10,
+       0x8,    0xe,    0x10,
+       0x8,    0xc,    0x10,
+       0x8,    0xa,    0x10,
+       0xb,    0xb,    0x10,
+       0xc,    0xb,    0x10,
+       0xd,    0xb,    0x10,
+       0xf,    0xb,    0x10,
+       0x10,   0xb,    0x10,
+       0x10,   0xb,    0xf,
+       0x10,   0xb,    0xd,
+       0x10,   0xb,    0xc,
+       0x10,   0xb,    0xb,
+       0x10,   0xc,    0xb,
+       0x10,   0xd,    0xb,
+       0x10,   0xf,    0xb,
+       0x10,   0x10,   0xb,
+       0xf,    0x10,   0xb,
+       0xd,    0x10,   0xb,
+       0xc,    0x10,   0xb,
+       0xb,    0x10,   0xb,
+       0xb,    0x10,   0xc,
+       0xb,    0x10,   0xd,
+       0xb,    0x10,   0xf,
+       0xb,    0x10,   0x10,
+       0xb,    0xf,    0x10,
+       0xb,    0xd,    0x10,
+       0xb,    0xc,    0x10,
+       0x0,    0x0,    0x0,
+       0x0,    0x0,    0x0,
+       0x0,    0x0,    0x0,
+       0x0,    0x0,    0x0,
+       0x0,    0x0,    0x0,
+       0x0,    0x0,    0x0,
+       0x0,    0x0,    0x0
+};
+
+unsigned char AC[21] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 
+    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+    0x0C, 0x00, 0x0F, 0x08, 0x00};
+
+static int scanPCI(int start_slt);
+static int PCIVendor(int);
+static void printslots(void);
+int delayLoop(int);
+extern void puthex(unsigned long);
+extern void puts(const char *);
+static void unlockS3(void);
+
+static inline
+outw(int port, unsigned short val)
+{
+       outb(port, val >> 8);
+       outb(port+1, val);
+}
+#define PPC_601 1
+
+vga_init(unsigned char *ISA_mem)
+{
+       int slot;
+       struct VgaRegs *VgaTextRegs;
+
+       if ((_get_PVR()>>16) == PPC_601) {
+               return(old_vga_init(ISA_mem));
+       }
+
+#if 1
+       /* See if VGA already in TEXT mode - exit if so! */
+       outb(0x3CE, 0x06);
+       if ((inb(0x3CF) & 0x01) == 0){puts("VGA already in text mode\n"); return;}
+#endif
+
+       /* If no VGA responding in text mode, then we have some work to do...
+        */
+       slot = -1;
+       while((slot = scanPCI(slot)) > -1) { /* find video card in use  */
+               unlockVideo(slot);           /* enable I/O to card      */
+               VgaTextRegs = GenVgaTextRegs;
+       
+               switch (PCIVendor(slot)) {
+               default:
+                       break;
+               case(S3Vendor):
+                       unlockS3();
+                       VgaTextRegs = S3TextRegs;
+                       break;
+       
+               case(CirrusVendor):
+                       outw(0x3C4, 0x0612);       /* unlock ext regs */
+                       outw(0x3C4, 0x0700);       /* reset ext sequence mode */
+                       break;
+       
+               case(ParadiseVendor):                 /* IBM Portable 850 */
+                       outw(0x3ce, 0x0f05);      /* unlock pardise registers */
+                       outw(0x3c4, 0x0648);
+                       outw(0x3d4, 0x2985);
+                       outw(0x3d4, 0x34a6);
+                       outb(0x3ce, 0x0b);       /* disable linear addressing */
+                       outb(0x3cf, inb(0x3cf) & ~0x30);
+                       outw(0x3c4, 0x1400);
+                       outb(0x3ce, 0x0e);       /* disable 256 color mode */
+                       outb(0x3cf, inb(0x3cf) & ~0x01);
+                       outb(0xd00, 0xff);       /* enable auto-centering */
+                       if (!(inb(0xd01) & 0x03)) {
+                               outb(0x3d4, 0x33);
+                               outb(0x3d5, inb(0x3d5) & ~0x90);
+                               outb(0x3d4, 0x32);
+                               outb(0x3d5, inb(0x3d5) | 0x04);
+                               outw(0x3d4, 0x0250);
+                               outw(0x3d4, 0x07ba);
+                               outw(0x3d4, 0x0900);
+                               outw(0x3d4, 0x15e7);
+                               outw(0x3d4, 0x2a95);
+                       }
+                       outw(0x3d4, 0x34a0);
+                       break;
+       
+       #if 0 /* Untested - probably doesn't work */
+               case(MatroxVendor):
+               case(DiamondVendor):
+                       puts("VGA Chip Vendor ID: ");
+                       puthex(PCIVendor(slot));
+                       puts("\n");
+                       delayLoop(1);
+       #endif
+               };
+       
+               outw(0x3C4, 0x0120);           /* disable video              */
+               setTextRegs(VgaTextRegs);      /* initial register setup     */
+               setTextCLUT(0);                /* load color lookup table    */
+               loadFont(ISA_mem);             /* load font                  */
+               setTextRegs(VgaTextRegs);      /* reload registers           */
+               outw(0x3C4, 0x0100);           /* re-enable video            */
+               clearVideoMemory();
+       
+               if (PCIVendor(slot) == S3Vendor) {
+                       outb(0x3c2, 0x63);                  /* MISC */
+               } /* endif */
+       
+       #ifdef DEBUG
+               printslots();
+               delayLoop(5);   
+       #endif
+       
+               delayLoop(1);   /* give time for the video monitor to come up */
+        }
+       return (1);  /* 'CRT' I/O supported */
+}
+
+static int
+NOP(int x)
+{
+}
+
+/*
+ * Write to VGA Attribute registers.  
+ */
+writeAttr(index, data, videoOn)
+     unsigned char index;
+     unsigned char data;
+     unsigned char videoOn;   /* video on flag */
+{
+       unsigned char v;
+       v = inb(0x3da);   /* reset attr. address toggle */
+       if (videoOn)
+               outb(0x3c0, (index & 0x1F) | 0x20);
+       else
+               outb(0x3c0, (index & 0x1F));
+       outb(0x3c0, data);
+}
+
+setTextRegs(struct VgaRegs *svp)
+{
+       int i;
+
+       /*
+        *  saved settings
+        */ 
+       while( svp->io_port != ENDMK ) {
+               outb(svp->io_port,   svp->io_index);
+               outb(svp->io_port+1, svp->io_value);
+               svp++; 
+       }
+
+       outb(0x3c2, 0x67);  /* MISC */
+       outb(0x3c6, 0xff);  /* MASK */
+
+       for ( i = 0; i < 0x10; i++)
+               writeAttr(i, AC[i], 0);  /* pallete */ 
+       writeAttr(0x10, 0x0c, 0);    /* text mode */
+       writeAttr(0x11, 0x00, 0);    /* overscan color (border) */
+       writeAttr(0x12, 0x0f, 0);    /* plane enable */
+       writeAttr(0x13, 0x08, 0);    /* pixel panning */
+       writeAttr(0x14, 0x00, 1);    /* color select; video on  */
+}
+
+setTextCLUT(int shift)
+{
+       int i;
+
+       outb(0x3C6, 0xFF); 
+       i = inb(0x3C7);
+       outb(0x3C8, 0); 
+       i = inb(0x3C7);
+
+       for ( i = 0; i < 256; i++) {
+               outb(0x3C9, TextCLUT[i].r << shift);
+               outb(0x3C9, TextCLUT[i].g << shift);
+               outb(0x3C9, TextCLUT[i].b << shift);
+       }
+}
+
+
+loadFont(unsigned char *ISA_mem)
+{
+       int i, j;
+       unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+    
+       outb(0x3C2, 0x67);
+       /* 
+        * Load font 
+        */
+       i = inb(0x3DA);  /* Reset Attr toggle */
+
+       outb(0x3C0,0x30); 
+       outb(0x3C0, 0x01);      /* graphics mode */
+
+       outw(0x3C4, 0x0001);    /* reset sequencer */
+       outw(0x3C4, 0x0204);    /* write to plane 2 */
+       outw(0x3C4, 0x0406);    /* enable plane graphics */
+       outw(0x3C4, 0x0003);    /* reset sequencer */
+       outw(0x3CE, 0x0402);    /* read plane 2 */
+       outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
+       outw(0x3CE, 0x0605);    /* set graphics mode */
+
+       for (i = 0;  i < sizeof(font);  i += 16) {
+               for (j = 0;  j < 16;  j++) {
+                       __asm__ volatile("eieio");
+                       font_page[(2*i)+j] = font[i+j];
+               }
+       }
+}
+
+static void
+unlockS3(void)
+{
+        int s3_device_id;
+       outw(0x3d4, 0x3848);
+       outw(0x3d4, 0x39a5);
+       outb(0x3d4, 0x2d);
+       s3_device_id = inb(0x3d5) << 8;
+       outb(0x3d4, 0x2e);
+       s3_device_id |= inb(0x3d5);
+
+       if (s3_device_id != 0x8812) {
+               /* From the S3 manual */
+               outb(0x46E8, 0x10);  /* Put into setup mode */
+               outb(0x3C3, 0x10);
+               outb(0x102, 0x01);   /* Enable registers */
+               outb(0x46E8, 0x08);  /* Enable video */
+               outb(0x3C3, 0x08);
+               outb(0x4AE8, 0x00);
+
+#if 0
+               outb(0x42E8, 0x80);  /* Reset graphics engine? */
+#endif
+
+               outb(0x3D4, 0x38);  /* Unlock all registers */
+               outb(0x3D5, 0x48);
+               outb(0x3D4, 0x39);
+               outb(0x3D5, 0xA5);
+               outb(0x3D4, 0x40);
+               outb(0x3D5, inb(0x3D5)|0x01);
+               outb(0x3D4, 0x33);
+               outb(0x3D5, inb(0x3D5)&~0x52);
+               outb(0x3D4, 0x35);
+               outb(0x3D5, inb(0x3D5)&~0x30);
+               outb(0x3D4, 0x3A);
+               outb(0x3D5, 0x00);
+               outb(0x3D4, 0x53);
+               outb(0x3D5, 0x00);
+               outb(0x3D4, 0x31);
+               outb(0x3D5, inb(0x3D5)&~0x4B);
+               outb(0x3D4, 0x58);
+
+               outb(0x3D5, 0);
+
+               outb(0x3D4, 0x54);
+               outb(0x3D5, 0x38);
+               outb(0x3D4, 0x60);
+               outb(0x3D5, 0x07);
+               outb(0x3D4, 0x61);
+               outb(0x3D5, 0x80);
+               outb(0x3D4, 0x62);
+               outb(0x3D5, 0xA1);
+               outb(0x3D4, 0x69);  /* High order bits for cursor address */
+               outb(0x3D5, 0);
+
+               outb(0x3D4, 0x32);
+               outb(0x3D5, inb(0x3D5)&~0x10);
+       } else {
+                outw(0x3c4, 0x0806);            /* IBM Portable 860 */
+                outw(0x3c4, 0x1041);
+                outw(0x3c4, 0x1128);
+                outw(0x3d4, 0x4000);
+                outw(0x3d4, 0x3100);
+                outw(0x3d4, 0x3a05);
+                outw(0x3d4, 0x6688);
+                outw(0x3d4, 0x5800);            /* disable linear addressing */
+                outw(0x3d4, 0x4500);            /* disable H/W cursor */
+                outw(0x3c4, 0x5410);            /* enable auto-centering */
+                outw(0x3c4, 0x561f);
+                outw(0x3c4, 0x1b80);            /* lock DCLK selection */
+                outw(0x3d4, 0x3900);            /* lock S3 registers */
+                outw(0x3d4, 0x3800);
+       } /* endif */
+}
+
+/*
+ * cursor() sets an offset (0-1999) into the 80x25 text area   
+ */
+void
+cursor(int x, int y)
+{
+       int pos = (y*cols)+x;
+       outb(0x3D4, 14);
+       outb(0x3D5, pos >> 8);
+       outb(0x3D4, 15);
+       outb(0x3D5, pos);
+}
+
+clearVideoMemory()
+{
+       int i, j;
+       for (i = 0;  i < lines;  i++) {
+               for (j = 0;  j < cols;  j++) {
+                       vidmem[((i*cols)+j)*2] = 0x20;  /* fill with space character */
+                       vidmem[((i*cols)+j)*2+1] = 0x07;  /* set bg & fg attributes */
+               }
+       }
+}
+
+/* ============ */
+
+
+#define NSLOTS 8
+#define NPCIREGS  5
+
+
+/* 
+ should use devfunc number/indirect method to be totally safe on 
+ all machines, this works for now on 3 slot Moto boxes 
+*/
+
+struct PCI_ConfigInfo {
+  unsigned long * config_addr;
+  unsigned long regs[NPCIREGS];  
+} PCI_slots [NSLOTS] = {
+
+    { (unsigned long *)0x80808000, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80800800, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80801000, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80802000, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80804000, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80810000, 0xDEADBEEF },   /* slot A/1 */
+    { (unsigned long *)0x80820000, 0xDEADBEEF },   /* slot B/2 */
+    { (unsigned long *)0x80840000, 0xDEADBEEF }    /* slot C/3 */
+};
+
+
+
+/*
+ * The following code modifies the PCI Command register
+ * to enable memory and I/O accesses.    
+ */ 
+unlockVideo(slot)        
+{
+       volatile unsigned char * ppci;
+
+        ppci =  (unsigned char * )PCI_slots[slot].config_addr;
+       ppci[4] = 0x0003;         /* enable memory and I/O accesses */
+       ppci[0x10] = 0x00000;     /* turn off memory mapping */
+       ppci[0x11] = 0x00000;     /* mem_base = 0 */
+       ppci[0x12] = 0x00000;
+       ppci[0x13] = 0x00000;
+       __asm__ volatile("eieio");
+
+       outb(0x3d4, 0x11);
+       outb(0x3d5, 0x0e);   /* unlock CR0-CR7 */
+}
+
+long
+SwapBytes(long lv)   /* turn little endian into big indian long */
+{
+    long t;
+    t  = (lv&0x000000FF) << 24;
+    t |= (lv&0x0000FF00) << 8;
+    t |= (lv&0x00FF0000) >> 8;
+    t |= (lv&0xFF000000) >> 24;
+    return(t);
+}
+
+
+#define DEVID   0
+#define CMD     1
+#define CLASS   2
+#define MEMBASE 4
+
+int
+scanPCI(int start_slt)
+{
+       int slt, r;
+       struct PCI_ConfigInfo *pslot;
+       int theSlot = -1;
+       int highVgaSlot = 0;
+
+       for ( slt = start_slt + 1; slt < NSLOTS; slt++) {
+               pslot = &PCI_slots[slt];
+               for ( r = 0; r < NPCIREGS; r++) {
+                       pslot->regs[r] = SwapBytes ( pslot->config_addr[r] );
+               }
+               /* card in slot ? */
+               if ( pslot->regs[DEVID] != 0xFFFFFFFF ) {     
+                       /* VGA ? */
+                       if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || 
+                            ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) {
+                               highVgaSlot = slt;
+                               /* did firmware enable it ? */
+                               if ( (pslot->regs[CMD] & 0x03) ) { 
+                                       theSlot = slt;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return ( theSlot );
+}
+
+/* Delay for a certain number of seconds */
+/* Note: They loop is used since 'udelay' can't handle really long counts! */
+
+int
+delayLoop(int k)
+{
+       int i;
+       while (k-- > 0) {
+               for (i = 0;  i < 1000;  i++) {
+                       udelay(1000);
+               }
+       }
+}
+
+
+/* return Vendor ID of card in the slot */
+static
+int PCIVendor(int slotnum) {
+ struct PCI_ConfigInfo *pslot;
+
+ pslot = &PCI_slots[slotnum];
+
+return (pslot->regs[DEVID] & 0xFFFF);
+}
+
+static
+void printslots(void) 
+{
+       int i;
+       struct PCI_ConfigInfo *pslot;
+       for(i=0; i < NSLOTS; i++) {
+#if 0
+               pslot = &PCI_slots[i];
+               printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n",
+                      i, pslot->config_addr, pslot->regs[0], pslot->regs[2]);
+#else
+               puts("PCI Slot number: "); puthex(i);
+               puts(" Vendor ID: "); 
+               puthex(PCIVendor(i)); puts("\n");
+#endif
+
+       }
+}
+
+/*
+ * OLD vreset.c
+ *
+ * Initialize the VGA control registers to 80x25 text mode.
+ *
+ * Adapted from a program by:
+ *                                      Steve Sellgren
+ *                                      San Francisco Indigo Company
+ *                                      sfindigo!sellgren@uunet.uu.net
  */
  
 unsigned char CRTC[24] = {
@@ -15,13 +873,8 @@ unsigned char CRTC[24] = {
     0x9C, 0xAE, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3};
 unsigned char SEQ[5] = {0x3, 0x0, 0x3, 0x0, 0x2};
 unsigned char GC[9] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0xE, 0x0, 0xFF};
-unsigned char AC[21] = {
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 
-    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
-    0x0C, 0x00, 0x0F, 0x08, 0x00};
-
-#include "iso_font.h"
 
+#if 0
 static const unsigned char color_LUT[] =
    {
        0x00, 0x00, 0x00, /* 0 - black */
@@ -41,124 +894,124 @@ static const unsigned char color_LUT[] =
        0x2A, 0x2A, 0x15, /* 14 - yellow */
        0x2A, 0x2A, 0x3F, /* 15 - bright white */
    };
-
-static inline
-outw(int port, unsigned short val)
-{
-       outb(port, val >> 8);
-       outb(port+1, val);
-}
+#endif
  
-vga_init(unsigned char *ISA_mem)
+old_vga_init(unsigned char *ISA_mem)
 {
-  int i, j;
-  int value;
-  unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+       int i, j;
+       int value;
+       unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
 
-  /* See if VGA already in TEXT mode - exit if so! */
-  outb(0x3CE, 0x06);
-  if ((inb(0x3CF) & 0x01) == 0) return;
+       /* See if VGA already in TEXT mode - exit if so! */
+       outb(0x3CE, 0x06);
+       if ((inb(0x3CF) & 0x01) == 0) return;
     
-  /* From the S3 manual */
-  outb(0x46E8, 0x10);  /* Put into setup mode */
-  outb(0x3C3, 0x10);
-  outb(0x102, 0x01);   /* Enable registers */
-  outb(0x46E8, 0x08);  /* Enable video */
-  outb(0x3C3, 0x08);
-  outb(0x4AE8, 0x00);
-
-  outb(0x42E8, 0x80);  /* Reset graphics engine? */
-
-  outb(0x3D4, 0x38);  /* Unlock all registers */
-  outb(0x3D5, 0x48);
-  outb(0x3D4, 0x39);
-  outb(0x3D5, 0xA5);
-  outb(0x3D4, 0x40);
-  outb(0x3D5, inb(0x3D5)|0x01);
-  outb(0x3D4, 0x33);
-  outb(0x3D5, inb(0x3D5)&~0x52);
-  outb(0x3D4, 0x35);
-  outb(0x3D5, inb(0x3D5)&~0x30);
-  outb(0x3D4, 0x3A);
-  outb(0x3D5, 0x00);
-  outb(0x3D4, 0x53);
-  outb(0x3D5, 0x00);
-  outb(0x3D4, 0x31);
-  outb(0x3D5, inb(0x3D5)&~0x4B);
-  outb(0x3D4, 0x58);
-  outb(0x3D5, 0);
-
-  outb(0x3D4, 0x54);
-  outb(0x3D5, 0x38);
-  outb(0x3D4, 0x60);
-  outb(0x3D5, 0x07);
-  outb(0x3D4, 0x61);
-  outb(0x3D5, 0x80);
-  outb(0x3D4, 0x62);
-  outb(0x3D5, 0xA1);
-  outb(0x3D4, 0x69);  /* High order bits for cursor address */
-  outb(0x3D5, 0);
+       /* From the S3 manual */
+       outb(0x46E8, 0x10);  /* Put into setup mode */
+       outb(0x3C3, 0x10);
+       outb(0x102, 0x01);   /* Enable registers */
+       outb(0x46E8, 0x08);  /* Enable video */
+       outb(0x3C3, 0x08);
+       outb(0x4AE8, 0x00);
+
+#if 0
+       outb(0x42E8, 0x80);  /* Reset graphics engine? */
+#endif
+
+       outb(0x3D4, 0x38);  /* Unlock all registers */
+       outb(0x3D5, 0x48);
+       outb(0x3D4, 0x39);
+       outb(0x3D5, 0xA5);
+       outb(0x3D4, 0x40);
+       outb(0x3D5, inb(0x3D5)|0x01);
+       outb(0x3D4, 0x33);
+       outb(0x3D5, inb(0x3D5)&~0x52);
+       outb(0x3D4, 0x35);
+       outb(0x3D5, inb(0x3D5)&~0x30);
+       outb(0x3D4, 0x3A);
+       outb(0x3D5, 0x00);
+       outb(0x3D4, 0x53);
+       outb(0x3D5, 0x00);
+       outb(0x3D4, 0x31);
+       outb(0x3D5, inb(0x3D5)&~0x4B);
+       outb(0x3D4, 0x58);
+       outb(0x3D5, 0);
+
+       outb(0x3D4, 0x54);
+       outb(0x3D5, 0x38);
+       outb(0x3D4, 0x60);
+       outb(0x3D5, 0x07);
+       outb(0x3D4, 0x61);
+       outb(0x3D5, 0x80);
+       outb(0x3D4, 0x62);
+       outb(0x3D5, 0xA1);
+       outb(0x3D4, 0x69);  /* High order bits for cursor address */
+       outb(0x3D5, 0);
   
-  outb(0x3D4, 0x32);
-  outb(0x3D5, inb(0x3D5)&~0x10);
-
-  outb(0x3C2, 0x67);
-
-  /* Initialize DAC */
-  outb(0x3C6,0xFF);
-  inb(0x3C7);
-  outb(0x3C8,0x00);
-  inb(0x3C7);
-  for (i=0; i<sizeof(color_LUT); i++) {
-    outb(0x3C9, color_LUT[i]);
-  }
-  for (i; i<768; i += 3) {
-    outb(0x3C9, 0x3F); /* White? */
-    outb(0x3C9, 0x3F); /* White? */
-    outb(0x3C9, 0x3F); /* White? */
-  }
-
-  /* Load font */
-  NOP(inb(0x3DA));  /* Reset Address/Data FlipFlop for Attribute ctlr */
-  outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
-  outw(0x3C4, 0x0001);    /* reset sequencer */
-  outw(0x3C4, 0x0204);    /* write to plane 2 */
-  outw(0x3C4, 0x0407);    /* enable plane graphics */
-  outw(0x3C4, 0x0003);    /* reset sequencer */
-  outw(0x3CE, 0x0402);    /* read plane 2 */
-  outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
-  outw(0x3CE, 0x0600);    /* set graphics */
-  for (i = 0;  i < sizeof(font);  i += 16) {
-    for (j = 0;  j < 16;  j++) {
-      font_page[(2*i)+j] = font[i+j];
-    }
-  }
-
-  for (i = 0; i < 24; i++) {
-    outb(0x3D4, i);
-    outb(0x3D5, CRTC[i]);
-  }
-  for (i = 0; i < 5; i++) {
-    outb(0x3C4, i);
-    outb(0x3C5, SEQ[i]);
-  }
-  for (i = 0; i < 9; i++) {
-    outb(0x3CE, i);
-    outb(0x3CF, GC[i]);
-  }
-  value = inb(0x3DA);         /* reset flip-flop */
-  for (i = 0; i < 16; i++) {
-    outb(0x3C0, i);
-    outb(0x3C0, AC[i]);
-  }
-  for (i = 16; i < 21; i++) {
-    outb(0x3C0, i | 0x20);
-    outb(0x3C0, AC[i]);
-  }
-  outb(0x3C2, 0x23);
-}
+       outb(0x3D4, 0x32);
+       outb(0x3D5, inb(0x3D5)&~0x10);
 
-static int
-NOP(int x)
-{
+       outb(0x3C2, 0x67);
+
+#if 0
+       /* Initialize DAC */
+       outb(0x3C6,0xFF);
+       inb(0x3C7);
+       outb(0x3C8,0x00);
+       inb(0x3C7);
+       for (i=0; i<sizeof(color_LUT); i++) {
+               outb(0x3C9, color_LUT[i]);
+       }
+       for (i; i<768; i += 3) {
+               outb(0x3C9, 0x3F); /* White? */
+               outb(0x3C9, 0x3F); /* White? */
+               outb(0x3C9, 0x3F); /* White? */
+       }
+
+       /* Load font */
+       NOP(inb(0x3DA));  /* Reset Address/Data FlipFlop for Attribute ctlr */
+       outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
+       outw(0x3C4, 0x0001);    /* reset sequencer */
+       outw(0x3C4, 0x0204);    /* write to plane 2 */
+       outw(0x3C4, 0x0407);    /* enable plane graphics */
+       outw(0x3C4, 0x0003);    /* reset sequencer */
+       outw(0x3CE, 0x0402);    /* read plane 2 */
+       outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
+       outw(0x3CE, 0x0600);    /* set graphics */
+       for (i = 0;  i < sizeof(font);  i += 16) {
+               for (j = 0;  j < 16;  j++) {
+                       font_page[(2*i)+j] = font[i+j];
+               }
+       }
+#else
+       outw(0x3C4, 0x0120);                /* disable video              */
+       setTextCLUT(2);                     /* load color lookup table    */
+       loadFont(ISA_mem);                  /* load font                  */
+#endif
+
+       for (i = 0; i < 24; i++) {
+               outb(0x3D4, i);
+               outb(0x3D5, CRTC[i]);
+       }
+       for (i = 0; i < 5; i++) {
+               outb(0x3C4, i);
+               outb(0x3C5, SEQ[i]);
+       }
+       for (i = 0; i < 9; i++) {
+               outb(0x3CE, i);
+               outb(0x3CF, GC[i]);
+       }
+       value = inb(0x3DA);         /* reset flip-flop */
+       for (i = 0; i < 16; i++) {
+               outb(0x3C0, i);
+               outb(0x3C0, AC[i]);
+       }
+       for (i = 16; i < 21; i++) {
+               outb(0x3C0, i | 0x20);
+               outb(0x3C0, AC[i]);
+       }
+       clearVideoMemory();
+       outw(0x3C4, 0x0100);                /* re-enable video            */
+       outb(0x3C2, 0x23);
+       return (1); /* Keyboard should work */
 }
index 4211b6b0038a491397f26b9d90683f2a467e9be2..9df35fa24cdc8520cb3806a5275f0487f366fe25 100644 (file)
@@ -2,62 +2,62 @@
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
-mainmenu_name "Linux Kernel Configuration"
+mainmenu_name "Linux/PowerPC Kernel Configuration"
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
+if [ "`uname`" != "Linux" ]; then
+  define_bool CONFIG_CROSSCOMPILE y
+else
+  define_bool CONFIG_NATIVE y
+fi
+
+bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
+bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
 bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
+bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
+bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+choice 'Processor type' \
+       "Common         CONFIG_MCOMMON \
+        601            CONFIG_M601     \
+        603            CONFIG_M603     \
+        604            CONFIG_M604" Common
 
-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 daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
-endmenu
 
-mainmenu_option next_comment
-comment 'General setup'
 
-bool 'Kernel math emulation' CONFIG_MATH_EMULATION
+mainmenu_option next_comment
+define_bool CONFIG_PCI y
+bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
 bool 'Networking support' CONFIG_NET
-bool 'PCI bios support' CONFIG_PCI
-if [ "$CONFIG_PCI" = "y" ]; then
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
-  fi
-fi
-bool 'System V IPC' CONFIG_SYSVIPC
 bool 'Sysctl support' CONFIG_SYSCTL
-tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+bool 'System V IPC' CONFIG_SYSVIPC
+
+# only elf supported, a.out is not -- Cort
+define_bool CONFIG_BINFMT_ELF y
+define_bool CONFIG_KERNEL_ELF y
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
-tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
-  bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
-fi
 
-source drivers/block/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
-fi
+source drivers/pnp/Config.in
+source drivers/block/Config.in
 
 mainmenu_option next_comment
 comment 'SCSI support'
-
 tristate 'SCSI support' CONFIG_SCSI
-
 if [ "$CONFIG_SCSI" != "n" ]; then
   source drivers/scsi/Config.in
 fi
 endmenu
 
+
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
   comment 'Network device support'
-
+  source net/Config.in
   bool 'Network device support' CONFIG_NETDEVICES
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     source drivers/net/Config.in
@@ -65,9 +65,9 @@ if [ "$CONFIG_NET" = "y" ]; then
   endmenu
 fi
 
+
 mainmenu_option next_comment
 comment 'ISDN subsystem'
-
 tristate 'ISDN support' CONFIG_ISDN
 if [ "$CONFIG_ISDN" != "n" ]; then
   source drivers/isdn/Config.in
@@ -76,7 +76,6 @@ endmenu
 
 mainmenu_option next_comment
 comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-
 bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
   source drivers/cdrom/Config.in
@@ -84,12 +83,10 @@ fi
 endmenu
 
 source fs/Config.in
-
 source drivers/char/Config.in
 
 mainmenu_option next_comment
 comment 'Sound'
-
 tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
   source drivers/sound/Config.in
@@ -97,11 +94,11 @@ fi
 endmenu
 
 mainmenu_option next_comment
-comment 'Kernel hacking'
-
+#comment 'Kernel hacking'
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-bool 'Kernel profiling support' CONFIG_PROFILE
-if [ "$CONFIG_PROFILE" = "y" ]; then
-  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
-fi
+#bool 'Kernel profiling support' CONFIG_PROFILE
+#if [ "$CONFIG_PROFILE" = "y" ]; then
+#  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+#fi
 endmenu
+
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
new file mode 100644 (file)
index 0000000..bd955c7
--- /dev/null
@@ -0,0 +1,239 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+# CONFIG_HEARTBEAT is not set
+# CONFIG_POWERSAVING is not set
+CONFIG_MCOMMON=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_NCR53C7xx=y
+# CONFIG_SCSI_NCR53C7xx_sync is not set
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_SCSI_QLOGIC_PMAC is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_BEXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_RNFS_BOOTP is not set
+# CONFIG_RNFS_RARP is not set
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_HFS_FS=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff --git a/arch/ppc/ignore b/arch/ppc/ignore
new file mode 100644 (file)
index 0000000..693fff6
--- /dev/null
@@ -0,0 +1,65 @@
+.config
+compile.h
+.version
+.objects
+.blurb
+*.cort
+*.paul
+*.old
+.defines
+version.h
+find_name
+checks
+#*
+.objects
+.object_files
+System.map
+asm
+.menuconfig*
+CVS
+ppc_defs.h
+mk_defs
+mkprep
+*.s
+.depend
+.hdepend
+*~
+*.o
+znetboot
+zvmlinux
+vmlinux
+zImage
+hack-coff
+coffboot
+vmlinux.coff
+.depend
+.cvsignore
+RCS
+SCCS
+CVS.adm
+RCSLOG
+cvslog.*
+tags
+TAGS
+.make.state
+.nse_depinfo
+*~
+#*
+.#*
+,*
+_$*
+*$
+*.old
+*.bak
+*.BAK
+*.orig
+*.rej
+*.a
+*.olb
+*.o
+*.obj
+*.so
+*.exe
+*.Z
+*.elc
+*.ln
index 0bfb26c014ac1a4f7b1313d97e8caa82eb6933a1..941cd9e38150bd1a095623820feb5131e6c6275a 100644 (file)
 
 HOST_CC = gcc
 
-OBJS  = misc.o setup.o port_io.o irq.o pci.o traps.o stubs.o process.o \
-       signal.o ksyms.o time.o syscalls.o usercpy.o\
-       support.o ptrace.o 
+OBJS  = misc.o port_io.o pci.o traps.o process.o \
+       signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
 
 all: head.o kernel.o
+head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
 
-head.o: head.s
-head.s: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
+ifeq ($(CONFIG_PREP),y)
+OBJS += prep_setup.o prep_time.o
+endif
+
+ifeq ($(CONFIG_PMAC),y)
+OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
+endif
+
+ifeq ($(CONFIG_MODULES),y)
+OBJS = ksyms.o
+endif
 
-ppc_defs.h: mk_defs
-       mk_defs $@
 
-mk_defs: mk_defs.c
-       $(HOSTCC) $(CFLAGSINC) -Wl,-static ${CFLAGS} -o mk_defs mk_defs.c
+ppc_defs.h: mk_defs.c ppc_defs.head \
+               $(TOPDIR)/include/asm/mmu.h \
+               $(TOPDIR)/include/asm/processor.h \
+               $(TOPDIR)/include/asm/pgtable.h \
+               $(TOPDIR)/include/asm/ptrace.h
+       $(CC) ${CFLAGS} -S mk_defs.c
+       cp ppc_defs.head ppc_defs.h
+       grep '^#define' mk_defs.s >>ppc_defs.h
+       rm mk_defs.s
 
+checks: checks.c
+       $(HOSTCC) ${CFLAGS} -o checks checks.c
+       checks
 
 kernel.o: $(OBJS)
        $(LD) -r -o kernel.o $(OBJS)
-       sync
-
-dep:
-       $(CPP) -M *.c > .depend
 
 fastdep:
+       $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+       $(CPP) -M *.S *.c > .depend
 
-modules:
+modules: 
 
 dummy:
 
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
new file mode 100644 (file)
index 0000000..39cb04f
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * align.c - handle alignment exceptions for the Power PC.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996 Paul Mackerras   (paulus@cs.anu.edu.au).
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+struct aligninfo {
+       unsigned char len;
+       unsigned char flags;
+};
+
+#define INVALID        { 0, 0 }
+
+#define LD     1       /* load */
+#define ST     2       /* store */
+#define        SE      4       /* sign-extend value */
+#define F      8       /* to/from fp regs */
+#define U      0x10    /* update index register */
+#define M      0x20    /* multiple load/store */
+#define S      0x40    /* single-precision fp, or byte-swap value */
+#define HARD   0x80    /* string, stwcx. */
+
+/*
+ * The PowerPC stores certain bits of the instruction that caused the
+ * alignment exception in the DSISR register.  This array maps those
+ * bits to information about the operand length and what the
+ * instruction would do.
+ */
+static struct aligninfo aligninfo[128] = {
+       { 4, LD },              /* 00 0 0000: lwz / lwarx */
+       INVALID,                /* 00 0 0001 */
+       { 4, ST },              /* 00 0 0010: stw */
+       INVALID,                /* 00 0 0011 */
+       { 2, LD },              /* 00 0 0100: lhz */
+       { 2, LD+SE },           /* 00 0 0101: lha */
+       { 2, ST },              /* 00 0 0110: sth */
+       { 4, LD+M },            /* 00 0 0111: lmw */
+       { 4, LD+F+S },          /* 00 0 1000: lfs */
+       { 8, LD+F },            /* 00 0 1001: lfd */
+       { 4, ST+F+S },          /* 00 0 1010: stfs */
+       { 8, ST+F },            /* 00 0 1011: stfd */
+       INVALID,                /* 00 0 1100 */
+       INVALID,                /* 00 0 1101 */
+       INVALID,                /* 00 0 1110 */
+       INVALID,                /* 00 0 1111 */
+       { 4, LD+U },            /* 00 1 0000: lwzu */
+       INVALID,                /* 00 1 0001 */
+       { 4, ST+U },            /* 00 1 0010: stwu */
+       INVALID,                /* 00 1 0011 */
+       { 2, LD+U },            /* 00 1 0100: lhzu */
+       { 2, LD+SE+U },         /* 00 1 0101: lhau */
+       { 2, ST+U },            /* 00 1 0110: sthu */
+       { 4, ST+M },            /* 00 1 0111: stmw */
+       { 4, LD+F+S+U },        /* 00 1 1000: lfsu */
+       { 8, LD+F+U },          /* 00 1 1001: lfdu */
+       { 4, ST+F+S+U },        /* 00 1 1010: stfsu */
+       { 8, ST+F+U },          /* 00 1 1011: stfdu */
+       INVALID,                /* 00 1 1100 */
+       INVALID,                /* 00 1 1101 */
+       INVALID,                /* 00 1 1110 */
+       INVALID,                /* 00 1 1111 */
+       INVALID,                /* 01 0 0000 */
+       INVALID,                /* 01 0 0001 */
+       INVALID,                /* 01 0 0010 */
+       INVALID,                /* 01 0 0011 */
+       INVALID,                /* 01 0 0100 */
+       INVALID,                /* 01 0 0101: lwax?? */
+       INVALID,                /* 01 0 0110 */
+       INVALID,                /* 01 0 0111 */
+       { 0, LD+HARD },         /* 01 0 1000: lswx */
+       { 0, LD+HARD },         /* 01 0 1001: lswi */
+       { 0, ST+HARD },         /* 01 0 1010: stswx */
+       { 0, ST+HARD },         /* 01 0 1011: stswi */
+       INVALID,                /* 01 0 1100 */
+       INVALID,                /* 01 0 1101 */
+       INVALID,                /* 01 0 1110 */
+       INVALID,                /* 01 0 1111 */
+       INVALID,                /* 01 1 0000 */
+       INVALID,                /* 01 1 0001 */
+       INVALID,                /* 01 1 0010 */
+       INVALID,                /* 01 1 0011 */
+       INVALID,                /* 01 1 0100 */
+       INVALID,                /* 01 1 0101: lwaux?? */
+       INVALID,                /* 01 1 0110 */
+       INVALID,                /* 01 1 0111 */
+       INVALID,                /* 01 1 1000 */
+       INVALID,                /* 01 1 1001 */
+       INVALID,                /* 01 1 1010 */
+       INVALID,                /* 01 1 1011 */
+       INVALID,                /* 01 1 1100 */
+       INVALID,                /* 01 1 1101 */
+       INVALID,                /* 01 1 1110 */
+       INVALID,                /* 01 1 1111 */
+       INVALID,                /* 10 0 0000 */
+       INVALID,                /* 10 0 0001 */
+       { 0, ST+HARD },         /* 10 0 0010: stwcx. */
+       INVALID,                /* 10 0 0011 */
+       INVALID,                /* 10 0 0100 */
+       INVALID,                /* 10 0 0101 */
+       INVALID,                /* 10 0 0110 */
+       INVALID,                /* 10 0 0111 */
+       { 4, LD+S },            /* 10 0 1000: lwbrx */
+       INVALID,                /* 10 0 1001 */
+       { 4, ST+S },            /* 10 0 1010: stwbrx */
+       INVALID,                /* 10 0 1011 */
+       { 2, LD+S },            /* 10 0 1100: lhbrx */
+       INVALID,                /* 10 0 1101 */
+       { 2, ST+S },            /* 10 0 1110: sthbrx */
+       INVALID,                /* 10 0 1111 */
+       INVALID,                /* 10 1 0000 */
+       INVALID,                /* 10 1 0001 */
+       INVALID,                /* 10 1 0010 */
+       INVALID,                /* 10 1 0011 */
+       INVALID,                /* 10 1 0100 */
+       INVALID,                /* 10 1 0101 */
+       INVALID,                /* 10 1 0110 */
+       INVALID,                /* 10 1 0111 */
+       INVALID,                /* 10 1 1000 */
+       INVALID,                /* 10 1 1001 */
+       INVALID,                /* 10 1 1010 */
+       INVALID,                /* 10 1 1011 */
+       INVALID,                /* 10 1 1100 */
+       INVALID,                /* 10 1 1101 */
+       INVALID,                /* 10 1 1110 */
+       { 0, ST+HARD },         /* 10 1 1111: dcbz */
+       { 4, LD },              /* 11 0 0000: lwzx */
+       INVALID,                /* 11 0 0001 */
+       { 4, ST },              /* 11 0 0010: stwx */
+       INVALID,                /* 11 0 0011 */
+       { 2, LD },              /* 11 0 0100: lhzx */
+       { 2, LD+SE },           /* 11 0 0101: lhax */
+       { 2, ST },              /* 11 0 0110: sthx */
+       INVALID,                /* 11 0 0111 */
+       { 4, LD+F+S },          /* 11 0 1000: lfsx */
+       { 8, LD+F },            /* 11 0 1001: lfdx */
+       { 4, ST+F+S },          /* 11 0 1010: stfsx */
+       { 8, ST+F },            /* 11 0 1011: stfdx */
+       INVALID,                /* 11 0 1100 */
+       INVALID,                /* 11 0 1101 */
+       INVALID,                /* 11 0 1110 */
+       INVALID,                /* 11 0 1111 */
+       { 4, LD+U },            /* 11 1 0000: lwzux */
+       INVALID,                /* 11 1 0001 */
+       { 4, ST+U },            /* 11 1 0010: stwux */
+       INVALID,                /* 11 1 0011 */
+       { 2, LD+U },            /* 11 1 0100: lhzux */
+       { 2, LD+SE+U },         /* 11 1 0101: lhaux */
+       { 2, ST+U },            /* 11 1 0110: sthux */
+       INVALID,                /* 11 1 0111 */
+       { 4, LD+F+S+U },        /* 11 1 1000: lfsux */
+       { 8, LD+F+U },          /* 11 1 1001: lfdux */
+       { 4, ST+F+S+U },        /* 11 1 1010: stfsux */
+       { 8, ST+F+U },          /* 11 1 1011: stfdux */
+       INVALID,                /* 11 1 1100 */
+       INVALID,                /* 11 1 1101 */
+       INVALID,                /* 11 1 1110 */
+       INVALID,                /* 11 1 1111 */
+};
+
+#define SWAP(a, b)     (t = (a), (a) = (b), (b) = t)
+
+int
+fix_alignment(struct pt_regs *regs)
+{
+       int instr, nb, flags;
+       int i, t;
+       int reg, areg;
+       unsigned char *addr;
+       union {
+               long l;
+               float f;
+               double d;
+               unsigned char v[8];
+       } data;
+
+       instr = (regs->dsisr >> 10) & 0x7f;
+       nb = aligninfo[instr].len;
+       if (nb == 0)
+               return 0;       /* too hard or invalid instruction bits */
+       flags = aligninfo[instr].flags;
+       addr = (unsigned char *) regs->dar;
+       reg = (regs->dsisr >> 5) & 0x1f;        /* source/dest register */
+
+       /* Verify the address of the operand */
+       if (user_mode(regs)) {
+               if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+                       return -EFAULT; /* bad address */
+       }
+
+       if ((flags & F) && last_task_used_math == current)
+               giveup_fpu();
+
+       if (flags & M)
+               return 0;               /* too hard for now */
+
+       /* If we read the operand, copy it in */
+       if (flags & LD) {
+               if (nb == 2) {
+                       data.v[0] = data.v[1] = 0;
+                       if (__get_user(data.v[2], addr)
+                           || __get_user(data.v[3], addr+1))
+                               return -EFAULT;
+               } else {
+                       for (i = 0; i < nb; ++i)
+                               if (__get_user(data.v[i], addr+i))
+                                       return -EFAULT;
+               }
+       }
+
+       switch (flags & ~U) {
+       case LD+SE:
+               if (data.v[2] >= 0x80)
+                       data.v[0] = data.v[1] = -1;
+               /* fall through */
+       case LD:
+               regs->gpr[reg] = data.l;
+               break;
+       case LD+S:
+               if (nb == 2) {
+                       SWAP(data.v[2], data.v[3]);
+               } else {
+                       SWAP(data.v[0], data.v[3]);
+                       SWAP(data.v[1], data.v[2]);
+               }
+               regs->gpr[reg] = data.l;
+               break;
+       case ST:
+               data.l = regs->gpr[reg];
+               break;
+       case ST+S:
+               data.l = regs->gpr[reg];
+               if (nb == 2) {
+                       SWAP(data.v[2], data.v[3]);
+               } else {
+                       SWAP(data.v[0], data.v[3]);
+                       SWAP(data.v[1], data.v[2]);
+               }
+               break;
+       case LD+F:
+               current->tss.fpr[reg] = data.d;
+               break;
+       case ST+F:
+               data.d = current->tss.fpr[reg];
+               break;
+       /* these require some floating point conversions... */
+       /* note that giveup_fpu enables the FPU for the kernel */
+       /* we'd like to use the assignment, but we have to compile
+        * the kernel with -msoft-float so it doesn't use the
+        * fp regs for copying 8-byte objects. */
+       case LD+F+S:
+               giveup_fpu();
+               cvt_fd(&data.f, &current->tss.fpr[reg]);
+               /* current->tss.fpr[reg] = data.f; */
+               break;
+       case ST+F+S:
+               giveup_fpu();
+               cvt_df(&current->tss.fpr[reg], &data.f);
+               /* data.f = current->tss.fpr[reg]; */
+               break;
+       default:
+               printk("align: can't handle flags=%x\n", flags);
+               return 0;
+       }
+
+       if (flags & ST) {
+               if (nb == 2) {
+                       if (__put_user(data.v[2], addr)
+                           || __put_user(data.v[3], addr+1))
+                               return -EFAULT;
+               } else {
+                       for (i = 0; i < nb; ++i)
+                               if (__put_user(data.v[i], addr+i))
+                                       return -EFAULT;
+               }
+       }
+
+       if (flags & U) {
+               areg = regs->dsisr & 0x1f;      /* register to update */
+               regs->gpr[areg] = regs->dar;
+       }
+
+       return 1;
+}
diff --git a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c
new file mode 100644 (file)
index 0000000..fb5a19e
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/kernel.h>
+#include <asm/bitops.h>
+
+/*
+ * I left these here since the problems with "cc" make it difficult to keep
+ * them in bitops.h -- Cort
+ */
+void set_bit(int nr, volatile void *addr)
+{
+       unsigned int t;
+       unsigned int mask = 1 << (nr & 0x1f);
+       volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+       if ((unsigned long)addr & 3)
+               printk(KERN_ERR "set_bit(%x, %p)\n", nr, addr);
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%2
+       or      %0,%0,%1
+       stwcx.  %0,0,%2
+       bne     1b"
+       : "=&r" (t)             /*, "=m" (*p)*/
+       : "r" (mask), "r" (p)
+       : "cc");
+}
+
+void clear_bit(int nr, volatile void *addr)
+{
+       unsigned int t;
+       unsigned int mask = 1 << (nr & 0x1f);
+       volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+       if ((unsigned long)addr & 3)
+               printk(KERN_ERR "clear_bit(%x, %p)\n", nr, addr);
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%2
+       andc    %0,%0,%1
+       stwcx.  %0,0,%2
+       bne     1b"
+       : "=&r" (t)             /*, "=m" (*p)*/
+       : "r" (mask), "r" (p)
+       : "cc");
+}
+
+void change_bit(int nr, volatile void *addr)
+{
+       unsigned int t;
+       unsigned int mask = 1 << (nr & 0x1f);
+       volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+       if ((unsigned long)addr & 3)
+               printk(KERN_ERR "change_bit(%x, %p)\n", nr, addr);
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%2
+       xor     %0,%0,%1
+       stwcx.  %0,0,%2
+       bne     1b"
+       : "=&r" (t)             /*, "=m" (*p)*/
+       : "r" (mask), "r" (p)
+       : "cc");
+}
+
+int test_and_set_bit(int nr, volatile void *addr)
+{
+       unsigned int old, t;
+       unsigned int mask = 1 << (nr & 0x1f);
+       volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+       if ((unsigned long)addr & 3)
+               printk(KERN_ERR "test_and_set_bit(%x, %p)\n", nr, addr);
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%3
+       or      %1,%0,%2
+       stwcx.  %1,0,%3
+       bne     1b"
+       : "=&r" (old), "=&r" (t)        /*, "=m" (*p)*/
+       : "r" (mask), "r" (p)
+       : "cc");
+
+       return (old & mask) != 0;
+}
+
+int test_and_clear_bit(int nr, volatile void *addr)
+{
+       unsigned int old, t;
+       unsigned int mask = 1 << (nr & 0x1f);
+       volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+       if ((unsigned long)addr & 3)
+               printk(KERN_ERR "test_and_clear_bit(%x, %p)\n", nr, addr);
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%3
+       andc    %1,%0,%2
+       stwcx.  %1,0,%3
+       bne     1b"
+       : "=&r" (old), "=&r" (t)        /*, "=m" (*p)*/
+       : "r" (mask), "r" (p)
+       : "cc");
+
+       return (old & mask) != 0;
+}
+
+int test_and_change_bit(int nr, volatile void *addr)
+{
+       unsigned int old, t;
+       unsigned int mask = 1 << (nr & 0x1f);
+       volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+       if ((unsigned long)addr & 3)
+               printk(KERN_ERR "test_and_change_bit(%x, %p)\n", nr, addr);
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%3
+       xor     %1,%0,%2
+       stwcx.  %1,0,%3
+       bne     1b"
+       : "=&r" (old), "=&r" (t)        /*, "=m" (*p)*/
+       : "r" (mask), "r" (p)
+       : "cc");
+
+       return (old & mask) != 0;
+}
+
+/* I put it in bitops.h -- Cort */
+#if 0
+int ffz(unsigned int x)
+{
+       int n;
+
+       x = ~x & (x+1);         /* set LS zero to 1, other bits to 0 */
+       __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+       return 31 - n;
+}
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+int find_first_zero_bit(void * addr, int size)
+{
+       unsigned int * p = ((unsigned int *) addr);
+       unsigned int result = 0;
+       unsigned int tmp;
+
+       if (size == 0)
+               return 0;
+       while (size & ~31UL) {
+               if (~(tmp = *(p++)))
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
+       tmp |= ~0UL << size;
+found_middle:
+       return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+int find_next_zero_bit(void * addr, int size, int offset)
+{
+       unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+       unsigned int result = offset & ~31UL;
+       unsigned int tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= 31UL;
+       if (offset) {
+               tmp = *(p++);
+               tmp |= ~0UL >> (32-offset);
+               if (size < 32)
+                       goto found_first;
+               if (~tmp)
+                       goto found_middle;
+               size -= 32;
+               result += 32;
+       }
+       while (size & ~31UL) {
+               if (~(tmp = *(p++)))
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
+found_first:
+       tmp |= ~0UL << size;
+found_middle:
+       return result + ffz(tmp);
+}
+#endif
diff --git a/arch/ppc/kernel/checks.c b/arch/ppc/kernel/checks.c
new file mode 100644 (file)
index 0000000..9e0bd3a
--- /dev/null
@@ -0,0 +1,56 @@
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+
+/*
+ * Do various before compile checks of data structures
+ * -- Cort
+ */
+int main(void)
+{
+       int ret = 0;
+       
+       if ( sizeof(struct thread_struct) % 16 )
+       {
+               printf("Thread struct is not modulo 16 bytes: "
+                       "%d bytes total, %d bytes off\n",
+                       sizeof(struct thread_struct),
+                       sizeof(struct thread_struct)%16);
+               ret = -1;
+       }
+
+       if ( sizeof(struct pt_regs) % 16 )
+       {
+               printf("pt_regs struct is not modulo 16 bytes: "
+                       "%d bytes total, %d bytes off\n",
+                       sizeof(struct pt_regs),
+                       sizeof(struct pt_regs)%16);
+               ret = -1;
+               
+       }
+
+       printf("Task size        : %d bytes\n"
+              "Tss size         : %d bytes\n"
+              "pt_regs size     : %d bytes\n"
+              "Kernel stack size: %d bytes\n",
+              sizeof(struct task_struct), sizeof(struct thread_struct),
+              sizeof(struct pt_regs),
+              sizeof(union task_union) - sizeof(struct task_struct));
+       return ret;
+}
index 648c7bccfcc259bebfc7a71a5b8f003557ee3410..25f2dd8a0a2e0a5d2dd78e4b675ca3c9f04d9bf9 100644 (file)
-#include "ppc_asm.tmpl"
-#include "ppc_defs.h"
-#include <linux/errno.h>
-#include <linux/sys.h>
-#include <asm/ppc_machine.h>
-       
-#define NEWMM 1
-#define SYNC() \
-       isync; \
-       sync
-
-#define STATS
 /*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
+ *  arch/ppc/kernel/head.S
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ *  Adapted for Power Macintosh by Paul Mackerras.
+ *  Low-level exception handlers and MMU support
+ *  rewritten by Paul Mackerras.
+ *    Copyright (C) 1996 Paul Mackerras.
+ *
+ *  This file contains the low-level support and setup for the
+ *  PowerPC platform, including trap and interrupt dispatch.
+ *  Also included here is low-level thread/task switch support.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *     
  */
-#define BUMP(ctr) \
-       lis     r2,ctr@h; \
-       ori     r2,r2,ctr@l; \
-       lwz     r3,4(r2); \
-       addic   r3,r3,1; \
-       stw     r3,4(r2); \
-       lwz     r3,0(r2); \
-       addze   r3,r3; \
-       stw     r3,0(r2)
-
-/* The same as 'BUMP' but running unmapped (TLB code) */       
-#define BUMP_UNMAPPED(ctr) \
-       mfspr   r0,XER; \
-       lis     r2,ctr@h; \
-       ori     r2,r2,ctr@l; \
-       lis     r3,0xF000; \
-       andc    r2,r2,r3; \
-       lwz     r3,4(r2); \
-       addic   r3,r3,1; \
-       stw     r3,4(r2); \
-       lwz     r3,0(r2); \
-       addze   r3,r3; \
-       mtspr   XER,r0; \
-       stw     r3,0(r2)
-
-#define DO_RFI_TRACE_UNMAPPED(mark)
-#define DO_RFI_TRACE_MAPPED(mark)
-
-#define DEFAULT_TRAP(offset) \
-       li      r13,0; \
-       ori     r13,r13,HID0_ICE; \
-       mtspr   HID0,r13; \
-       lis     r13,0xFFF00000>>16; \
-       ori     r13,r13,offset; \
-       mtlr    r13; \
-       blr
-#define TRACE_TRAP(offset)     
 
-#define DATA_CACHE_OFF() \
-       mfspr   r2,HID0; \
-       li      r3,0; \
-       ori     r3,r3,HID0_DCE; \
-       andc    r2,r2,r3; \
-       mtspr   HID0,r2;
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/config.h>
 
-#define DATA_CACHE_ON() \
-       mfspr   r2,HID0; \
-       ori     r2,r2,HID0_DCE; \
-       mtspr   HID0,r2;
+#define SYNC() \
+       sync; \
+       isync
 
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 603 or 601 */
 #define tlbia \
-       li      r4,64; \
-       mtspr   CTR,r4; \
-       lis     r4,0x9000; \
+       li      r4,128; \
+       mtctr   r4; \
+       lis     r4,0xC000; \
 0:     tlbie   r4; \
        addi    r4,r4,0x1000; \
        bdnz    0b
 
-/* Validate kernel stack - check for overflow */
-/* all regs are considered scratch since the C function will stomp them */
-#define CHECK_STACK() \
-       /*lis   r3,current_set@ha; \
-       lwz     r3,current_set@l(r3); \
-       bl      _EXTERN(check_stack)*/
-#if 0
-#define _CHECK_STACK() \
-       mtspr   SPR0,r3; \
-       mtspr   SPR1,r4;    /* use r3,4 as scratch */ \
-       lis     r2,current_set@ha; \
-       lwz     r2,current_set@l(r2); \
-       lwz     r2,KERNEL_STACK_PAGE(r2); \
-       /* if kernel stack is sys_stack skip check */ \
-       /*lis   r3,sys_stack@h; \
-       ori     r3,r3,sys_stack@l; \
-       cmpl    0,r1,r3;*/ \
-       /* check for STACK_MAGIC on kernel stack page */ \
-       lis     r3, 0xdead; /* STACK_MAGIC */ \
-       ori     r3,r3,0xbeef; \
-       lwz     r4,0(r2);      /* get *kernel_stack_page */ \
-       cmpl    0,r4,r3; \
-       bne     01f; \
-       /* check that ksp is > kernel page */ \
-       /*li    r3,0x0FFF; \
-       andc    r2,r2,r3; \
-       andc    r3,r1,r3; \
-       cmp     0,r3,r2; \
-       beq     02f;*/ \
-       /* check that ksp and kernel stack page are on same page */ \
-       cmp     0,r1,r2; \
-       bge     02f; \
-01:    mr      r6,r1; /* setup info for call to bad_stack() */ \
-       mr      r5,r2; \
-       bl      _EXTERN(bad_stack); \
-02:    mfspr   r4,SPR1; \
-       mfspr   r3,SPR0
-#endif
+#define TOPHYS(x)      (x - KERNELBASE)
+
+
+/* this is a very kludgey way of loading up the BATs on the
+   prep system.  I'll kill this horrible macro and write
+   something clean when I have a chance -- Cort
+ */    
+#define LOAD_BATS(RA,RB) \
+       mfspr   RA,PVR          ; \
+       srwi    r5,r5,16        ; \
+       cmpi    0,RA,1          ; \
+       beq     199f            ; \
+       /* load bats for 60x */ ; \
+       lis     RA,BAT0@h       ; \
+       ori     RA,RA,BAT0@l    ; \
+       addis   RA,RA,-KERNELBASE@h;\
+       lwz     RB,0(RA)        ; \
+       mtspr   IBAT0U,RB       ; \
+       mtspr   DBAT0U,RB       ; \
+       lwz     RB,4(RA)        ; \
+       mtspr   IBAT0L,RB       ; \
+       mtspr   DBAT0L,RB       ; \
+       lis     RA,BAT1@h       ; \
+       ori     RA,RA,BAT1@l    ; \
+       addis   RA,RA,-KERNELBASE@h;\
+       lwz     RB,0(RA)        ; \
+       mtspr   IBAT1U,RB       ; \
+       mtspr   DBAT1U,RB       ; \
+       lwz     RB,4(RA)        ; \
+       mtspr   IBAT1L,RB       ; \
+       mtspr   DBAT1L,RB       ; \
+       lis     RA,BAT2@h       ; \
+       ori     RA,RA,BAT2@l    ; \
+       addis   RA,RA,-KERNELBASE@h;\
+       lwz     RB,0(RA)        ; \
+       mtspr   IBAT2U,RB       ; \
+       mtspr   DBAT2U,RB       ; \
+       lwz     RB,4(RA)        ; \
+       mtspr   IBAT2L,RB       ; \
+       mtspr   DBAT2L,RB       ; \
+       lis     RA,BAT3@h       ; \
+       ori     RA,RA,BAT3@l    ; \
+       addis   RA,RA,-KERNELBASE@h;\
+       lwz     RB,0(RA)        ; \
+       mtspr   IBAT3U,RB       ; \
+       mtspr   DBAT3U,RB       ; \
+       lwz     RB,4(RA)        ; \
+       mtspr   IBAT3L,RB       ; \
+       mtspr   DBAT3L,RB       ; \
+       b       200f            ; \
+199:   /*load bats for 601 */  ; \
+       lis     RA,BAT0_601@h   ; \
+       ori     RA,RA,BAT0_601@l; \
+       addis   RA,RA,-KERNELBASE@h;\
+       lwz     RB,0(RA)        ; \
+       mtspr   IBAT0U,RB       ; \
+       mtspr   DBAT0U,RB       ; \
+       lwz     RB,4(RA)        ; \
+       mtspr   IBAT0L,RB       ; \
+       mtspr   DBAT0L,RB       ; \
+       lis     RA,BAT1_601@h   ; \
+       ori     RA,RA,BAT1_601@l; \
+       addis   RA,RA,-KERNELBASE@h;\
+       lwz     RB,0(RA)        ; \
+       mtspr   IBAT1U,RB       ; \
+       mtspr   DBAT1U,RB       ; \
+       lwz     RB,4(RA)        ; \
+       mtspr   IBAT1L,RB       ; \
+       mtspr   DBAT1L,RB       ; \
+       lis     RA,BAT2_601@h   ; \
+       ori     RA,RA,BAT2_601@l; \
+       addis   RA,RA,-KERNELBASE@h;\
+       lwz     RB,0(RA)        ; \
+       mtspr   IBAT2U,RB       ; \
+       mtspr   DBAT2U,RB       ; \
+       lwz     RB,4(RA)        ; \
+       mtspr   IBAT2L,RB       ; \
+       mtspr   DBAT2L,RB       ; \
+       lis     RA,BAT3_601@h   ; \
+       ori     RA,RA,BAT3_601@l; \
+       addis   RA,RA,-KERNELBASE@h;\
+       lwz     RB,0(RA)        ; \
+       mtspr   IBAT3U,RB       ; \
+       mtspr   DBAT3U,RB       ; \
+       lwz     RB,4(RA)        ; \
+       mtspr   IBAT3L,RB       ; \
+       mtspr   DBAT3L,RB       ; \
+200:
        
-/* save fp regs if fp is used */
-/* assumes that r1 contains ptr to regs of task and r2 is scratch 
-         -- Cort  */
-#define SAVE_FP_REGS() \
-               /* check if fp has been used by checking msr_fp bit */ \
-       lwz     r2,_MSR(r1);  \
-       andi.   r2,r2,MSR_FP; \
-       bne     00f; \
-       /* floating point has been used -- save fp regs */ \
-       lis     r2,current_set@h; \
-       ori     r2,r2,current_set@l; \
-       addi    r2,r2,TSS; \
-       /*mr    r2,r1;*/ \
-       stfd    fr0,TSS_FPR0(r2); \
-       stfd    fr1,TSS_FPR1(r2); \
-       stfd    fr2,TSS_FPR2(r2); \
-       stfd    fr3,TSS_FPR3(r2); \
-       stfd    fr4,TSS_FPR4(r2); \
-       stfd    fr5,TSS_FPR5(r2); \
-       stfd    fr6,TSS_FPR6(r2); \
-       stfd    fr7,TSS_FPR7(r2); \
-       stfd    fr8,TSS_FPR8(r2); \
-       stfd    fr9,TSS_FPR9(r2); \
-       stfd    fr10,TSS_FPR10(r2); \
-       stfd    fr11,TSS_FPR11(r2); \
-       stfd    fr12,TSS_FPR12(r2); \
-       stfd    fr13,TSS_FPR13(r2); \
-       stfd    fr14,TSS_FPR14(r2); \
-       stfd    fr15,TSS_FPR15(r2); \
-       stfd    fr16,TSS_FPR16(r2); \
-       stfd    fr17,TSS_FPR17(r2); \
-       stfd    fr18,TSS_FPR18(r2); \
-       stfd    fr19,TSS_FPR19(r2); \
-       stfd    fr20,TSS_FPR20(r2); \
-       stfd    fr21,TSS_FPR21(r2); \
-       stfd    fr22,TSS_FPR22(r2); \
-       stfd    fr23,TSS_FPR23(r2); \
-       stfd    fr24,TSS_FPR24(r2); \
-       stfd    fr25,TSS_FPR25(r2); \
-       stfd    fr26,TSS_FPR26(r2); \
-       stfd    fr27,TSS_FPR27(r2); \
-       stfd    fr28,TSS_FPR28(r2); \
-       stfd    fr29,TSS_FPR29(r2); \
-       stfd    fr30,TSS_FPR30(r2); \
-       stfd    fr31,TSS_FPR31(r2); \
-00:
-
-
-/* restores fp regs if fp has been used -- always restores fpscr */
-/* assumes that r1 contains ptr to regs, r2 is scratch and srr1 holds
-   what will become the msr when this process executes         -- Cort*/
-#define RESTORE_FP_REGS(mark) \
-       /* check if restoring from _switch() */ \
-       li      r2, mark; \
-       cmpi    0,r2,0x0f0f; \
-       bne     00f; /* only need to save if called from _switch() with 0x0f0f */\
-               /* check if fp has been used by checking msr_fp bit */ \
-       /* srr1 contains msr */ \
-       mfspr   r2,SRR1; \
-       andi.   r2,r2,MSR_FP; \
-       bne     00f; \
-       /* floating point has been used -- restore fp regs */ \
-       /* Hey, Rocky!  Watch me pull fp regs from my stack! */ \
-       lis     r2,current_set@h; \
-       ori     r2,r2,current_set@l; \
-       addi    r2,r2,TSS; \
-       /*mr    r2,r1;*/\
-       lfd     fr0,TSS_FPR0(r2); \
-       lfd     fr1,TSS_FPR1(r2); \
-       lfd     fr2,TSS_FPR2(r2); \
-       lfd     fr3,TSS_FPR3(r2); \
-       lfd     fr4,TSS_FPR4(r2); \
-       lfd     fr5,TSS_FPR5(r2); \
-       lfd     fr6,TSS_FPR6(r2); \
-       lfd     fr7,TSS_FPR7(r2); \
-       lfd     fr8,TSS_FPR8(r2); \
-       lfd     fr9,TSS_FPR9(r2); \
-       lfd     fr10,TSS_FPR10(r2); \
-       lfd     fr11,TSS_FPR11(r2); \
-       lfd     fr12,TSS_FPR12(r2); \
-       lfd     fr13,TSS_FPR13(r2); \
-       lfd     fr14,TSS_FPR14(r2); \
-       lfd     fr15,TSS_FPR15(r2); \
-       lfd     fr16,TSS_FPR16(r2); \
-       lfd     fr17,TSS_FPR17(r2); \
-       lfd     fr18,TSS_FPR18(r2); \
-       lfd     fr19,TSS_FPR19(r2); \
-       lfd     fr20,TSS_FPR20(r2); \
-       lfd     fr21,TSS_FPR21(r2); \
-       lfd     fr22,TSS_FPR22(r2); \
-       lfd     fr23,TSS_FPR23(r2); \
-       lfd     fr24,TSS_FPR24(r2); \
-       lfd     fr25,TSS_FPR25(r2); \
-       lfd     fr26,TSS_FPR26(r2); \
-       lfd     fr27,TSS_FPR27(r2); \
-       lfd     fr28,TSS_FPR28(r2); \
-       lfd     fr29,TSS_FPR29(r2); \
-       lfd     fr30,TSS_FPR30(r2); \
-       lfd     fr31,TSS_FPR31(r2); \
-00:
-
-/* save all registers */
-#define SAVE_ALL_REGS(mark) \
-       subi    r1,r1,INT_FRAME_SIZE;   /* Make room for frame */ \
-       stmw    r3,GPR3(r1);    /* Save R3..R31 */ \
-       stw     r3,ORIG_GPR3(r1); \
-       stw     r0,GPR0(r1); \
-       mfspr   r2,SPR0; \
-       stw     r2,GPR1(r1); \
-       mfspr   r2,SPR1; \
-       stw     r2,GPR2(r1); \
-       mfspr   r2,SPR2; \
-       stw     r2,_NIP(r1); \
-       mfspr   r2,SPR3; \
-       stw     r2,_MSR(r1); \
-       mfctr   r2; \
-       stw     r2,_CTR(r1); \
-       mflr    r2; \
-       stw     r2,_LINK(r1); \
-       mfcr    r2; \
-       stw     r2,_CCR(r1); \
-       mfspr   r2,XER; \
-       stw     r2,_XER(r1); \
-       mffs    fr0; \
-       stfd    fr0,FPCSR(r1); \
-       lis     r2,_break_lwarx@h; \
-       ori     r2,r2,_break_lwarx@l; \
-       stwcx.  r2,0,r2; \
-       li      r2,mark; \
-       stw     r2,TRAP(r1); \
-       lis     r2,0xDEAD; \
-       ori     r2,r2,0xDEAD; \
-       stw     r2,MARKER(r1); \
-       li      r2,0; \
-       stw     r2,RESULT(r1)
-
-
-/* save registers clobbered by a page fault handler */
-#define SAVE_PAGE_FAULT_REGS(offset) \
-       mfspr   r2,DAR; \
-       stw     r2,_DAR(r1); \
-       mfspr   r2,DSISR; \
-       stw     r2,_DSISR(r1); \
-       mfspr   r2,PVR;                 /* Check for 603/603e */ \
-       srwi    r2,r2,16; \
-       cmpi    0,r2,3;                 /* 603 */ \
-       beq     22f; \
-       cmpi    0,r2,6;                 /* 603e */ \
-       bne     24f; \
-22:    mfspr   r2,HASH1;               /* Note: these registers exist only on 603 */ \
-       stw     r2,_HASH1(r1); \
-       mfspr   r2,HASH2; \
-       stw     r2,_HASH2(r1); \
-       mfspr   r2,IMISS; \
-       stw     r2,_IMISS(r1); \
-       mfspr   r2,DMISS; \
-       stw     r2,_DMISS(r1); \
-       mfspr   r2,ICMP; \
-       stw     r2,_ICMP(r1); \
-       mfspr   r2,DCMP; \
-       stw     r2,_DCMP(r1); \
-24:    
-
-#define SAVE_INT_REGS(mark) \
-       mtspr   SPR0,r1;        /* Save current stack pointer */ \
-       mtspr   SPR1,r2;        /* Scratch */ \
-       mfcr    r2; \
-       mtspr   SPR2,r2; \
-       mfspr   r2,SRR1;        /* Interrupt from user/system mode */ \
-       andi.   r2,r2,MSR_PR; \
-       beq+    10f;            /* Jump if system - already have stack */ \
-       mfspr   r2,SPR2;        /* Restore CCR */ \
-       mtcrf   0xFF,r2; \
-       mfspr   r2,SRR0;        /* Preserve interrupt registers */ \
-       mtspr   SPR2,r2; \
-       mfspr   r2,SRR1; \
-       mtspr   SPR3,r2; \
-       lis     r2,05f@h; \
-       ori     r2,r2,05f@l; \
-       mtspr   SRR0,r2; \
-       mfmsr   r2; \
-       ori     r2,r2,MSR_|MSR_DR|MSR_IR; \
-       mtspr   SRR1,r2; \
-       rfi; \
-05:    lis     r2,current_set@ha; \
-       lwz     r2,current_set@l(r2); \
-       mfspr   r1,SPR2; \
-       stw     r1,TSS+LAST_PC(r2); \
-       mfspr   r1,SPR0; \
-       stw     r1,TSS+USER_STACK(r2); \
-       lwz     r1,TSS+KSP(r2); \
-       subi    r1,r1,INT_FRAME_SIZE;   /* Make room for frame */ \
-       stw     r1,TSS+PT_REGS(r2);     /* Save regs pointer for 'ptrace' */ \
-       lwz     r1,TSS+KSP(r2); \
-       b       20f; \
-10:    mfspr   r2,SPR2;        /* Restore CCR */ \
-       mtcrf   0xFF,r2; \
-       mfspr   r2,SRR0;        /* Preserve interrupt registers */ \
-       mtspr   SPR2,r2; \
-       mfspr   r2,SRR1; \
-       mtspr   SPR3,r2; \
-       lis     r2,20f@h; \
-       ori     r2,r2,20f@l; \
-       mtspr   SRR0,r2; \
-       mfmsr   r2; \
-       ori     r2,r2,MSR_|MSR_DR|MSR_IR; \
-       mtspr   SRR1,r2; \
-       SYNC(); \
-       rfi; \
-20:    SAVE_ALL_REGS(mark); \
-       CHECK_STACK()
-
-#define RETURN_FROM_INT(mark) \
-90:    mfmsr   r0;             /* Disable interrupts */ \
-       li      r4,0; \
-       ori     r4,r4,MSR_EE; \
-       andc    r0,r0,r4; \
-       sync;                   /* Some chip revs need this... */ \
-       mtmsr   r0; \
-       lis     r2,intr_count@ha; /* Need to run 'bottom half' */ \
-       lwz     r3,intr_count@l(r2); \
-       cmpi    0,r3,0; \
-       bne     00f; \
-       lis     r4,bh_mask@ha; \
-       lwz     r4,bh_mask@l(r4); \
-       lis     r5,bh_active@ha; \
-       lwz     r5,bh_active@l(r5); \
-       and.    r4,r4,r5; \
-       beq     00f; \
-       addi    r3,r3,1; \
-       stw     r3,intr_count@l(r2); \
-       bl      _EXTERN(_do_bottom_half); \
-       lis     r2,intr_count@ha; \
-       lwz     r3,intr_count@l(r2); \
-       subi    r3,r3,1; \
-       stw     r3,intr_count@l(r2); \
-00:    lwz     r2,_MSR(r1); /* Returning to user mode? */ \
-       andi.   r2,r2,MSR_PR; \
-       beq+    10f;            /* no - no need to mess with stack */ \
-/*     lis     r2,kernel_pages_are_copyback@ha; \
-       lwz     r2,kernel_pages_are_copyback@l(r2); \
-       cmpi    0,r2,0; \
-       beq     05f; \
-       bl      _EXTERN(flush_instruction_cache); */ \
-05:    lis     r3,current_set@ha;      /* need to save kernel stack pointer */ \
-       lwz     r3,current_set@l(r3); \
-       /*addi  r4,r1,INT_FRAME_SIZE*/; /* size of frame */ \
-       lwz     r4, KERNEL_STACK_PAGE(r3); \
-       addi    r4,r4,KERNEL_STACK_SIZE; /* reset stack pointer to top of stack page */ \
-       /* stack isn't 0'd so show_task():sched.c shows highwater of stack */ \
-       stw     r4,TSS+KSP(r3); \
-       lwz     r4,STATE(r3);   /* If state != 0, can't run */ \
-       cmpi    0,r4,0; \
-       beq     06f; \
-       bl      _EXTERN(schedule); \
-       b       90b; \
-06:    lwz     r4,COUNTER(r3); /* Time quantum expired? */ \
-       cmpi    0,r4,0; \
-       bne     07f; \
-       bl      _EXTERN(schedule); \
-       b       90b; \
-07:    lwz     r4,BLOCKED(r3); /* Check for pending unblocked signals */ \
-       lwz     r5,SIGNAL(r3); \
-       andc.   r0,r5,r4;       /* Lets thru any unblocked */ \
-       beq     10f; \
-       mr      r3,r4; \
-       mr      r4,r1; \
-       bl      _EXTERN(do_signal); \
-10:    lwz     r2,_NIP(r1);    /* Restore environment */ \
-       mtspr   SRR0,r2; \
-       lwz     r2,_MSR(r1); \
-       mtspr   SRR1,r2; \
-       lmw     r3,GPR3(r1); \
-       lwz     r2,_CTR(r1); \
-       mtctr   r2; \
-       lwz     r2,_LINK(r1); \
-       mtlr    r2; \
-       lwz     r2,_XER(r1); \
-       mtspr   XER,r2; \
-       lfd     fr0,FPCSR(r1); \
-       mtfsf   0xFF,fr0; \
-       RESTORE_FP_REGS(mark) ; \
-       lwz     r2,_CCR(r1); \
-       mtcrf   0xFF,r2; \
-       lwz     r0,GPR0(r1); \
-       lwz     r2,GPR2(r1); \
-       lwz     r1,GPR1(r1); \
-       SYNC(); \
-       rfi
+
 
        
-_TEXT()
+       .text
+       .globl  _stext
+_stext:
+
+#ifdef CONFIG_PREP     
+       . = 0x100
+_GLOBAL(HardReset)
+       b       _start
+
+#endif /* CONFIG_PREP */
+
+#ifdef CONFIG_PMAC
 /*
- * This code may be executed by a bootstrap process.  If so, the
- * purpose is to relocate the loaded image to it's final location
- * in memory.
- *    R3: End of image
- *    R4: Start of image - 0x400
- *   R11: Start of command line string
- *   R12: End of command line string
- *   R30: 'BeBx' if this is a BeBox
- *
+ * _start is defined this way because the XCOFF loader in the OpenFirmware
+ * on the powermac expects the entry point to be a procedure descriptor.
  */
+       .text
        .globl  _start
-       .globl  _stext
-_stext:
 _start:
-       addi    r4,r4,0x400     /* Point at start of image */
-       li      r5,0            /* Load address */
-       subi    r4,r4,4         /* Adjust for auto-increment */
-       subi    r5,r5,4
-       subi    r3,r3,4
-00:    lwzu    r0,4(r4)        /* Fast move */
-       stwu    r0,4(r5)
-       cmp     0,r3,r4
-       bne     00b
-       li      r5,0x100        /* Actual code starts here */
-       mtlr    r5
-       blr
-
-hang:
-       ori     r0,r0,0
-       b       hang
+       .long   TOPHYS(__start),0,0
 
 /*
- * BeBox CPU #1 vector & code
- */    
-_ORG(0x0080)
-       .globl  BeBox_CPU1_vector
-BeBox_CPU1_vector:
-       .long   0
-BeBox_CPU1_reset:
-       li      r1,BeBox_CPU1_vector@l
-       li      r2,0
-       stw     r2,0(r1)
-00:    lwz     r2,0(r1)
-       cmpi    0,r2,0
-       bne     10f
-       li      r2,10000
-       mtctr   r2
-02:    nop
-       bdnz    02b
-       b       00b
-10:    mtlr    r1
-       blr     
-       
-_ORG(0x0100)
+ * Enter here with the kernel text, data and bss loaded starting at
+ * 0, running with virtual == physical mapping.
+ * r5 points to the prom entry point (the client interface handler
+ * address).  Address translation is turned on, with the prom
+ * managing the hash table.  Interrupts are disabled.  The stack
+ * pointer (r1) points to just below the end of the half-meg region
+ * from 0x380000 - 0x400000, which is mapped in already.
+ */
+       .globl  __start
+__start:
 
-/* Hard Reset */
-       .globl  HardReset
-HardReset:
-       b       Reset
+/*
+ * Use the first pair of BAT registers to map the 1st 8MB
+ * of RAM to KERNELBASE.
+ */
+       mfspr   r9,PVR
+       rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
+       cmpi    0,r9,1
+       lis     r7,KERNELBASE@h
+       bne     4f
+       ori     r7,r7,4                 /* set up BAT registers for 601 */
+       li      r8,0x7f
+       b       5f
+4:     ori     r7,r7,0xff              /* set up BAT registers for 604 */
+       li      r8,2
+       mtspr   DBAT0U,r7
+       mtspr   DBAT0L,r8
+5:     mtspr   IBAT0U,r7
+       mtspr   IBAT0L,r8
+       isync
 
-_ORG(0x0200)
-       b       MachineCheck
+/*
+ * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
+ * refer to addresses of data items, procedures, etc. normally.
+ */
+       lis     r7,start_here@ha        /* jump up to our copy at KERNELBASE */
+       addi    r7,r7,start_here@l
+       mtlr    r7
+       blr
+#endif /* CONFIG_PMAC */
 
-_ORG(0x0300)
-       b       DataAccess
 
-_ORG(0x0400)
-       b       InstructionAccess
 
-_ORG(0x0500)
-       b       HardwareInterrupt
        
-_ORG(0x0600)
-       b       Alignment
-
-_ORG(0x0700)
-       b       ProgramCheck
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)      stw     n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base)    SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)    SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)    SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)   SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base)      lwz     n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base)    REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)    REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)    REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)   REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base)      stfd    n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base)    SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base)    SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base)    SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base)   SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base)   SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base)      lfd     n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base)    REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base)    REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base)    REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base)   REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base)   REST_16FPRS(n, base); REST_16FPRS(n+16, base)
 
-_ORG(0x0800)
-       b       FloatingPointCheck
+/*
+ * Exception entry code.  This code runs with address translation
+ * turned off, i.e. using physical addresses.
+ * We assume sprg3 has the physical address of the current
+ * task's thread_struct.
+ */
+#define EXCEPTION_PROLOG       \
+0:     mtspr   SPRG0,r20;      \
+       mtspr   SPRG1,r21;      \
+       mfcr    r20;            \
+       mfspr   r21,SRR1;               /* test whether from user or kernel */\
+       andi.   r21,r21,MSR_PR; \
+       mr      r21,r1;                 /* from kernel - use current sp */\
+       beq     1f;             \
+       mfspr   r21,SPRG3;              /* from user - load kernel sp */\
+       lwz     r21,KSP(r21);   \
+1:     addis   r21,r21,-KERNELBASE@h;  /* convert sp to physical */    \
+       subi    r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\
+       stw     r1,GPR1(r21);   \
+       stw     r1,0(r21);      \
+       addis   r1,r21,KERNELBASE@h;    /* set new kernel sp */         \
+       stw     r20,_CCR(r21);          /* save registers */            \
+       stw     r22,GPR22(r21); \
+       stw     r23,GPR23(r21); \
+       mfspr   r20,SPRG0;      \
+       stw     r20,GPR20(r21); \
+       mfspr   r22,SPRG1;      \
+       stw     r22,GPR21(r21); \
+       mflr    r20;            \
+       stw     r20,_LINK(r21); \
+       mfctr   r22;            \
+       stw     r22,_CTR(r21);  \
+       mfspr   r20,XER;        \
+       stw     r20,_XER(r21);  \
+       mfspr   r22,SRR0;       \
+       mfspr   r23,SRR1;               /* we can now take exceptions */\
+       stw     r0,GPR0(r21);   \
+       stw     r2,GPR2(r21);   \
+       SAVE_4GPRS(3, r21);
+/*
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r21, r22 (SRR0), and r23 (SRR1).
+ */
 
-/* Decrementer register - ignored for now... */
+/*
+ * Exception vectors.
+ */
+#define STD_EXCEPTION(n, label, hdlr)          \
+       . = n;                                  \
+label:                                         \
+       EXCEPTION_PROLOG;                       \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;     \
+       li      r20,MSR_KERNEL;                 \
+       bl      transfer_to_handler;            \
+       .long   hdlr;                           \
+       .long   int_return
+
+#ifndef CONFIG_PREP
+/* System reset */
+       STD_EXCEPTION(0x100, Reset, UnknownException)
+#endif /* ndef CONFIG_PREP */
+
+/* Machine check */
+       STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data access exception */
+       . = 0x300
+DataAccess:
+       EXCEPTION_PROLOG
+       mfspr   r20,DSISR
+       andis.  r0,r20,0x8470           /* weird error? */
+       bne     1f                      /* if not, try to put a PTE */
+       mfspr   r3,DAR                  /* into the hash table */
+       rlwinm  r4,r23,32-13,30,30      /* MSR_PR -> _PAGE_USER */
+       rlwimi  r4,r20,32-23,29,29      /* DSISR_STORE -> _PAGE_RW */
+       mfspr   r5,SPRG3                /* phys addr of TSS */
+       bl      hash_page
+1:     stw     r20,_DSISR(r21)
+       mr      r5,r20
+       mfspr   r4,DAR
+       stw     r4,_DAR(r21)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r20,MSR_KERNEL
+       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
+       bl      transfer_to_handler
+       .long   do_page_fault
+       .long   int_return
+
+/* Instruction access exception */
+       . = 0x400
+InstructionAccess:     
+       EXCEPTION_PROLOG
+       andis.  r0,r23,0x4000           /* no pte found? */
+       beq     1f                      /* if so, try to put a PTE */
+       mr      r3,r22                  /* into the hash table */
+       rlwinm  r4,r23,32-13,30,30      /* MSR_PR -> _PAGE_USER */
+       mr      r20,r23                 /* SRR1 has reason bits */
+       mfspr   r5,SPRG3                /* phys addr of TSS */
+       bl      hash_page
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       mr      r4,r22
+       mr      r5,r23
+       li      r20,MSR_KERNEL
+       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
+       bl      transfer_to_handler
+       .long   do_page_fault
+       .long   int_return
+
+/* External interrupt */
+       STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+
+/* Alignment exception */
+       . = 0x600
+Alignment:
+       EXCEPTION_PROLOG
+       mfspr   r4,DAR
+       stw     r4,_DAR(r21)
+       mfspr   r5,DSISR
+       stw     r5,_DSISR(r21)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r20,MSR_KERNEL
+       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
+       bl      transfer_to_handler
+       .long   AlignmentException
+       .long   int_return
+
+/* Program check exception */
+       . = 0x700
+ProgramCheck:
+       EXCEPTION_PROLOG
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r20,MSR_KERNEL
+       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
+       bl      transfer_to_handler
+       .long   ProgramCheckException
+       .long   int_return
+
+/* Floating-point unavailable */
+       . = 0x800
+FPUnavailable:
+       EXCEPTION_PROLOG
+       bne     load_up_fpu             /* if from user, just load it up */
+       li      r20,MSR_KERNEL
+       bl      transfer_to_handler     /* if from kernel, take a trap */
+       .long   KernelFP
+       .long   int_return
+
+/* Decrementer */
+#ifdef CONFIG_PREP
+/* - ignored for now... */
 _ORG(0x0900)
-/* TRACE_TRAP(0x900) */
-       mtspr   SPR0,r1
+       mtspr   SPRG0,r1
        lis     r1,0x7FFF
        ori     r1,r1,0xFFFF
        mtspr   DEC,r1
-       mfspr   r1,SPR0
-#if 0  
-       SYNC
-#endif 
+       mfspr   r1,SPRG0
        rfi
-       
-_ORG(0x0A00)
-DEFAULT_TRAP(0x0A00)   
-_ORG(0x0B00)
-DEFAULT_TRAP(0x0B00)
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_PMAC
+       STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+#endif /* CONFIG_PMAC */
 
-/*
- * System call
- */
-_ORG(0x0C00)
-       b       SystemCall
+       STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+       STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+
+/* System call */
+       . = 0xc00
+SystemCall:
+       EXCEPTION_PROLOG
+       stw     r3,ORIG_GPR3(r21)
+       li      r20,MSR_KERNEL
+       rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
+       bl      transfer_to_handler
+       .long   DoSyscall
+       .long   int_return
 
-_ORG(0x0D00)
-       b       SingleStep
+/* Single step - not used on 601 */
+       STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
 
-_ORG(0x0E00)
-DEFAULT_TRAP(0x0E00)   
-_ORG(0x0F00)
-DEFAULT_TRAP(0x0F00)   
+       STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+       STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
 
 /*
- * Handle TLB Miss on an instruction load
+ * Handle TLB miss for instruction on 603/603e.
+ * Note: we get an alternate set of r0 - r3 to use automatically.
  */
-_ORG(0x1000)
-/* Note: It is *unsafe* to use the TRACE TRAP macro here since there */
-/* could be a 'trace' in progress when the TLB miss occurs.          */
-/* TRACE_TRAP(0x1000) */
-       b       InstructionTLBMiss
+       . = 0x1000
+InstructionTLBMiss:
+       mfctr   r0              /* Need to save this - CTR can't be touched! */
+       mfspr   r2,HASH1        /* Get PTE pointer */
+       mfspr   r3,ICMP         /* Partial item compare value */
+00:    li      r1,8            /* 8 items / bucket */
+       mtctr   r1
+       subi    r2,r2,8         /* Preset pointer */
+10:    lwzu    r1,8(r2)        /* Get next PTE */
+       cmp     0,r1,r3         /* Found entry yet? */
+       bdnzf   2,10b           /* Jump back if not, until CTR==0 */
+       bne     30f             /* Try secondary hash if CTR==0 */
+       lwz     r1,4(r2)        /* Get second word of entry */
+20:    mtctr   r0              /* Restore CTR */
+       mfspr   r3,SRR1         /* Need to restore CR0 */
+       mtcrf   0x80,r3
+       mfspr   r0,IMISS        /* Set to update TLB */
+       mtspr   RPA,r1
+       tlbli   r0
+       rfi                     /* All done */
+/* Secondary hash */
+30:    andi.   r1,r3,0x40      /* Already doing secondary hash? */
+       bne     InstructionAddressInvalid /* Yes - item not in hash table */
+       mfspr   r2,HASH2        /* Get hash table pointer */
+       ori     r3,r3,0x40      /* Set secondary hash */
+       b       00b             /* Try lookup again */
+InstructionAddressInvalid:
+       mfspr   r3,SRR1
+       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
+       addis   r1,r1,0x4000    /* Set bit 1 -> PTE not found */
+       mtspr   DSISR,r1
+       mtctr   r0              /* Restore CTR */
+       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
+       or      r2,r2,r1
+       mtspr   SRR1,r2
+       mfspr   r1,IMISS        /* Get failing address */
+       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
+       beq     20f             /* Jump if big endian */
+       xori    r1,r1,3
+20:    mtspr   DAR,r1          /* Set fault address */
+       mfmsr   r0              /* Restore "normal" registers */
+       xoris   r0,r0,MSR_TGPR>>16
+       mtcrf   0x80,r3         /* Restore CR0 */
+       sync                    /* Some chip revs have problems here... */
+       mtmsr   r0
+       b       InstructionAccess
 
 /*
- * Handle TLB Miss on a data item load
+ * Handle TLB miss for DATA Load operation on 603/603e
  */
-_ORG(0x1100)
-/* TRACE_TRAP(0x1100) */
-       b       DataLoadTLBMiss
+       . = 0x1100
+DataLoadTLBMiss:
+       mfctr   r0              /* Need to save this - CTR can't be touched! */
+       mfspr   r2,HASH1        /* Get PTE pointer */
+       mfspr   r3,DCMP         /* Partial item compare value */
+00:    li      r1,8            /* 8 items / bucket */
+       mtctr   r1
+       subi    r2,r2,8         /* Preset pointer */
+10:    lwzu    r1,8(r2)        /* Get next PTE */
+       cmp     0,r1,r3         /* Found entry yet? */
+       bdnzf   2,10b           /* Jump back if not, until CTR==0 */
+       bne     30f             /* Try secondary hash if CTR==0 */
+       lwz     r1,4(r2)        /* Get second word of entry */
+20:    mtctr   r0              /* Restore CTR */
+       mfspr   r3,SRR1         /* Need to restore CR0 */
+       mtcrf   0x80,r3
+       mfspr   r0,DMISS        /* Set to update TLB */
+       mtspr   RPA,r1
+       tlbld   r0
+       rfi                     /* All done */
+/* Secondary hash */
+30:    andi.   r1,r3,0x40      /* Already doing secondary hash? */
+       bne     DataAddressInvalid /* Yes - item not in hash table */
+       mfspr   r2,HASH2        /* Get hash table pointer */
+       ori     r3,r3,0x40      /* Set secondary hash */
+       b       00b             /* Try lookup again */
+DataAddressInvalid:
+       mfspr   r3,SRR1
+       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
+       addis   r1,r1,0x4000    /* Set bit 1 -> PTE not found */
+       mtspr   DSISR,r1
+       mtctr   r0              /* Restore CTR */
+       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
+       mtspr   SRR1,r2
+       mfspr   r1,DMISS        /* Get failing address */
+       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
+       beq     20f             /* Jump if big endian */
+       xori    r1,r1,3
+20:    mtspr   DAR,r1          /* Set fault address */
+       mfmsr   r0              /* Restore "normal" registers */
+       xoris   r0,r0,MSR_TGPR>>16
+       mtcrf   0x80,r3         /* Restore CR0 */
+       sync                    /* Some chip revs have problems here... */
+       mtmsr   r0
+       b       DataAccess
 
 /*
- * Handle TLB Miss on a store operation
+ * Handle TLB miss for DATA Store on 603/603e
  */
-_ORG(0x1200)
-/* TRACE_TRAP(0x1200) */
-       b       DataStoreTLBMiss
-
-_ORG(0x1300)
-InstructionAddressBreakpoint:
-       DEFAULT_TRAP(0x1300)
+       . = 0x1200
+DataStoreTLBMiss:
+       mfctr   r0              /* Need to save this - CTR can't be touched! */
+       mfspr   r2,HASH1        /* Get PTE pointer */
+       mfspr   r3,DCMP         /* Partial item compare value */
+00:    li      r1,8            /* 8 items / bucket */
+       mtctr   r1
+       subi    r2,r2,8         /* Preset pointer */
+10:    lwzu    r1,8(r2)        /* Get next PTE */
+       cmp     0,r1,r3         /* Found entry yet? */
+       bdnzf   2,10b           /* Jump back if not, until CTR==0 */
+       bne     30f             /* Try secondary hash if CTR==0 */
+       lwz     r1,4(r2)        /* Get second word of entry */
+20:    mtctr   r0              /* Restore CTR */
+       mfspr   r3,SRR1         /* Need to restore CR0 */
+       mtcrf   0x80,r3
+       mfspr   r0,DMISS        /* Set to update TLB */
+       mtspr   RPA,r1
+       tlbld   r0
+       rfi                     /* All done */  
+/* Secondary hash */
+30:    andi.   r1,r3,0x40      /* Already doing secondary hash? */
+       bne     DataAddressInvalid /* Yes - item not in hash table */
+       mfspr   r2,HASH2        /* Get hash table pointer */
+       ori     r3,r3,0x40      /* Set secondary hash */
+       b       00b                     /* Try lookup again */
 
-_ORG(0x1400)
-SystemManagementInterrupt:
-       DEFAULT_TRAP(0x1400)
+/* Instruction address breakpoint exception (on 603/604) */
+       STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
+
+/* System management exception (603?) */
+       STD_EXCEPTION(0x1400, Trap_14, UnknownException)
+
+       STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+       STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+       STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+       STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+       STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+       STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+       STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+       STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+       STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+       STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+       STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+
+/* Run mode exception */
+       STD_EXCEPTION(0x2000, RunMode, RunModeException)
+
+       STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+       STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+       STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+       STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+       STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+       STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+       STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+       STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+       STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+       STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+       STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+       STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+       STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+       STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+       STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+       . = 0x3000
 
-_ORG(0x1500)
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception, turning
+ * on address translation.
+ */
+       .globl  transfer_to_handler
+transfer_to_handler:
+       stw     r22,_NIP(r21)
+       stw     r23,_MSR(r21)
+       SAVE_GPR(7, r21)
+       SAVE_4GPRS(8, r21)
+       SAVE_8GPRS(12, r21)
+       SAVE_8GPRS(24, r21)
+       andi.   r23,r23,MSR_PR
+       mfspr   r23,SPRG3               /* if from user, fix up tss */
+       beq     2f
+#ifdef CONFIG_PMAC     
+       lwz     r24,GPR1(r21)
+       stw     r22,LAST_PC(r23)
+       stw     r24,USER_STACK(r23)
+#endif /* CONFIG_PMAC */
+       addi    r24,r1,STACK_FRAME_OVERHEAD
+       stw     r24,PT_REGS(r23)
+2:     addi    r2,r23,-TSS             /* set r2 to current */
+       addis   r2,r2,KERNELBASE@h
+       mflr    r23
+       andi.   r24,r23,0x3f00          /* get vector offset */
+       stw     r24,TRAP(r21)
+       li      r22,0
+       stw     r22,RESULT(r21)
+       lwz     r24,0(r23)              /* virtual address of handler */
+       lwz     r23,4(r23)              /* where to go when done */
+       mtspr   SRR0,r24
+       mtspr   SRR1,r20
+       mtlr    r23
+       SYNC
+       rfi                             /* jump to handler, enable MMU */
 
 /*
- * This space [buffer] is used to forceably flush the data cache when
- * running in copyback mode.  This is necessary IFF the data cache could
- * contain instructions for which the instruction cache has stale data.
- * Since the instruction cache NEVER snoops the data cache, memory must
- * be made coherent with the data cache to insure that the instruction
- * cache gets a valid instruction stream.  Note that this flushing is
- * only performed when switching from system to user mode since this is
- * the only juncture [as far as the OS goes] where the data cache may
- * contain instructions, e.g. after a disk read.
+ * Continuation of the floating-point unavailable handler.
  */
-#define NUM_CACHE_LINES 128*4
-#define CACHE_LINE_SIZE 32 
-cache_flush_buffer:
-       .space  NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
+load_up_fpu:
+       bl      giveup_fpu_unmapped
+       ori     r23,r23,MSR_FP          /* enable use of FP after return */
+       mfspr   r5,SPRG3                /* current task's TSS (phys) */
+       lfd     fr0,TSS_FPSCR-4(r5)
+       mtfsf   0xff,fr0
+       REST_32FPRS(0, r5)
+
+/* use last_task_used_math instead of fpu_tss */
+       lis     r3,last_task_used_math@h/*a*/
+       addis   r3,r3,-KERNELBASE@h
+       subi    r4,r5,TSS
+       addis   r4,r4,KERNELBASE@h
+       stw     r4,last_task_used_math@l(r3)
+#if 0  
+       lis     r3,fpu_tss@ha
+       addis   r4,r5,KERNELBASE@h
+       addis   r3,r3,-KERNELBASE@h
+       stw     r4,fpu_tss@l(r3)
+#endif 
+       /* restore registers and return */
+       lwz     r3,_CCR(r21)
+       lwz     r4,_LINK(r21)
+       mtcrf   0xff,r3
+       mtlr    r4
+       REST_GPR(1, r21)
+       REST_4GPRS(3, r21)
+       /* we haven't used ctr or xer */
+       mtspr   SRR1,r23
+       mtspr   SRR0,r22
+       REST_GPR(20, r21)
+       REST_2GPRS(22, r21)
+       lwz     r21,GPR21(r21)
+       SYNC
+       rfi
 
-#if NUM_CACHE_LINES < 512      
-_ORG(0x4000)
-#endif
+/*
+ * Load a PTE into the hash table, if possible.
+ * The address is in r3, and r4 contains access flags:
+ * _PAGE_USER (4) if a user-mode access, ored with
+ * _PAGE_RW (2) if a write.  r20 contains DSISR or SRR1,
+ * so bit 1 (0x40000000) is set if the exception was due
+ * to no matching PTE being found in the hash table.
+ * r5 contains the physical address of the current task's tss.
+ *
+ * Returns to the caller if the access is illegal or there is no
+ * mapping for the address.  Otherwise it places an appropriate PTE
+ * in the hash table and returns from the exception.
+ * Uses r0, r2 - r6, ctr, lr.
+ *
+ * For speed, 4 of the instructions get patched once the size and
+ * physical address of the hash table are known.  These definitions
+ * of Hash_base and Hash_bits below are just an example.
+ */
+Hash_base = 0x180000
+Hash_bits = 12                         /* e.g. 256kB hash table */
+Hash_msk = (((1 << Hash_bits) - 1) * 64)
+
+       .globl  hash_page
+hash_page:
+       /* Get PTE (linux-style) and check access */
+       lwz     r5,PG_TABLES(r5)        /* task's page tables */
+       lis     r2,-KERNELBASE@h
+       add     r5,r5,r2                /* convert to phys addr */
+       rlwimi  r5,r3,12,20,29          /* insert top 10 bits of address */
+       lwz     r5,0(r5)                /* get pmd entry */
+       rlwinm. r5,r5,0,0,19            /* extract address of pte page */
+       beqlr-                          /* return if no mapping */
+       add     r2,r5,r2
+       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
+       lwz     r6,0(r2)                /* get linux-style pte */
+       ori     r4,r4,1                 /* set _PAGE_PRESENT bit in access */
+       andc.   r0,r4,r6                /* check access & ~permission */
+       bnelr-                          /* return if access not permitted */
+       ori     r6,r6,0x100             /* set _PAGE_ACCESSED in pte */
+       rlwinm  r5,r4,5,24,24           /* _PAGE_RW access -> _PAGE_DIRTY */
+       rlwimi  r5,r4,7,22,22           /* _PAGE_RW -> _PAGE_HWWRITE */
+       or      r6,r6,r5
+       stw     r6,0(r2)                /* update PTE (accessed/dirty bits) */
+
+       /* Convert linux-style PTE to low word of PPC-style PTE */
+       rlwinm  r4,r6,32-9,31,31        /* _PAGE_HWWRITE -> PP lsb */
+       rlwimi  r6,r6,32-1,31,31        /* _PAGE_USER -> PP (both bits now) */
+       ori     r4,r4,0xe04             /* clear out reserved bits */
+       andc    r6,r6,r4                /* PP=2 or 0, when _PAGE_HWWRITE */
+
+       /* Construct the high word of the PPC-style PTE */
+       mfsrin  r5,r3                   /* get segment reg for segment */
+       rlwinm  r5,r5,7,1,24            /* put VSID in 0x7fffff80 bits */
+       oris    r5,r5,0x8000            /* set V (valid) bit */
+       rlwimi  r5,r3,10,26,31          /* put in API (abbrev page index) */
+
+       /* Get the address of the primary PTE group in the hash table */
+       .globl  hash_page_patch_A
+hash_page_patch_A:
+       lis     r4,Hash_base@h          /* base address of hash table */
+       rlwimi  r4,r5,32-1,26-Hash_bits,25      /* (VSID & hash_mask) << 6 */
+       rlwinm  r0,r3,32-6,26-Hash_bits,25      /* (PI & hash_mask) << 6 */
+       xor     r4,r4,r0                /* make primary hash */
+
+       /* See whether it was a PTE not found exception or a
+          protection violation. */
+       andis.  r0,r20,0x4000
+       li      r2,8                    /* PTEs/group */
+       bne     10f                     /* no PTE: go look for an empty slot */
+       tlbie   r3                      /* invalidate TLB entry */
+
+       /* Search the primary PTEG for a PTE whose 1st word matches r5 */
+       mtctr   r2
+       addi    r3,r4,-8
+1:     lwzu    r0,8(r3)                /* get next PTE */
+       cmp     0,r0,r5
+       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
+       beq+    found_slot
+
+       /* Search the secondary PTEG for a matching PTE */
+       ori     r5,r5,0x40              /* set H (secondary hash) bit */
+       .globl  hash_page_patch_B
+hash_page_patch_B:
+       xoris   r3,r4,Hash_msk>>16      /* compute secondary hash */
+       xori    r3,r3,0xffc0
+       addi    r3,r3,-8
+       mtctr   r2
+2:     lwzu    r0,8(r3)
+       cmp     0,r0,r5
+       bdnzf   2,2b
+       beq+    found_slot
+       xori    r5,r5,0x40              /* clear H bit again */
+
+       /* Search the primary PTEG for an empty slot */
+10:    mtctr   r2
+       addi    r3,r4,-8                /* search primary PTEG */
+1:     lwzu    r0,8(r3)                /* get next PTE */
+       cmpi    0,r0,0                  /* empty? */
+       bdnzf   2,1b                    /* loop while ctr != 0 && !cr0.eq */
+       beq+    found_empty
+
+       /* Search the secondary PTEG for an empty slot */
+       ori     r5,r5,0x40              /* set H (secondary hash) bit */
+       .globl  hash_page_patch_C
+hash_page_patch_C:
+       xoris   r3,r4,Hash_msk>>16      /* compute secondary hash */
+       xori    r3,r3,0xffc0
+       addi    r3,r3,-8
+       mtctr   r2
+2:     lwzu    r0,8(r3)
+       cmpi    0,r0,0
+       bdnzf   2,2b
+       beq+    found_empty
+
+       /* Choose an arbitrary slot in the primary PTEG to overwrite */
+       xori    r5,r5,0x40              /* clear H bit again */
+       lwz     r2,next_slot@l(0)
+       addi    r2,r2,8
+       andi.   r2,r2,0x38
+       stw     r2,next_slot@l(0)
+       add     r3,r4,r2
+
+       /* Store PTE in PTEG */
+found_empty:
+       stw     r5,0(r3)
+found_slot:
+       stw     r6,4(r3)
+       SYNC
+       /* Return from the exception */
+       lwz     r3,_CCR(r21)
+       lwz     r4,_LINK(r21)
+       lwz     r5,_CTR(r21)
+       mtcrf   0xff,r3
+       mtlr    r4
+       mtctr   r5
+       REST_GPR(0, r21)
+       REST_2GPRS(1, r21)
+       REST_4GPRS(3, r21)
+       /* we haven't used xer */
+       mtspr   SRR1,r23
+       mtspr   SRR0,r22
+       REST_GPR(20, r21)
+       REST_2GPRS(22, r21)
+       lwz     r21,GPR21(r21)
+       SYNC
+       rfi
 
+next_slot:
+       .long   0
 
-/* changed to use r3 as residual pointer (as firmware does), that's all -- Cort */
 /*
- * Hardware reset [actually from bootstrap]
- * Initialize memory management & call secondary init
- * Registers initialized by bootstrap:
- *   R11: Start of command line string
- *   R12: End of command line string
- *   R28: Residual data
- *   R29: Total Memory Size
- *   R30: 'BeBx' if this is a BeBox
- */    
-Reset:
-       lis     r7,0xF000               /* To mask upper 4 bits */
-/* set pointer to residual data */
-       lis     r1,resptr@h
-       ori     r1,r1,resptr@l
-       andc    r1,r1,r7
-/* changed to use r3 as residual pointer (as firmware does) -- Cort */
-/* this is only a ptr, the actual data is copied in mmu_init */
-       stw     r3,0(r1)
-       
-/* Copy argument string */
-       li      r0,0            /* Null terminate string */
-       stb     r0,0(r12)
-       lis     r1,cmd_line@h
-       ori     r1,r1,cmd_line@l
-       andc    r1,r1,r7        /* No MMU yet - need unmapped address */
-       subi    r1,r1,1
-       subi    r11,r11,1
-00:    lbzu    r0,1(r11)
-       cmpi    0,r0,0
-       stbu    r0,1(r1)
-       bne     00b
+ * This is where the main kernel code starts.
+ */
 
-#define IS_BE_BOX      0x42654278      /* 'BeBx' */
-       lis     r1,isBeBox@h
-       ori     r1,r1,isBeBox@l
-       andc    r1,r1,r7
-/* See if this is a CPU other than CPU#1 */
-/* This [currently] happens on the BeBox */
-       lwz     r2,0(r1)
-       cmpi    0,r2,0
-       bne     Reset_BeBox_CPU1
-/* Save machine type indicator */
-       li      r2,0
-       lis     r3,IS_BE_BOX>>16
-       ori     r3,r3,IS_BE_BOX&0xFFFF
-       cmp     0,r30,r3
-       bne     00f
-       li      r2,1
-       mr      r11,r28
-       mr      r12,r29
-       lis     r5,BeBox_CPU1_vector@h
-       ori     r5,r5,BeBox_CPU1_vector@l
-       andc    r5,r5,r7                /* Tell CPU #1 where to go */
-00:    stw     r2,0(r1)
-       stw     r30,4(r1)
-       
+start_here:
+       /*
+        * Enable caches and 604-specific features if necessary.
+        */
+       mfspr   r9,PVR
+       rlwinm  r9,r9,16,16,31
+       cmpi    0,r9,1
+       beq     4f                      /* not needed for 601 */
+       mfspr   r7,HID0
+       andi.   r0,r7,HID0_DCE
+       ori     r7,r7,HID0_ICE|HID0_DCE
+       ori     r8,r7,HID0_ICFI
+       bne     3f                      /* don't invalidate the D-cache */
+       ori     r8,r8,HID0_DCI          /* unless it wasn't enabled */
+3:     sync
+       mtspr   HID0,r8                 /* enable and invalidate caches */
+       sync
+       mtspr   HID0,r7                 /* enable caches */
+       sync
+       isync
+       cmpi    0,r9,4                  /* check for 604 */
+       cmpi    1,r9,9                  /* or 604e */
+       cror    2,2,6
+       bne     4f
+       ori     r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+       mtspr   HID0,r7                 /* superscalar exec & br history tbl */
+4:
+       /* ptr to current */
+       lis     r2,init_task_union@h
+       ori     r2,r2,init_task_union@l
+       /* ptr to phys current tss */
+       addis   r3,r2,-KERNELBASE@h
+       addi    r3,r3,TSS       /* init task's TSS */
+       mtspr   SPRG3,r3
+       /* stack */
+       addi    r1,r2,TASK_UNION_SIZE
+       li      r0,0
+       stwu    r0,-STACK_FRAME_OVERHEAD(r1)
+
+       /* Clear out the BSS */
+       lis     r7,_end@ha
+       addi    r7,r7,_end@l
+       lis     r8,__bss_start@ha
+       addi    r8,r8,__bss_start@l
+       subf    r7,r8,r7
+       addi    r7,r7,3
+       rlwinm. r7,r7,30,2,31
+       beq     2f
+       addi    r8,r8,-4
+       mtctr   r7
+       li      r0,0
+3:     stwu    r0,4(r8)
+       bdnz    3b
+2:
+/*
+ * Initialize the prom stuff (powermacs only) and the MMU.
+ */
+#ifdef CONFIG_PMAC
+       bl      prom_init
+#endif /* CONFIG_PMAC */
+       bl      MMU_init
 
-#if 0  
-       lis     r1,sys_stack@h
-       ori     r1,r1,sys_stack@l
-#else
-       lis     r1,init_kernel_stack@h
-       ori     r1,r1,init_kernel_stack@l
-#endif
-       addi    r1,r1,0x1000    /* top of stack */
-#if 0  
-       li      r2,0x0FFF       /* Mask stack address down to page boundary */
+/*
+ * Go back to running unmapped so we can load up new values
+ * for SDR1 (hash table pointer) and the segment registers
+ * and change to using our exception vectors.
+ */
+       lis     r6,_SDR1@ha
+       lwz     r6,_SDR1@l(r6)
+       li      r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+       lis     r4,2f@h
+       addis   r4,r4,-KERNELBASE@h
+       ori     r4,r4,2f@l
+       mtspr   SRR0,r4
+       mtspr   SRR1,r3
+       rfi
+/* Load up the kernel context */
+2:
+#ifdef CONFIG_PREP
+       /* reload the bats now that MMU_init() has setup them up -- Cort */
+       LOAD_BATS(r3,r0)
 #endif
-       andc    r1,r1,r2
-       subi    r1,r1,INT_FRAME_SIZE    /* Padding for first frame */
-       li      r2,0            /* TOC pointer for nanokernel */
-       li      r0,MSR_         /* Make sure FPU enabled */
-       mtmsr   r0
-       lis     r3,_edata@h     /* Clear BSS */
-       ori     r3,r3,_edata@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lis     r4,_end@h
-       ori     r4,r4,_end@l
-       andc    r4,r4,r7        /* make unmapped address */
-       subi    r3,r3,4
-       li      r0,0
-00:    stwu    r0,4(r3)
-       cmp     0,r3,r4
-       blt     00b
-#if 0  
-/* Save total memory size (passed from bootstrap) */
-       lis     r3,_TotalMemory@h
-       ori     r3,r3,_TotalMemory@l
-       andc    r3,r3,r7        /* make unmapped address */
-       stw     r29,0(r3)
-#endif 
-/* Initialize BAT registers */
-       lis     r3,BAT0@h
-       ori     r3,r3,BAT0@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r0,0(r3)
+
+       SYNC                    /* Force all PTE updates to finish */
+       tlbia                   /* Clear all TLB entries */
+       mtspr   SDR1,r6
+       li      r0,16           /* load up segment register values */
+       mtctr   r0              /* for context 0 */
+       lis     r3,0x2000       /* Ku = 1, VSID = 0 */
+       li      r4,0
+3:     mtsrin  r3,r4
+       addi    r3,r3,1         /* increment VSID */
+       addis   r4,r4,0x1000    /* address of next segment */
+       bdnz    3b
+#ifdef CONFIG_PMAC
+       li      r0,0            /* zot the BATs */
+#if 1
        mtspr   IBAT0U,r0
-       mtspr   DBAT0U,r0
-       lwz     r0,4(r3)
        mtspr   IBAT0L,r0
+       mtspr   DBAT0U,r0
        mtspr   DBAT0L,r0
-       lis     r3,BAT1@h
-       ori     r3,r3,BAT1@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r0,0(r3)
+#endif
        mtspr   IBAT1U,r0
-       mtspr   DBAT1U,r0
-       lwz     r0,4(r3)
        mtspr   IBAT1L,r0
+       mtspr   DBAT1U,r0
        mtspr   DBAT1L,r0
-/* this BAT mapping will cover all of kernel space */
-#ifdef NEWMM
-       lis     r3,BAT2@h
-       ori     r3,r3,BAT2@l
-#else
-       lis     r3,TMP_BAT2@h
-       ori     r3,r3,TMP_BAT2@l
-#endif
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r0,0(r3)
        mtspr   IBAT2U,r0
-       mtspr   DBAT2U,r0
-       lwz     r0,4(r3)
        mtspr   IBAT2L,r0
+       mtspr   DBAT2U,r0
        mtspr   DBAT2L,r0
-#if 1
-       lis     r3,BAT3@h
-       ori     r3,r3,BAT3@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r0,0(r3)
        mtspr   IBAT3U,r0
-       mtspr   DBAT3U,r0
-       lwz     r0,4(r3)
        mtspr   IBAT3L,r0
+       mtspr   DBAT3U,r0
        mtspr   DBAT3L,r0
-#endif 
-/* Now we can turn on the MMU */
-       mfmsr   r3
-       ori     r3,r3,MSR_DR|MSR_IR
-       mtspr   SRR1,r3
-       lis     r3,10f@h
-       ori     r3,r3,10f@l
-       mtspr   SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0000)      
-       SYNC
-       rfi                             /* enables MMU */
-10:            bl      _EXTERN(MMU_init)       /* initialize MMU environment */
-DO_RFI_TRACE_MAPPED(0xDEAD0100)        
-/* Withdraw BAT2->RAM mapping */
-       lis     r7,0xF000               /* To mask upper 4 bits */
-       lis     r3,20f@h
-       ori     r3,r3,20f@l
-       andc    r3,r3,r7        /* make unmapped address */
-       mtspr   SRR0,r3
-       mfmsr   r3
-       li      r4,MSR_DR|MSR_IR
-       andc    r3,r3,r4
-       mtspr   SRR1,r3
-       SYNC
-DO_RFI_TRACE_MAPPED(0xDEAD0200)        
-       SYNC
-       rfi
-20:
-
-DO_RFI_TRACE_UNMAPPED(0xDEAD0400)      
-20:    lis     r3,BAT2@h
-       ori     r3,r3,BAT2@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r0,0(r3)
-       mtspr   IBAT2U,r0
-       mtspr   DBAT2U,r0
-       lwz     r0,4(r3)
-       mtspr   IBAT2L,r0
-       mtspr   DBAT2L,r0
-/* Load up the kernel context */
-       lis     r2,init_task@h
-       ori     r2,r2,init_task@l
-       addi    r2,r2,TSS
-       andc    r2,r2,r7        /* make unmapped address */
-       SYNC                    /* Force all PTE updates to finish */
-       tlbia                   /* Clear all TLB entries */
-       lis     r3,_SDR1@h
-       ori     r3,r3,_SDR1@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r3,0(r3)
-       mtspr   SDR1,r3
-       lwz     r0,MMU_SEG0(r2)
-       mtsr    SR0,r0
-       lwz     r0,MMU_SEG1(r2)
-       mtsr    SR1,r0
-       lwz     r0,MMU_SEG2(r2)
-       mtsr    SR2,r0
-       lwz     r0,MMU_SEG3(r2)
-       mtsr    SR3,r0
-       lwz     r0,MMU_SEG4(r2)
-       mtsr    SR4,r0
-       lwz     r0,MMU_SEG5(r2)
-       mtsr    SR5,r0
-       lwz     r0,MMU_SEG6(r2)
-       mtsr    SR6,r0
-       lwz     r0,MMU_SEG7(r2)
-       mtsr    SR7,r0
-       lwz     r0,MMU_SEG8(r2)
-       mtsr    SR8,r0
-       lwz     r0,MMU_SEG9(r2)
-       mtsr    SR9,r0
-       lwz     r0,MMU_SEG10(r2)
-       mtsr    SR10,r0
-       lwz     r0,MMU_SEG11(r2)
-       mtsr    SR11,r0
-       lwz     r0,MMU_SEG12(r2)
-       mtsr    SR12,r0
-       lwz     r0,MMU_SEG13(r2)
-       mtsr    SR13,r0
-       lwz     r0,MMU_SEG14(r2)
-       mtsr    SR14,r0
-       lwz     r0,MMU_SEG15(r2)
-       mtsr    SR15,r0
+#endif
 /* Now turn on the MMU for real! */
-       mfmsr   r3
-       ori     r3,r3,MSR_DR|MSR_IR
-       mtspr   SRR1,r3
-       lis     r3,30f@h
-       ori     r3,r3,30f@l
+       li      r4,MSR_KERNEL
+       lis     r3,start_kernel@h
+       ori     r3,r3,start_kernel@l
        mtspr   SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0500)      
-       SYNC
-       rfi                             /* enables MMU */
-30:
-/* Turn on L1 Data Cache */
-       mfspr   r3,HID0         /* Caches are controlled by this register */
-       ori     r4,r3,(HID0_ICE|HID0_ICFI)
-       ori     r3,r3,(HID0_ICE)
-       ori     r4,r4,(HID0_DCE|HID0_DCI)
-       ori     r3,r3,(HID0_DCE)
-       sync
-       mtspr   HID0,r4
-       mtspr   HID0,r3
-/* L1 cache enable */
-       mfspr   r2,PVR                  /* Check for 603/603e */
-       srwi    r2,r2,16
-       cmpi    0,r2,4                  /* 604 */
-       bne     40f
-       mfspr   r3,HID0                 /* Turn on 604 specific features */
-       ori     r3,r3,(HID0_SIED|HID0_BHTE)
-       mtspr   HID0,r3
-40:    b       _EXTERN(start_kernel)           /* call main code */
-       .long   0               # Illegal!
+       mtspr   SRR1,r4
+       rfi                     /* enable MMU and jump to start_kernel */
 
+#ifdef CONFIG_PREP
 /*
- * BeBox CPU #2 runs here
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader.  The expected layout
+ * of the regs is:     
+ *   R3: End of image
+ *   R4: Start of image - 0x400
+ *   R11: Start of command line string
+ *   R12: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort     
  */
-Reset_BeBox_CPU1:      
-       lis     r1,CPU1_stack@h
-       ori     r1,r1,CPU1_stack@l
-       li      r2,0x0FFF       /* Mask stack address down to page boundary */
-       andc    r1,r1,r2
-       subi    r1,r1,INT_FRAME_SIZE    /* Padding for first frame */
-       lis     r30,CPU1_trace@h
-       ori     r30,r30,CPU1_trace@l
-       andc    r30,r30,r7
-       li      r5,1
-       stw     r5,0(r30)
-       li      r2,0            /* TOC pointer for nanokernel */
-       li      r0,MSR_         /* Make sure FPU enabled */
+       .globl __start
+__start:       
+       .globl _start
+_start:        
+       lis     r7,0xF000               /* To mask upper 4 bits */
+/* save pointer to residual data */
+       lis     r1,resptr@h
+       ori     r1,r1,resptr@l
+       addis   r1,r1,-KERNELBASE@h
+       stw     r3,0(r1)
+/* save argument string */
+       li      r0,0            /* Null terminate string */
+       stb     r0,0(r12)
+       lis     r1,cmd_line@h
+       ori     r1,r1,cmd_line@l
+       addis   r1,r1,-KERNELBASE@h
+       subi    r1,r1,1
+       subi    r11,r11,1
+00:    lbzu    r0,1(r11)
+       cmpi    0,r0,0
+       stbu    r0,1(r1)
+       bne     00b
+/* setup the msr with sane values */
+       li      r0,MSR_
        mtmsr   r0
-/* Initialize BAT registers */
-       lis     r3,BAT0@h
-       ori     r3,r3,BAT0@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r0,0(r3)
-       mtspr   IBAT0U,r0
-       mtspr   DBAT0U,r0
-       lwz     r0,4(r3)
-       mtspr   IBAT0L,r0
-       mtspr   DBAT0L,r0
-       lis     r3,BAT1@h
-       ori     r3,r3,BAT1@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r0,0(r3)
-       mtspr   IBAT1U,r0
-       mtspr   DBAT1U,r0
-       lwz     r0,4(r3)
-       mtspr   IBAT1L,r0
-       mtspr   DBAT1L,r0
-       lis     r3,TMP_BAT2@h
-       ori     r3,r3,TMP_BAT2@l
-       andc    r3,r3,r7        /* make unmapped address */
-       lwz     r0,0(r3)
-       mtspr   IBAT2U,r0
-       mtspr   DBAT2U,r0
-       lwz     r0,4(r3)
-       mtspr   IBAT2L,r0
-       mtspr   DBAT2L,r0
-/* Now we can turn on the MMU */
+/* turn on the mmu with bats covering kernel enough to get started */
+       LOAD_BATS(r3,r0)
        mfmsr   r3
        ori     r3,r3,MSR_DR|MSR_IR
        mtspr   SRR1,r3
        lis     r3,10f@h
        ori     r3,r3,10f@l
        mtspr   SRR0,r3
-       li      r5,2
-       stw     r5,0(r30)
        SYNC
        rfi                             /* enables MMU */
-10:
-       lis     r30,CPU1_trace@h
-       ori     r30,r30,CPU1_trace@l
-       li      r5,3
-       stw     r5,0(r30)
-       bl      _EXTERN(BeBox_CPU1)
-
-/*
- * Machine Check (Bus Errors, etc)
- */
-MachineCheck:  
-       TRACE_TRAP(0x0200)
-       SAVE_INT_REGS(0x0200)
-       mr      r3,r1           /* Set pointer to saved regs */
-       bl      _EXTERN(MachineCheckException)
-       RETURN_FROM_INT(0x0200)
-
-/*
- * Data Access exception
- */
-DataAccess:
-       SAVE_INT_REGS(0x0300)
-#if 1
-       mfspr   r3, DAR
-       mfspr   r4, DSISR
-       li      r5, 0           /* not a text fault */
-       mr      r6, r1
-       bl      _EXTERN(new_page_fault)
-#else
-       SAVE_PAGE_FAULT_REGS(0x0D00)    
-       mr      r3,r1
-       bl      _EXTERN(DataAccessException)
-#endif 
-       RETURN_FROM_INT(0x0300)
-
-/*
- * Instruction Access Exception
- */
-InstructionAccess:
-       SAVE_INT_REGS(0x0400)
-#if 1
-       mfspr   r3, SPR2 /* srr0 was saved here */
-       mfspr   r4, SPR3 /* srr1 was saved here */
-       li      r5, 1    /* a text fault */
-       mr      r6, r1
-       bl      _EXTERN(new_page_fault)
-#else
-       SAVE_PAGE_FAULT_REGS(0x0D00)    
-       mr      r3,r1
-       bl      _EXTERN(InstructionAccessException)
-#endif 
-       RETURN_FROM_INT(0x0400)
-
-/*
- * Hardware Interrupt
- */
-HardwareInterrupt:     
-       SAVE_INT_REGS(0x0500)
-       BUMP(__Hardware_Interrupts)
-       mr      r3,r1           /* Set pointer to saved regs */
-       bl      _EXTERN(handle_IRQ)
-       RETURN_FROM_INT(0x0500)
-
-/*
- * Alignment
- */
-Alignment:     
-       TRACE_TRAP(0x0600)
-       SAVE_INT_REGS(0x0600)
-       mr      r3,r1           /* Set pointer to saved regs */
-       bl      _EXTERN(AlignmentException)
-       RETURN_FROM_INT(0x0600)
-
+10:    lis     r7,start_here@ha        /* jump up to our copy at KERNELBASE */
+       addi    r7,r7,start_here@l
+       mtlr    r7
+       blr
+#endif /* CONFIG_PREP */
+       
 /*
- * Illegal instruction
+ * FP unavailable trap from kernel - print a message, but let
+ * the task use FP in the kernel until it returns to user mode.
  */
-ProgramCheck:
-       TRACE_TRAP(0x0700)
-       SAVE_INT_REGS(0x0700)
-       mr      r3,r1           /* Set pointer to saved regs */
-       bl      _EXTERN(ProgramCheckException)
-       RETURN_FROM_INT(0x0700)
+KernelFP:
+       lwz     r3,_MSR(r1)
+       ori     r3,r3,MSR_FP
+       stw     r3,_MSR(r1)             /* enable use of FP after return */
+       lis     r3,86f@h
+       ori     r3,r3,86f@l
+       mr      r4,r2                   /* current */
+       lwz     r5,_NIP(r1)
+       bl      printk
+       b       int_return
+86:    .string "floating point used in kernel (task=%p, pc=%x)\n"
+       .align  4
 
 /*
- * Single Step Exception
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ * (If giveup_fpu_unmapped uses any integer registers other than
+ * r3 - r6, the return code at load_up_fpu above will have
+ * to be adjusted.)
  */
-SingleStep:
-       SAVE_INT_REGS(0x0D00)
-       SAVE_PAGE_FAULT_REGS(0x0D00)
-       mr      r3,r1           /* Set pointer to saved regs */
-       bl      _EXTERN(SingleStepException)
-#if 0
-       bl      _EXTERN(flush_instruction_cache)
+giveup_fpu_unmapped:
+       lis     r6,-KERNELBASE@h
+       b       1f
+
+       .globl  giveup_fpu
+giveup_fpu:
+       li      r6,0
+1:
+       addis   r3,r6,last_task_used_math@h/*a*/
+       lwz     r4,last_task_used_math@l(r3)
+#if 0          
+       addis   r3,r6,fpu_tss@ha
+       lwz     r4,fpu_tss@l(r3)
 #endif 
-       RETURN_FROM_INT(0x0D00)
-
-/*
- * Floating point [not available, etc]
- */
-FloatingPointCheck:    
-       SAVE_INT_REGS(0x0800)
-       mr      r3,r1           /* Set pointer to saved regs */
-       bl      _EXTERN(FloatingPointCheckException)
-       cmpi    0,r3,MSR_FP    /* check if fp was turned on by handler */
-       bne     00f
-       RETURN_FROM_INT(0x0f0f) /* 0xf0f tells to restore fp regs */
-00:    RETURN_FROM_INT(0x0200)
+       mfmsr   r5
+       ori     r5,r5,MSR_FP
+       SYNC
+       mtmsr   r5                      /* enable use of fpu now */
+       SYNC
+       cmpi    0,r4,0
+       add     r4,r4,r6
+       beqlr                           /* if no previous owner, done */
+       addi    r4,r4,TSS               /* want TSS of last_task_used_math */
+       li      r5,0
+       stw     r5,last_task_used_math@l(r3)
+#if 0  
+       stw     r5,fpu_tss@l(r3)
+#endif
+       SAVE_32FPRS(0, r4)
+       mffs    fr0
+       stfd    fr0,TSS_FPSCR-4(r4)
+       lwz     r5,PT_REGS(r4)
+       lwz     r5,PT_REGS(r4)
+       add     r5,r5,r6
+       lwz     r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+       li      r4,MSR_FP
+       andc    r3,r3,r4                /* disable FP for previous task */
+       stw     r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+       blr
 
 /*
- * System Call exception
+ * Handle a system call.
  */
-SystemCall:
-       SAVE_INT_REGS(0x0C00)
-       lwz     r2,_CCR(r1)     /* Clear SO bit in CR */
-       lis     r9,0x1000
-       andc    r2,r2,r9
-       stw     r2,_CCR(r1)
+DoSyscall:
+       stw     r0,TSS+LAST_SYSCALL(r2)
+       lwz     r11,_CCR(r1)    /* Clear SO bit in CR */
+       lis     r10,0x1000
+       andc    r11,r11,r10
+       stw     r11,_CCR(r1)
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+       lis     r31,show_syscalls_task@ha
+       lwz     r31,show_syscalls_task@l(r31)
+       cmp     0,r2,r31
+       bne     1f
+#endif
+       lis     r3,7f@ha
+       addi    r3,r3,7f@l
+       lwz     r4,GPR0(r1)
+       lwz     r5,GPR3(r1)
+       lwz     r6,GPR4(r1)
+       lwz     r7,GPR5(r1)
+       lwz     r8,GPR6(r1)
+       mr      r9,r2
+       bl      printk
+       lwz     r0,GPR0(r1)
+       lwz     r3,GPR3(r1)
+       lwz     r4,GPR4(r1)
+       lwz     r5,GPR5(r1)
+       lwz     r6,GPR6(r1)
+       lwz     r7,GPR7(r1)
+       lwz     r8,GPR8(r1)
+1:
+#endif /* SHOW_SYSCALLS */
        cmpi    0,r0,0x7777     /* Special case for 'sys_sigreturn' */
-       bne+    10f
-       mr      r3,r1
-       bl      _EXTERN(sys_sigreturn)
-       cmpi    0,r3,0          /* Check for restarted system call */
-       bge     99f
-       b       20f
-10:    lis     r2,current_set@ha
-       lwz     r2,current_set@l(r2)
-       lwz     r2,TASK_FLAGS(r2)
-       andi.   r2,r2,PF_TRACESYS
-       bne     50f
-       
-       lis     r2,sys_call_table@h
-       ori     r2,r2,sys_call_table@l
+       beq-    10f
+       lwz     r10,TASK_FLAGS(r2)
+       andi.   r10,r10,PF_TRACESYS
+       bne-    50f
+       cmpli   0,r0,NR_syscalls
+       bge-    66f
+       lis     r10,sys_call_table@h
+       ori     r10,r10,sys_call_table@l
        slwi    r0,r0,2
-       lwzx    r2,r2,r0        /* Fetch system call handler [ptr] */
-#if 1
-       cmpi    0,r2,0          /* make sure syscall handler not 0 */
-       beq     99f
-       cmpi    0,r0,NR_syscalls<<2 /* make sure syscallnum in bounds */
-       bgt     99f
-#endif 
-       mtlr    r2
-       mr      r9,r1
+       lwzx    r10,r10,r0      /* Fetch system call handler [ptr] */
+       cmpi    0,r10,0
+       beq-    66f
+       mtlr    r10
+       addi    r9,r1,STACK_FRAME_OVERHEAD
        blrl                    /* Call handler */
-       
-20:    stw     r3,RESULT(r1)   /* Save result */       
-       cmpi    0,r3,0
-       bge     30f
+       .globl  syscall_ret_1
+syscall_ret_1:
+20:    stw     r3,RESULT(r1)   /* Save result */
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+       cmp     0,r2,r31
+       bne     91f
+#endif
+       mr      r4,r3
+       lis     r3,79f@ha
+       addi    r3,r3,79f@l
+       bl      printk
+       lwz     r3,RESULT(r1)
+91:
+#endif
+       li      r10,-_LAST_ERRNO
+       cmpl    0,r3,r10
+       blt     30f
        neg     r3,r3
        cmpi    0,r3,ERESTARTNOHAND
        bne     22f
        li      r3,EINTR
-22:    lwz     r2,_CCR(r1)     /* Set SO bit in CR */
-       oris    r2,r2,0x1000
-       stw     r2,_CCR(r1)
+22:    lwz     r10,_CCR(r1)    /* Set SO bit in CR */
+       oris    r10,r10,0x1000
+       stw     r10,_CCR(r1)
 30:    stw     r3,GPR3(r1)     /* Update return value */
-       b       99f
+       b       int_return
+66:    li      r3,ENOSYS
+       b       22b
+/* sys_sigreturn */
+10:    addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      _EXTERN(sys_sigreturn)
+       cmpi    0,r3,0          /* Check for restarted system call */
+       bge     int_return
+       b       20b
 /* Traced system call support */
 50:    bl      _EXTERN(syscall_trace)
        lwz     r0,GPR0(r1)     /* Restore original registers */
@@ -1045,369 +1149,371 @@ SystemCall:
        lwz     r7,GPR7(r1)
        lwz     r8,GPR8(r1)
        lwz     r9,GPR9(r1)
-       lis     r2,sys_call_table@h
-       ori     r2,r2,sys_call_table@l
+       cmpli   0,r0,NR_syscalls
+       bge-    66f
+       lis     r10,sys_call_table@h
+       ori     r10,r10,sys_call_table@l
        slwi    r0,r0,2
-       lwzx    r2,r2,r0        /* Fetch system call handler [ptr] */
-       mtlr    r2
-       mr      r9,r1
+       lwzx    r10,r10,r0      /* Fetch system call handler [ptr] */
+       cmpi    0,r10,0
+       beq-    66f
+       mtlr    r10
+       addi    r9,r1,STACK_FRAME_OVERHEAD
        blrl                    /* Call handler */
+       .globl  syscall_ret_2
+syscall_ret_2:
        stw     r3,RESULT(r1)   /* Save result */       
-       cmpi    0,r3,0
-       bge     60f
+       stw     r3,GPR0(r1)     /* temporary gross hack to make strace work */
+       li      r10,-_LAST_ERRNO
+       cmpl    0,r3,r10
+       blt     60f
        neg     r3,r3
        cmpi    0,r3,ERESTARTNOHAND
        bne     52f
        li      r3,EINTR
-52:    lwz     r2,_CCR(r1)     /* Set SO bit in CR */
-       oris    r2,r2,0x1000
-       stw     r2,_CCR(r1)
+52:    lwz     r10,_CCR(r1)    /* Set SO bit in CR */
+       oris    r10,r10,0x1000
+       stw     r10,_CCR(r1)
 60:    stw     r3,GPR3(r1)     /* Update return value */
        bl      _EXTERN(syscall_trace)
-99:
-       RETURN_FROM_INT(0x0C00)
-
-/*
- * Handle TLB miss for instruction
- */
-InstructionTLBMiss:
-       BUMP_UNMAPPED(__Instruction_TLB_Misses)
-       mfctr   r0              /* Need to save this - CTR can't be touched! */
-       mfspr   r2,HASH1        /* Get PTE pointer */
-       mfspr   r3,ICMP         /* Partial item compare value */
-00:    li      r1,8            /* 8 items / bucket */
-       mtctr   r1
-       subi    r2,r2,8         /* Preset pointer */
-10:    lwzu    r1,8(r2)        /* Get next PTE */
-       cmp     0,r1,r3         /* Found entry yet? */
-       bdne    10b             /* Jump back if not, until CTR==0 */
-       bne     30f             /* Try secondary hash if CTR==0 */
-       lwz     r1,4(r2)        /* Get second word of entry */
-#if 0  
-       andi.   r3,r1,0x08      /* Check guard bit - invalid access if set */
-       bne     InstructionFetchError
-#endif 
-       andi.   r3,r1,0x100     /* Check R bit (referenced) */
-       bne     20f             /* If set, all done */
-       ori     r1,r1,0x100     /* Set bit */
-       stw     r1,4(r2)        /* Update memory image */
-20:    mtctr   r0              /* Restore CTR */
-       mfspr   r3,SRR1         /* Need to restore CR0 */
-       mtcrf   0x80,r3
-       mfspr   r0,IMISS        /* Set to update TLB */
-       mtspr   RPA,r1
-       tlbli   r0
-#if 0  
-       SYNC
+       b       int_return
+66:    li      r3,ENOSYS
+       b       52b
+#ifdef SHOW_SYSCALLS
+7:     .string "syscall %d(%x, %x, %x, %x), current=%p\n"
+79:    .string " -> %x\n"
+       .align  2
 #endif
-       rfi                     /* All done */
-/* Secondary hash */
-30:    andi.   r1,r3,0x40      /* Already doing secondary hash? */
-       bne     InstructionAddressInvalid /* Yes - item not in hash table */
-       mfspr   r2,HASH2        /* Get hash table pointer */
-       ori     r3,r3,0x40      /* Set secondary hash */
-       b       00b                     /* Try lookup again */
 
 /*
- * Handle TLB miss for DATA Load operation
+ * This routine switches between two different tasks.  The process
+ * state of one is saved on its kernel stack.  Then the state
+ * of the other is restored from its kernel stack.  The memory
+ * management hardware is updated to the second process's state.
+ * Finally, we can return to the second process, via int_return.
+ * On entry, r3 points to the TSS for the current task, r4
+ * points to the TSS for the new task, and r5 contains the
+ * MMU context number for the new task.
+ *
+ * Note: there are two ways to get to the "going out" portion
+ * of this code; either by coming in via the entry (_switch)
+ * or via "fork" which must set up an environment equivalent
+ * to the "_switch" path.  If you change this (or in particular, the
+ * SAVE_REGS macro), you'll have to change the fork code also.
+ *
+ * The code which creates the new task context is in 'copy_thread'
+ * in arch/ppc/kernel/process.c
  */    
-DataLoadTLBMiss:
-       mfctr   r0              /* Need to save this - CTR can't be touched! */
-       mfspr   r2,HASH1        /* Get PTE pointer */
-       mfspr   r3,DCMP         /* Partial item compare value */
-00:    li      r1,8            /* 8 items / bucket */
-       mtctr   r1
-       subi    r2,r2,8         /* Preset pointer */
-10:    lwzu    r1,8(r2)        /* Get next PTE */
-       cmp     0,r1,r3         /* Found entry yet? */
-       bdne    10b             /* Jump back if not, until CTR==0 */
-       bne     30f             /* Try secondary hash if CTR==0 */
-       lwz     r1,4(r2)        /* Get second word of entry */
-       andi.   r3,r1,0x100     /* Check R bit (referenced) */
-       ori     r1,r1,0x100     /* Set bit */
-       bne     20f             /* If set, all done */
-       stw     r1,4(r2)        /* Update memory image */
-20:    mtctr   r0              /* Restore CTR */
-       mfspr   r3,SRR1         /* Need to restore CR0 */
-       mtcrf   0x80,r3
-       mfspr   r0,DMISS        /* Set to update TLB */
-       mtspr   RPA,r1
-/*     SYNC() */
-       tlbld   r0
-#if 0  
+_GLOBAL(_switch)
+       stwu    r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+       stw     r0,GPR0(r1)
+       lwz     r0,0(r1)
+       stw     r0,GPR1(r1)
+       SAVE_10GPRS(2, r1)
+       SAVE_10GPRS(12, r1)
+       SAVE_10GPRS(22, r1)
+       mflr    r20             /* Return to switch caller */
+       mfmsr   r22
+       li      r0,MSR_FP       /* Disable floating-point */
+       andc    r22,r22,r0
+       stw     r20,_NIP(r1)
+       stw     r22,_MSR(r1)
+       stw     r20,_LINK(r1)
+       mfcr    r20
+       mfctr   r22
+       mfspr   r23,XER
+       stw     r20,_CCR(r1)
+       stw     r22,_CTR(r1)
+       stw     r23,_XER(r1)
+       li      r0,0x0ff0
+       stw     r0,TRAP(r1)
+       stw     r1,KSP(r3)      /* Set old stack pointer */
+       sync
+       addis   r0,r4,-KERNELBASE@h
+       mtspr   SPRG3,r0        /* Update current TSS phys addr */
+       SYNC
+       lwz     r1,KSP(r4)      /* Load new stack pointer */
+       addi    r2,r4,-TSS      /* Update current */
+       /* Set up segment registers for new task */
+       rlwinm  r5,r5,4,8,27    /* VSID = context << 4 */
+       addis   r5,r5,0x6000    /* Set Ks, Ku bits */
+       li      r0,8            /* TASK_SIZE / SEGMENT_SIZE */
+       mtctr   r0
+       li      r3,0
+3:     mtsrin  r5,r3
+       addi    r5,r5,1         /* next VSID */
+       addis   r3,r3,0x1000    /* address of next segment */
+       bdnz    3b
        SYNC
-#endif 
-       rfi                     /* All done */
-/* Secondary hash */
-30:    andi.   r1,r3,0x40      /* Already doing secondary hash? */
-       bne     DataAddressInvalid /* Yes - item not in hash table */
-       mfspr   r2,HASH2        /* Get hash table pointer */
-       ori     r3,r3,0x40      /* Set secondary hash */
-       b       00b                     /* Try lookup again */
+
+/* FALL THROUGH into int_return */
 
 /*
- * Handle TLB miss for DATA STORE
+ * Trap exit.
  */
-DataStoreTLBMiss:
-       BUMP_UNMAPPED(__DataStore_TLB_Misses)
-       mfctr   r0              /* Need to save this - CTR can't be touched! */
-       mfspr   r2,HASH1        /* Get PTE pointer */
-       mfspr   r3,DCMP         /* Partial item compare value */
-00:    li      r1,8            /* 8 items / bucket */
-       mtctr   r1
-       subi    r2,r2,8         /* Preset pointer */
-10:    lwzu    r1,8(r2)        /* Get next PTE */
-       cmp     0,r1,r3         /* Found entry yet? */
-       bdne    10b             /* Jump back if not, until CTR==0 */
-       bne     30f             /* Try secondary hash if CTR==0 */
-       lwz     r1,4(r2)        /* Get second word of entry */
-       andi.   r3,r1,0x80      /* Check C bit (changed) */
-#if 0 /* Note: no validation */
-       beq     40f             /* If not set (first time) validate access */
-#else
-       ori     r1,r1,0x180     /* Set changed, accessed */
-       bne     20f
-       stw     r1,4(r2)
-#endif 
-20:    mtctr   r0              /* Restore CTR */
-       mfspr   r3,SRR1         /* Need to restore CR0 */
-       mtcrf   0x80,r3
-       mfspr   r0,DMISS        /* Set to update TLB */
-       mtspr   RPA,r1
-       tlbld   r0
-#if 0  
+       .globl  int_return
+int_return:
+0:     mfmsr   r30             /* Disable interrupts */
+       li      r4,0
+       ori     r4,r4,MSR_EE
+       andc    r30,r30,r4
+       SYNC                    /* Some chip revs need this... */
+       mtmsr   r30
        SYNC
-#endif 
-       rfi                     /* All done */  
-/* Secondary hash */
-30:    andi.   r1,r3,0x40      /* Already doing secondary hash? */
-       bne     DataAddressInvalid /* Yes - item not in hash table */
-       mfspr   r2,HASH2        /* Get hash table pointer */
-       ori     r3,r3,0x40      /* Set secondary hash */
-       b       00b                     /* Try lookup again */
-/* PTE found - validate access */
-40:    rlwinm. r3,r1,30,0,1    /* Extract PP bits */
-       bge-    50f             /* Jump if PP=0,1 */
-       andi.   r3,r1,1
-       beq+    70f             /* Access OK */
-       b       WriteProtectError       /* Not OK - fail! */
-50:    mfspr   r3,SRR1         /* Check privilege */
+       lwz     r5,_MSR(r1)
+       and.    r5,r5,r4
+       beq     2f
+3:     lis     r4,lost_interrupts@ha
+       lwz     r4,lost_interrupts@l(r4)
+       cmpi    0,r4,0
+       beq+    1f
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      handle_IRQ
+       b       3b
+1:     lis     r4,bh_mask@ha
+       lwz     r4,bh_mask@l(r4)
+       lis     r5,bh_active@ha
+       lwz     r5,bh_active@l(r5)
+       and.    r4,r4,r5
+       beq+    2f
+       ori     r31,r30,MSR_EE  /* re-enable interrupts */
+       SYNC
+       mtmsr   r31
+       SYNC
+       bl      _EXTERN(do_bottom_half)
+       SYNC
+       mtmsr   r30             /* disable interrupts again */
+       SYNC
+2:     lwz     r3,_MSR(r1)     /* Returning to user mode? */
        andi.   r3,r3,MSR_PR
-       beq+    60f             /* Jump if supervisor mode */
-       mfspr   r3,DMISS        /* Get address */
-       mfsrin  r3,r3           /* Get segment register */
-       andis.  r3,r3,0x2000    /* If Kp==0, OK */
-       beq+    70f
-       b       WriteProtectError       /* Bad access */
-60:    mfspr   r3,DMISS        /* Get address */
-       mfsrin  r3,r3           /* Get segment register */
-       andis.  r3,r3,0x4000    /* If Ks==0, OK */
-       beq+    70f
-       b       WriteProtectError       /* Bad access */
-70:    ori     r1,r1,0x180     /* Set changed, accessed */
-       stw     r1,4(r2)        /* Update PTE in memory */
-       b       20b
-       
+       beq+    10f             /* no - no need to mess with stack */
+       lis     r3,need_resched@ha
+       lwz     r3,need_resched@l(r3)
+       cmpi    0,r3,0          /* check need_resched flag */
+       beq+    7f
+       bl      _EXTERN(schedule)
+       b       0b
+7:     lwz     r3,BLOCKED(r2)  /* Check for pending unblocked signals */
+       lwz     r5,SIGNAL(r2)
+       andc.   r0,r5,r3        /* Lets thru any unblocked */
+       beq+    8f
+       addi    r4,r1,STACK_FRAME_OVERHEAD
+       bl      _EXTERN(do_signal)
+       b       0b
+8:     addi    r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD    /* size of frame */
+       stw     r4,TSS+KSP(r2)  /* save kernel stack pointer */
+10:
+       lwz     r2,_CTR(r1)
+       lwz     r0,_LINK(r1)
+       mtctr   r2
+       mtlr    r0
+       lwz     r2,_XER(r1)
+       lwz     r0,_CCR(r1)
+       mtspr   XER,r2
+       mtcrf   0xFF,r0
+       REST_10GPRS(3, r1)
+       REST_10GPRS(13, r1)
+       REST_8GPRS(23, r1)
+       REST_GPR(31, r1)
+       lwz     r2,_NIP(r1)     /* Restore environment */
+       lwz     r0,_MSR(r1)
+       mtspr   SRR0,r2
+       mtspr   SRR1,r0
+       lwz     r0,GPR0(r1)
+       lwz     r2,GPR2(r1)
+       lwz     r1,GPR1(r1)
+       SYNC
+       rfi
+
 /*
- * These routines are error paths/continuations of the exception
- * handlers above.  They are placed here to avoid the problems
- * of only 0x100 bytes per exception handler.
+ * Fake an interrupt from kernel mode.
+ * This is used when enable_irq loses an interrupt.
+ * We only fill in the stack frame minimally.
  */
-/* Invalid address */
-InstructionAddressInvalid:
-       mfspr   r3,SRR1
-       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
-       addis   r1,r1,0x4000    /* Set bit 1 -> PTE not found */
-       b       10f
-
-/* Fetch from guarded or no-access page */
-InstructionFetchError:
-       mfspr   r3,SRR1
-       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
-       addis   r1,r1,0x0800    /* Set bit 4 -> protection error */
-10:    mtspr   DSISR,r1
-       mtctr   r0              /* Restore CTR */
-       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
-       mtspr   SRR1,r2
-       mfspr   r1,IMISS        /* Get failing address */
-       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
-       beq     20f             /* Jump if big endian */
-       xori    r1,r1,3
-20:    mtspr   DAR,r1          /* Set fault address */
-       mfmsr   r0              /* Restore "normal" registers */
-       xoris   r0,r0,MSR_TGPR>>16
-       mtcrf   0x80,r3         /* Restore CR0 */
-       ori     r0,r0,MSR_FP    /* Need to keep FP enabled */
-       sync                    /* Some chip revs have problems here... */
-       mtmsr   r0
-       b       InstructionAccess
-
-/* Invalid address */
-DataAddressInvalid:
-       mfspr   r3,SRR1
-       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
-       addis   r1,r1,0x4000    /* Set bit 1 -> PTE not found */
-       b       10f
+_GLOBAL(fake_interrupt)
+       mflr    r0
+       stw     r0,4(r1)
+       stwu    r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+       stw     r0,_NIP(r1)
+       stw     r0,_LINK(r1)
+       mfmsr   r3
+       stw     r3,_MSR(r1)
+       li      r0,0x0fac
+       stw     r0,TRAP(r1)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      handle_IRQ
+       addi    r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+       lwz     r0,4(r1)
+       mtlr    r0
+       blr
 
-/* Write to read-only space */
-WriteProtectError:
-       mfspr   r3,SRR1
-       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
-       addis   r1,r1,0x0800    /* Set bit 4 -> protection error */
-10:    mtspr   DSISR,r1
-       mtctr   r0              /* Restore CTR */
-       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
-       mtspr   SRR1,r2
-       mfspr   r1,DMISS        /* Get failing address */
-       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
-       beq     20f             /* Jump if big endian */
-       xori    r1,r1,3
-20:    mtspr   DAR,r1          /* Set fault address */
-       mfmsr   r0              /* Restore "normal" registers */
-       xoris   r0,r0,MSR_TGPR>>16
-       mtcrf   0x80,r3         /* Restore CR0 */
-       ori     r0,r0,MSR_FP    /* Need to keep FP enabled */
-       sync                    /* Some chip revs have problems here... */
-       mtmsr   r0
-       b       DataAccess
+/*
+ * Set up the segment registers for a new context.
+ */
+_GLOBAL(set_context)
+       rlwinm  r3,r3,4,8,27    /* VSID = context << 4 */
+       addis   r3,r3,0x6000    /* Set Ks, Ku bits */
+       li      r0,8            /* TASK_SIZE / SEGMENT_SIZE */
+       mtctr   r0
+       li      r4,0
+3:     mtsrin  r3,r4
+       addi    r3,r3,1         /* next VSID */
+       addis   r4,r4,0x1000    /* address of next segment */
+       bdnz    3b
+       SYNC
+       blr
 
 /*
- * Flush instruction cache
- * *** I'm really paranoid here!
+ * Flush instruction cache.
+ * This is a no-op on the 601.
  */
 _GLOBAL(flush_instruction_cache)
-       mflr    r5
-       bl      _EXTERN(flush_data_cache)
-       mfspr   r3,HID0 /* Caches are controlled by this register */
-       li      r4,0
-       ori     r4,r4,(HID0_ICE|HID0_ICFI)
-       or      r3,r3,r4        /* Need to enable+invalidate to clear */
+       mfspr   r3,PVR
+       rlwinm  r3,r3,16,16,31
+       cmpi    0,r3,1
+       beqlr                   /* for 601, do nothing */
+       /* 603/604 processor - use invalidate-all bit in HID0 */
+       mfspr   r3,HID0
+       ori     r3,r3,HID0_ICFI
        mtspr   HID0,r3
-       andc    r3,r3,r4
-       ori     r3,r3,HID0_ICE  /* Enable cache */
-       mtspr   HID0,r3
-       mtlr    r5
+       SYNC
        blr
 
 /*
- * Flush data cache
- * *** I'm really paranoid here!
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * store_cache_range(unsigned long start, unsigned long stop)
  */
-_GLOBAL(flush_data_cache)
-       BUMP(__Cache_Flushes)
-       lis     r3,cache_is_copyback@ha
-       lwz     r3,cache_is_copyback@l(r3)
-       cmpi    0,r3,0
-       beq     10f
-/* When DATA CACHE is copy-back */
-       lis     r3,cache_flush_buffer@h
-       ori     r3,r3,cache_flush_buffer@l
-       li      r4,NUM_CACHE_LINES
+CACHE_LINE_SIZE = 32
+LG_CACHE_LINE_SIZE = 5
+_GLOBAL(store_cache_range)
+       mfspr   r5,PVR
+       rlwinm  r5,r5,16,16,31
+       cmpi    0,r5,1
+       beqlr                           /* for 601, do nothing */
+       li      r5,CACHE_LINE_SIZE-1
+       andc    r3,r3,r5
+       subf    r4,r3,r4
+       add     r4,r4,r5
+       srwi.   r4,r4,LG_CACHE_LINE_SIZE
+       beqlr
+       mtctr   r4
+       mr      r6,r3
+1:     dcbst   0,r3
+       addi    r3,r3,CACHE_LINE_SIZE
+       bdnz    1b
+       sync                            /* wait for dcbst's to get to ram */
        mtctr   r4
-00:    dcbz    0,r3                    /* Flush cache line with minimal BUS traffic */
-       addi    r3,r3,CACHE_LINE_SIZE   /* Next line, please */
-       bdnz    00b     
-10:    blr
+2:     icbi    0,r6
+       addi    r6,r6,CACHE_LINE_SIZE
+       bdnz    2b
+       sync
+       isync
+       blr
 
 /*
  * Flush a particular page from the DATA cache
  * Note: this is necessary because the instruction cache does *not*
  * snoop from the data cache.
- *     void flush_page(void *page)
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ *     void flush_page_to_ram(void *page)
  */
-_GLOBAL(flush_page)
+_GLOBAL(flush_page_to_ram)
+       mfspr   r5,PVR
+       rlwinm  r5,r5,16,16,31
+       cmpi    0,r5,1
+       beqlr                           /* for 601, do nothing */
        li      r4,0x0FFF
        andc    r3,r3,r4                /* Get page base address */
        li      r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
        mtctr   r4
-00:    dcbf    0,r3                    /* Clear line */
-       icbi    0,r3
+       mr      r6,r3
+0:     dcbst   0,r3                    /* Write line to ram */
        addi    r3,r3,CACHE_LINE_SIZE
-       bdnz    00b
+       bdnz    0b
+       sync
+       mtctr   r4
+1:     icbi    0,r6
+       addi    r6,r6,CACHE_LINE_SIZE
+       bdnz    1b
+       sync
+       isync
        blr
 
 /*
- * This routine switches between two different tasks.  The process
- * state of one is saved on its kernel stack.  Then the state
- * of the other is restored from its kernel stack.  The memory
- * management hardware is updated to the second process's state.
- * Finally, we can return to the second process, via the 'return'.
- *
- * Note: there are two ways to get to the "going out" portion
- * of this code; either by coming in via the entry (_switch)
- * or via "fork" which must set up an environment equivalent
- * to the "_switch" path.  If you change this (or in particular, the
- * SAVE_ALL_REGS macro), you'll have to change the fork code also.
+ * Flush entries from the hash table with VSIDs in the range
+ * given.
+ */
+_GLOBAL(flush_hash_segments)
+       rlwinm  r3,r3,7,1,24            /* put VSID lower limit in position */
+       oris    r3,r3,0x8000            /* set V bit */
+       rlwinm  r4,r4,7,1,24            /* put VSID upper limit in position */
+       oris    r4,r4,0x8000
+       ori     r4,r4,0x7f
+       lis     r5,Hash@ha
+       lwz     r5,Hash@l(r5)           /* base of hash table */
+       lis     r6,Hash_size@ha
+       lwz     r6,Hash_size@l(r6)      /* size in bytes */
+       srwi    r6,r6,3                 /* # PTEs */
+       mtctr   r6
+       addi    r5,r5,-8
+       li      r0,0
+1:     lwzu    r6,8(r5)                /* get next tag word */
+       cmplw   0,r6,r3
+       cmplw   1,r6,r4
+       cror    0,0,5                   /* set cr0.lt if out of range */
+       blt     2f                      /* branch if out of range */
+       stw     r0,0(r5)                /* invalidate entry */
+2:     bdnz    1b                      /* continue with loop */
+       sync
+       tlbia
+       isync
+       blr
+
+/*
+ * Flush the entry for a particular page from the hash table.
  *
- * The code which creates the new task context is in 'copy_thread'
- * in arch/ppc/kernel/process.c
- */    
-_GLOBAL(_switch)
-       mtspr   SPR0,r1         /* SAVE_ALL_REGS prologue */
-       mtspr   SPR1,r2
-       mflr    r2              /* Return to switch caller */
-       mtspr   SPR2,r2
-       mfmsr   r2
-       mtspr   SPR3,r2
-       SAVE_ALL_REGS(0x0FF0)
-       SAVE_FP_REGS()
-       CHECK_STACK()
-       SYNC()
-       stw     r1,KSP(r3)      /* Set old stack pointer */
-       BUMP(__Context_Switches)
-       lwz     r1,KSP(r4)      /* Load new stack pointer */
-       lwz     r0,MMU_SEG0(r4)
-       mtsr    SR0,r0
-       lwz     r0,MMU_SEG1(r4)
-       mtsr    SR1,r0
-       lwz     r0,MMU_SEG2(r4)
-       mtsr    SR2,r0
-       lwz     r0,MMU_SEG3(r4)
-       mtsr    SR3,r0
-       lwz     r0,MMU_SEG4(r4)
-       mtsr    SR4,r0
-       lwz     r0,MMU_SEG5(r4)
-       mtsr    SR5,r0
-       lwz     r0,MMU_SEG6(r4)
-       mtsr    SR6,r0
-       lwz     r0,MMU_SEG7(r4)
-       mtsr    SR7,r0
-#if 0
-       /* segs 8-15 are shared by everyone -- don't need to be changed */
-       lwz     r0,MMU_SEG8(r4)
-       mtsr    SR8,r0
-       lwz     r0,MMU_SEG9(r4)
-       mtsr    SR9,r0
-       lwz     r0,MMU_SEG10(r4)
-       mtsr    SR10,r0
-       lwz     r0,MMU_SEG11(r4)
-       mtsr    SR11,r0
-       lwz     r0,MMU_SEG12(r4)
-       mtsr    SR12,r0
-       lwz     r0,MMU_SEG13(r4)
-       mtsr    SR13,r0
-       lwz     r0,MMU_SEG14(r4)
-       mtsr    SR14,r0
-       lwz     r0,MMU_SEG15(r4)
-       mtsr    SR15,r0
-#endif
-       /* no need to invalidate tlb since each process has a distinct
-          set of vsid's.        -- Cort */
-#if 0    
-       tlbia                           /* Invalidate entire TLB */
-       BUMP(__TLBIAs)
-#endif 
-       /* p5.2 603 users manual - with addr transl. enabled, 
-          the memory access is performed under the control of 
-          the page table entry.  I interpret this to mean that
-          it is tagged with the vsid -- so no need to flush here
-          since each process has a distinct set of vsid's.
-          Of course, my intepretation may be wrong.
-                     -- Cort */
-       /*bl    _EXTERN(flush_instruction_cache)*/
-       RETURN_FROM_INT(0x0f0f)
-       
+ * flush_hash_page(unsigned context, unsigned long va)
+ */
+_GLOBAL(flush_hash_page)
+       rlwinm  r3,r3,11,1,20           /* put context into vsid */
+       rlwimi  r3,r4,11,21,24          /* put top 4 bits of va into vsid */
+       oris    r3,r3,0x8000            /* set V (valid) bit */
+       rlwimi  r3,r4,10,26,31          /* put in API (abbrev page index) */
+       rlwinm  r7,r4,32-6,10,25        /* get page index << 6 */
+       rlwinm  r5,r3,32-1,7,25         /* vsid << 6 */
+       xor     r7,r7,r5                /* primary hash << 6 */
+       lis     r5,Hash_mask@ha
+       lwz     r5,Hash_mask@l(r5)      /* hash mask */
+       slwi    r5,r5,6                 /*  << 6 */
+       and     r7,r7,r5
+       lis     r6,Hash@ha
+       lwz     r6,Hash@l(r6)           /* hash table base */
+       add     r6,r6,r7                /* address of primary PTEG */
+       li      r8,8
+       mtctr   r8
+       addi    r7,r6,-8
+1:     lwzu    r0,8(r7)                /* get next PTE */
+       cmpw    0,r0,r3                 /* see if tag matches */
+       bdnzf   2,1b                    /* while --ctr != 0 && !cr0.eq */
+       beq     3f                      /* if we found it */
+       ori     r3,r3,0x40              /* set H (alt. hash) bit */
+       xor     r6,r6,r5                /* address of secondary PTEG */
+       mtctr   r8
+       addi    r7,r6,-8
+2:     lwzu    r0,8(r7)                /* get next PTE */
+       cmpw    0,r0,r3                 /* see if tag matches */
+       bdnzf   2,2b                    /* while --ctr != 0 && !cr0.eq */
+       bne     4f                      /* if we didn't find it */
+3:     li      r0,0
+       stw     r0,0(r7)                /* invalidate entry */
+4:     sync
+       tlbie   r4                      /* in hw tlb too */
+       isync
+       blr
 
 /*
  * This routine is just here to keep GCC happy - sigh...
@@ -1415,18 +1521,212 @@ _GLOBAL(_switch)
 _GLOBAL(__main)
        blr
 
+#ifdef CONFIG_PMAC
+/*
+ * These exception handlers are used when we have called a prom
+ * routine after we have taken over the exception vectors and MMU.
+ */
+       .globl  prom_exc_table
+prom_exc_table:
+       .long   TOPHYS(prom_exception)          /* 0 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 400 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 800 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* c00 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 1000 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 1400 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 1800 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 1c00 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 1000 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 1400 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 1800 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)          /* 1c00 */
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+       .long   TOPHYS(prom_exception)
+
+/*
+ * When we come in to these prom exceptions, r1 and lr have been
+ * saved in sprg1 and sprg2, and lr points to a word containing
+ * the vector offset.
+ */
+prom_exception:
+       mr      r1,r21                  /* save r21 */
+       lis     r21,prom_sp@ha          /* get a stack to use */
+       addis   r21,r21,-KERNELBASE@h
+       lwz     r21,prom_sp@l(r21)
+       addis   r21,r21,-KERNELBASE@h   /* convert to physical addr */
+       subi    r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD
+       stw     r0,GPR0(r21)
+       stw     r2,GPR2(r21)
+       stw     r3,GPR3(r21)
+       stw     r4,GPR4(r21)
+       stw     r5,GPR5(r21)
+       stw     r6,GPR6(r21)
+       stw     r20,GPR20(r21)
+       stw     r1,GPR21(r21)
+       stw     r22,GPR22(r21)
+       stw     r23,GPR23(r21)
+       mfspr   r1,SPRG1
+       stw     r1,GPR1(r21)
+       mfcr    r3
+       mfspr   r4,SPRG2
+       stw     r3,_CCR(r21)
+       stw     r4,_LINK(r21)
+       mfctr   r3
+       mfspr   r4,XER
+       stw     r3,_CTR(r21)
+       stw     r4,_XER(r21)
+       mfspr   r22,SRR0
+       mfspr   r23,SRR1
+
+       /* at this point we have set things up pretty much exactly
+          how EXCEPTION_PROLOG does */
+       mflr    r3
+       lwz     r3,0(r3)                /* get exception vector */
+       stw     r3,TRAP(r21)
+       cmpi    0,r3,0x300              /* was it a dsi? */
+       bne     1f
+
+       mfspr   r20,DSISR               /* here on data access exc. */
+       andis.  r0,r20,0x8470           /* weird error? */
+       bne     3f                      /* if not, try to put a PTE */
+       mfspr   r3,DAR                  /* into the hash table */
+       rlwinm  r4,r23,32-13,30,30      /* MSR_PR -> _PAGE_USER */
+       rlwimi  r4,r20,32-23,29,29      /* DSISR_STORE -> _PAGE_RW */
+       b       2f
+
+1:     cmpi    0,r3,0x400              /* was it an isi? */
+       bne     3f
+       andis.  r0,r23,0x4000           /* if so, check if no pte found */
+       beq     3f                      /* if so, try to put a PTE */
+       mr      r3,r22                  /* into the hash table */
+       rlwinm  r4,r23,32-13,30,30      /* MSR_PR -> _PAGE_USER */
+       mr      r20,r23                 /* SRR1 has reason bits */
+2:     lis     r5,prom_tss@ha          /* phys addr of TSS */
+       addis   r5,r5,-KERNELBASE@h
+       lwz     r5,prom_tss@l(r5)
+       bl      hash_page
+
+3:     addis   r1,r21,KERNELBASE@h     /* restore kernel stack ptr */
+       addi    r3,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+       stw     r3,0(r21)               /* set stack chain pointer */
+       lis     r5,prom_tss@ha
+       addis   r5,r5,-KERNELBASE@h
+       lwz     r5,prom_tss@l(r5)
+       mtspr   SPRG3,r5                /* reset phys TSS pointer */
+       lwz     r4,TRAP(r21)            /* the real exception vector */
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r20,MSR_KERNEL
+       bl      transfer_to_handler
+       .long   PromException
+       .long   prom_int_return
+
+       .comm   prom_sp,4
+       .comm   prom_tss,4
+
+       .globl  prom_int_return
+prom_int_return:
+       lis     r3,prom_exc_table@ha    /* restore sprg3 for prom vectors */
+       addi    r3,r3,prom_exc_table@l
+       addis   r3,r3,-KERNELBASE@h
+       mtspr   SPRG3,r3
+       b       int_return
+
+/*
+ * When entering the prom, we have to change to using a different
+ * set of exception vectors.
+ */
+       .globl  enter_prom
+enter_prom:
+       stwu    r1,-32(r1)
+       mflr    r0
+       stw     r0,36(r1)
+       stw     r29,20(r1)
+       stw     r30,24(r1)
+       stw     r31,28(r1)
+       lis     r8,prom_entry@ha
+       lwz     r8,prom_entry@l(r8)
+       mfmsr   r31
+       andi.   r0,r31,MSR_IP           /* using our own vectors yet? */
+       beq     1f                      /* if so, have to switch */
+       mtlr    r8
+       blrl                            /* if not, can just charge ahead */
+       b       2f
+1:     lis     r9,prom_sp@ha           /* save sp for exception handler */
+       stw     r1,prom_sp@l(r9)
+       mfspr   r29,SPRG3               /* save physical tss pointer */
+       lis     r9,prom_tss@ha
+       stw     r29,prom_tss@l(r9)
+       li      r9,0
+       ori     r9,r9,MSR_EE
+       andc    r30,r31,r9
+       lis     r9,prom_exc_table@ha    /* set pointer to exception table */
+       addi    r9,r9,prom_exc_table@l
+       addis   r9,r9,-KERNELBASE@h
+       ori     r0,r31,MSR_IP
+       sync
+       mtmsr   r30                     /* disable interrupts */
+       mtspr   SPRG3,r9                /* while we update MSR_IP and sprg3 */
+       sync
+       mtmsr   r0                      /* start using exc. vectors in prom */
+       mtlr    r8
+       blrl                            /* call prom */
+       sync
+       mtmsr   r30                     /* disable interrupts again */
+       mtspr   SPRG3,r29               /* while we restore MSR_IP and sprg3 */
+       sync
+       mtmsr   r31                     /* reenable interrupts */
+2:     lwz     r0,36(r1)
+       mtlr    r0
+       lwz     r29,20(r1)
+       lwz     r30,24(r1)
+       lwz     r31,28(r1)
+       lwz     r1,0(r1)
+       blr
+#endif
+
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
        .data
        .globl  sdata
 sdata:
        .space  2*4096
-
-#if 0
-_GLOBAL(sys_stack)
-sys_stack:
-       .space  4096
-#endif
-CPU1_stack:    
-
        .globl  empty_zero_page
 empty_zero_page:
        .space  4096
@@ -1435,6 +1735,7 @@ empty_zero_page:
 swapper_pg_dir:
        .space  4096    
 
+#ifdef CONFIG_PREP
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
  * Used to pass parameters into the kernel like root=/dev/sda1, etc.
@@ -1442,54 +1743,5 @@ swapper_pg_dir:
        .globl  cmd_line
 cmd_line:
        .space  512
-       
-#ifdef STATS   
-/*
- * Miscellaneous statistics - gathered just for performance info
- */
-       .globl  _INTR_stats
-_INTR_stats:
-       .globl __Instruction_TLB_Misses
-__Instruction_TLB_Misses:
-       .long   0,0     /* Instruction TLB misses */
-       .globl __DataLoad_TLB_Misses
-__DataLoad_TLB_Misses:
-       .long   0,0     /* Data [load] TLB misses */
-       .globl __DataStore_TLB_Misses
-__DataStore_TLB_Misses:
-       .long   0,0     /* Data [store] TLB misses */
-       .globl __Instruction_Page_Faults
-__Instruction_Page_Faults:     
-       .long   0,0     /* Instruction page faults */
-       .globl __Data_Page_Faults
-__Data_Page_Faults:    
-       .long   0,0     /* Data page faults */
-       .globl __Cache_Flushes
-__Cache_Flushes:       
-       .long   0,0     /* Explicit cache flushes */
-       .globl __Context_Switches
-__Context_Switches:    
-       .long   0,0     /* Context switches */
-       .globl __Hardware_Interrupts
-__Hardware_Interrupts: 
-       .long   0,0     /* I/O interrupts (disk, timer, etc) */
-       .globl  __TLBIAs
-       .globl __TLBIAs
-__TLBIAs:
-       .long   0,0     /* TLB cache forceably flushed */
-       .globl  __TLBIEs
-__TLBIEs:
-       .long   0,0     /* Specific TLB entry flushed */        
-#endif
-
-       .globl  _TotalMemory
-_TotalMemory:
-       .long   0,0     
-       
-/*
- * This location is used to break any outstanding "lock"s when
- * changing contexts.
- */
-_break_lwarx:  .long   0
-       
+#endif /* CONFIG_PREP */
 
index 41d453186c909e469f92d0f74e33417f44906b94..171bfaa5c3ea39745c2b3837fd2b09b050bada65 100644 (file)
@@ -1,9 +1,13 @@
 /*
- *     linux/arch/ppc/kernel/irq.c
+ *  arch/ppc/kernel/irq.c
  *
- *     Copyright (C) 1992 Linus Torvalds
- *      Adapted from arch/i386 by Gary Thomas
- *      Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *  Power Macintosh version
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Derived from arch/i386/kernel/irq.c
+ *    Copyright (C) 1992 Linus Torvalds
+ *  Adapted from arch/i386 by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu) 
  *
  * This file contains the code used by various IRQ handling routines:
  * asking for different IRQ's should be done through these routines
@@ -11,7 +15,7 @@
  * shouldn't result in any weird surprises, and installing new handlers
  * should be easier.
  */
-
+       
 /*
  * IRQ's are in fact implemented a bit like signal handlers for the kernel.
  * Naturally it's not a 1:1 relation, but there are similarities.
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
+#include <linux/config.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
-inline int get_irq_list(char *);
-void check_irq(void);
-void BeBox_CPU1(void);
-void BeBox_state(void);
-int BeBox_irq(void);
-void show_BeBox_state(void);
-void BeBox_enable_irq(int );
-void BeBox_disable_irq(int );
-void BeBox_init_IRQ(void);
-void _do_bottom_half(void);
-static _NOP(void);
-static _delay(void);
-void hard_disk_LED(int state);
+#define IRQ_FLAG       ((unsigned *)0xf3000020)
+#define IRQ_ENABLE     ((unsigned *)0xf3000024)
+#define IRQ_ACK                ((unsigned *)0xf3000028)
+#define IRQ_LEVEL      ((unsigned *)0xf300002c)
+
+#define KEYBOARD_IRQ   20      /* irq number for command-power interrupt */
 
+#undef SHOW_IRQ 1
 
-#define SHOW_IRQ
-#undef  SHOW_IRQ
+unsigned lost_interrupts = 0;
+
+unsigned int local_irq_count[NR_CPUS];
+static struct irqaction irq_action[32];
 
 /*
- * For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
- * and 16..31 for other BeBox motherboard type interrupts.
+ * This contains the irq mask for both irq controllers
  */
-unsigned long isBeBox[];
-unsigned char *BeBox_IO_page;
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_21      (((char *)(&cached_irq_mask))[0])
+#define cached_A1      (((char *)(&cached_irq_mask))[1])
+
 
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
+int __ppc_bh_counter;
 
-void disable_irq(unsigned int irq_nr)
+void *null_handler(int,void *,struct pt_regs *);
+
+/*
+ * disable and enable intrs in software.  This is used
+ * from the non-realtime parts of Linux to disable interrupts.
+ * The realtime part disables/enables intrs in the hardware.
+ * -- Cort
+ */
+unsigned long soft_intr_enable = 1;
+void _soft_cli(void)
 {
-       unsigned char mask;
-       int s = _disable_interrupts();
+       soft_intr_enable = 0;
+}
 
-       if (isBeBox[0] && (irq_nr >= 16))
-       {
-               BeBox_disable_irq(irq_nr);
-       } else
+void _soft_sti(void)
+{
+       soft_intr_enable = 1;
+       if ( lost_interrupts )
        {
-               mask = 1 << (irq_nr & 7);
-               if (irq_nr < 8)
-               {
-                       cache_21 |= mask;
-                       outb(cache_21,0x21);
-               } else
-               {
-                       cache_A1 |= mask;
-                       outb(cache_A1,0xA1);
-               }
+               printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
+               fake_interrupt();
        }
-       _enable_interrupts(s);
 }
 
-void enable_irq(unsigned int irq_nr)
+void *
+null_handler(int a, void *b, struct pt_regs *regs)
+{
+       /*printk("irq.c: null_handler() called.  Should not have happened.\n");*/
+}
+
+void
+disable_irq(unsigned int irq_nr)
 {
-       unsigned char mask;
        int s = _disable_interrupts();
+       unsigned char mask;
 
-       if (isBeBox[0] && (irq_nr >= 16))
+#ifdef CONFIG_PMAC
+       out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+#else /* CONFIG_PMAC */
+       mask = 1 << (irq_nr & 7);
+       if (irq_nr < 8)
        {
-               BeBox_enable_irq(irq_nr);
-               _enable_interrupts(s);
-               return;
+               cached_21 |= mask;
+               outb(cached_21,0x21);
        } else
        {
-               mask = ~(1 << (irq_nr & 7));
-               if (irq_nr < 8) {
-                       cache_21 &= mask;
-                       outb(cache_21,0x21);
-               } else
-               {
-                       cache_A1 &= mask;
-                       outb(cache_A1,0xA1);
-               }
-       }
+               cached_A1 |= mask;
+               outb(cached_A1,0xA1);
+       }       
+#endif /* CONFIG_PMAC */
        _enable_interrupts(s);
 }
 
-/*
- * Irq handlers.
- */
-struct irq_action {
-       void (*handler)(int, void *dev, struct pt_regs *);
-       unsigned long flags;
-       unsigned long mask;
-       const char *name;
-       int notified;
-       void *dev_id;
-};
-
-static struct irq_action irq_action[32] = {
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-       { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
-};
-
-
-inline int get_irq_list(char *buf)
+void
+enable_irq(unsigned int irq_nr)
 {
-  int i, len = 0;
-  struct irq_action * action = irq_action;
-  
-  for (i = 0;  i < 32;  i++, action++) {
-    if (!action->handler)
-      continue;
-    len += sprintf(buf+len, "%2d: %8d %c %s\n",
-                  i, kstat.interrupts[i],
-                  (action->flags & SA_INTERRUPT) ? '+' : ' ',
-                  action->name);
-  }
-  return len;
-}
+       int s = _disable_interrupts();
+#ifdef CONFIG_PMAC
+       unsigned bit = 1U << irq_nr;
+       
+       out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+       out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
+
+       /*
+        * Unfortunately, setting the bit in the enable register
+        * when the device interrupt is already on *doesn't* set
+        * the bit in the flag register or request another interrupt.
+        */
+       if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
+               lost_interrupts |= bit;
+#else /* CONFIG_PMAC */
+       if (irq_nr < 8) {
+               cached_21 &= ~(1 << (irq_nr & 7));
+               outb(cached_21,0x21);
+       } else
+       {
+               cached_A1 &= ~(1 << (irq_nr-8 & 7));
+               outb(cached_A1,0xA1);
+       }       
+#endif /* CONFIG_PMAC */
 
-inline void
-process_IRQ(int irq, int _irq, struct pt_regs *regs)
-{
-  struct irq_action *action;
-  atomic_inc(&intr_count);
-  if (irq < 16)
-  {
-    /* Mask interrupt */
-    if (irq > 7)
-    {
-      cache_A1 |= (1<<(irq-8));
-      outb(cache_A1, 0xA1);
-    } else
-    {
-      cache_21 |= (1<<irq);
-      outb(cache_21, 0x21);
-    }
-  }
-  action = irq + irq_action;
-  kstat.interrupts[irq]++;
-  /* TEMP */
-  /* On the Nobis, the keyboard interrupt "edge" gets lost - why? */
-  if (irq == 0)
-  {
-    static int count;
-    if (++count == 500)
-    {
-      if (inb(0x64) & 0x01)
-      {
-       struct irq_action *action;
-       action = irq_action + 1;  /* Keyboard */
-       printk("Reset KBD, KBSTAT = %x, ELCR = %x/%x, MASK = %x/%x\n",
-              inb(0x64), inb(0x4D0), inb(0x4D1), cache_21, cache_A1);
-       action->handler(1, action->dev_id, regs);
-      }
-      count = 0;
-    }
-  }
-  if (action->handler)
-  {    
-    action->handler(irq, action->dev_id, regs);
-  } else
-  {
-    printk("Bogus interrupt %d/%x, pc %x regs %x\n",
-          irq, _irq,regs->nip,regs);
-#if 0
-    printk("BeBox[] = %x/%x\n", isBeBox[0], isBeBox[1]);
-    show_BeBox_state();
-    cnpause();
-#endif
-  }
-  if (_disable_interrupts() && !action->notified)
-  {
-    action->notified = 1;
-    printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n",
-          action->name, irq);
-  }
-  if (irq < 16)
-  {
-    /* Issue EOI to interrupt controller */
-    if (irq > 7)
-    {
-      outb(0xE0|(irq-8), 0xA0);
-      outb(0xE2, 0x20);
-    } else
-    {
-      outb(0xE0|irq, 0x20);
-    }
-    if (!(action->flags & SA_ONESHOT))
-    {
-      /* Re-enable interrupt */
-      if (irq > 7)
-      {
-       cache_A1 &= ~(1<<(irq-8));
-       outb(cache_A1, 0xA1);
-      } else
-      {
-       cache_21 &= ~(1<<irq);
-       outb(cache_21, 0x21);
-      }
-    }
-  } else
-  {
-    BeBox_enable_irq(irq);
-  }
-  atomic_dec(&intr_count);
+       _enable_interrupts(s);
 }
 
-asmlinkage inline void handle_IRQ(struct pt_regs *regs)
+
+int get_irq_list(char *buf)
 {
-  int irq, _irq, s;
-  struct irq_action *action;
-  static int _ints;
-  
-  if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
-  {
-    /* Figure out IRQ#, etc. */
-    outb(0x0C, 0x20);  /* Poll interrupt controller */
-    irq = _irq = inb(0x20);
-    irq &= 0x07;  /* Caution! */
-    if (irq == 2)
-    { /* Cascaded interrupt -> IRQ8..IRQ15 */
-      outb(0x0C, 0xA0);
-      irq = (_irq = inb(0xA0)) & 0x07;
-      irq += 8;
-    }
-  }
-  process_IRQ(irq, _irq, regs);
-  
-  /* Sometimes, the cascaded IRQ controller get's "stuck" */
-  if ((irq == 0) && (_ints++ == 100))
-  {
-    _ints = 0;
-    outb(0x0A, 0xA0);  _irq = inb(0xA0);
-    if (_irq & ~cache_A1)
-    {  /* Figure out which IRQs are present */
-      _irq &= ~cache_A1;
-      for (irq = 0;  irq < 7;  irq++)
-      {
-       if (_irq & (1<<irq))
-       {
-#if 0
-         printk("Dropped IRQ #%d\n", irq+8);
-#endif
-         process_IRQ(irq+8, _irq, regs);
+       int i, len = 0;
+       struct irqaction * action;
+
+       for (i = 0 ; i < NR_IRQS ; i++) {
+               action = irq_action + i;
+               if (!action || !action->handler) 
+                       continue;
+               len += sprintf(buf+len, "%2d: %10u   %s",
+                       i, kstat.interrupts[i], action->name);
+               for (action=action->next; action; action = action->next) {
+                       len += sprintf(buf+len, ", %s", action->name);
+               }
+               len += sprintf(buf+len, "\n");
        }
-      }
-    }
-  }
-}
-
 /*
- * Display current IRQ state
+ *     Linus - should you add NMI counts here ?????
  */
-
-void
-show_irq_state(void)
-{
-  unsigned char state_21, state_A1;
-  outb(0x0A, 0x20);  state_21 = inb(0x20);
-  outb(0x0A, 0xA0);  state_A1 = inb(0xA0);
-  printk("IRQ State = %x/%x, Edge = %x/%x, Processor = %d\n", state_21, state_A1, inb(0x4D0), inb(0x4D1), _Processor);
+#ifdef __SMP_PROF__
+       len+=sprintf(buf+len, "IPI: %8lu received\n",
+               ipi_count);
+#endif         
+       return len;
 }
 
-/*
- * Initialize interrupt controllers to a well-known state.
- */
-
-static void
-reset_int_controllers(void)
+asmlinkage void handle_IRQ(struct pt_regs *regs)
 {
-       /* Initialize interrupt controllers */
-       outb(0x11, 0x20); /* Start init sequence */
-       outb(0x40, 0x21); /* Vector base */
-       outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
-       outb(0x01, 0x21); /* Select 8086 mode */
-       outb(0xFF, 0x21); /* Mask all */
-       outb(0x11, 0xA0); /* Start init sequence */
-       outb(0x48, 0xA1); /* Vector base */
-       outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
-       outb(0x01, 0xA1); /* Select 8086 mode */
-       outb(0xFF, 0xA1); /* Mask all */
-#if 0
-       outb(0x00, 0x4D0); /* All edge triggered */
-       outb(0xCF, 0x4D1); /* Trigger mode */
+       int irq;
+       unsigned bits;
+       struct irqaction *action;
+       int cpu = smp_processor_id();
+
+       hardirq_enter(cpu);
+
+#ifdef CONFIG_PMAC 
+       bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+       lost_interrupts = 0;
+       
+       for (irq = NR_IRQS; irq >= 0; --irq)
+               if (bits & (1U << irq))
+                       break;
+#else /* CONFIG_PMAC */
+#if 1
+       if ( lost_interrupts )
+       {
+               irq = ffz(~lost_interrupts);
+               lost_interrupts &= ~irq;
+               goto retry;
+       }
+       outb(0x0C, 0x20);
+       irq = inb(0x20) & 7;
+       if (irq == 2)
+       {
+retry_cascade:         
+               outb(0x0C, 0xA0);
+               irq = inb(0xA0);
+               /* if no intr left */
+               if ( !(irq & 128 ) )
+                       goto out;
+               irq = (irq&7) + 8;
+       }
+retry:
+#else
+       /* get the irr from the intr controller */
+       outb(0x0A, 0x20);
+       bits = inb(0x20);
+       /* handle cascade */
+       if ( bits  ) 
+       {
+               bits &= 4;
+               outb(0x0A, 0xA0);
+               bits = inb(0xA0)<<8;
+       }
+       /* get lost interrupts */
+       bits |= lost_interrupts;
+       /* save intrs that are masked out */
+       lost_interrupts = bits & cached_irq_mask;
+       /* get rid of intrs being masked */
+       bits &= ~cached_irq_mask;
+        /* non-specifc eoi */
+       outb(0x20,0x20);
+       if ( bits & 0xff00 )
+               outb(0x20,0xA0);
+       
+       printk("bits %04X lost %04X mask %04x\n",
+              bits, lost_interrupts,cached_irq_mask);
+       
+       for (irq = NR_IRQS; irq >= 0; --irq)
+               if (bits & (1U << irq))
+                       break;
 #endif
-       outb(cache_A1, 0xA1);
-       outb(cache_21, 0x21);
-       enable_irq(2);  /* Enable cascade interrupt */
+#endif /* CONFIG_PMAC */
+       
+       if (irq < 0) {
+               printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+               goto out;
+       }
+
+#ifdef CONFIG_PMAC 
+       out_le32(IRQ_ACK, 1U << irq);
+#else /* CONFIG_PMAC */
+        /* mask out the irq while handling it */       
+       disable_irq(irq); 
+       /*
+        * send eoi to interrupt controller right away or lower
+        * priority intrs would be ignored even if with intrs enabled
+        */
+       if (irq > 7)
+       {
+               outb(0xE0|(irq-8), 0xA0);
+               outb(0xE2, 0x20);
+       } else
+       {
+               outb(0xE0|irq, 0x20);
+       }
+#endif /* !CONFIG_PMAC */
+
+       /*
+        * now that we've acked the irq, if intrs are disabled in software
+        * we're in the real-time system and non-rt linux has disabled them
+        * so we just queue it up and return -- Cort
+        */
+       if ( ! soft_intr_enable ) 
+       {
+               lost_interrupts |= 1UL << irq;
+               /* can't printk - kernel expects intrs off! */
+               /*printk("irq %d while intrs soft disabled\n", irq);*/
+               goto out;
+       }
+       
+       action = irq + irq_action;
+       kstat.interrupts[irq]++;
+       if (action->handler) {
+               action->handler(irq, action->dev_id, regs);
+               _disable_interrupts(); /* in case the handler turned them on */
+       } else {
+               disable_irq( irq );
+       }
+#ifdef CONFIG_PREP
+       /* re-enable if the interrupt was good and isn't one-shot */
+       if ( action->handler && !(action->flags & SA_ONESHOT) )
+               enable_irq(irq);
+       /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
+       if ( irq > 7 )
+               goto retry_cascade;
+#endif
+       
+       hardirq_exit(cpu);
+       /*
+        * This should be conditional: we should really get
+        * a return code from the irq handler to tell us
+        * whether the handler wants us to do software bottom
+        * half handling or not..
+        */
+       if (1)
+               if (bh_active & bh_mask)
+                       do_bottom_half();
+        return;
+out:
+       hardirq_exit(cpu);
+
 }
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-               unsigned long irqflags, const char * devname, void *dev_id)
+       unsigned long irqflags, const char * devname, void *dev_id)
 {
-       struct irq_action * action;
+       struct irqaction * action;
        unsigned long flags;
-
-#ifdef SHOW_IRQ
-if (irq) printk("Request IRQ #%d, Handler: %x\n", irq, handler);
-#endif
-       if (irq > 15)
-       {
-               if (!isBeBox[0] || (irq > 31))
-                       return -EINVAL;
-       }
+       
+#ifdef SHOW_IRQ        
+       printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
+              irq,handler,devname,dev_id);
+#endif /* SHOW_IRQ */
+       
+       if (irq > NR_IRQS)
+               return -EINVAL;
        action = irq + irq_action;
        if (action->handler)
                return -EBUSY;
@@ -361,10 +342,14 @@ if (irq) printk("Request IRQ #%d, Handler: %x\n", irq, handler);
                
 void free_irq(unsigned int irq, void *dev_id)
 {
-       struct irq_action * action = irq + irq_action;
+       struct irqaction * action = irq + irq_action;
        unsigned long flags;
 
-       if (irq > 31) {
+#ifdef SHOW_IRQ        
+       printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
+#endif /* SHOW_IRQ */
+       
+       if (irq > NR_IRQS) {
                printk("Trying to free IRQ%d\n",irq);
                return;
        }
@@ -383,15 +368,6 @@ void free_irq(unsigned int irq, void *dev_id)
        restore_flags(flags);
 }
 
-#define SA_PROBE SA_ONESHOT
-
-static void no_action(int irq, void *dev, struct pt_regs * regs)
-{
-#ifdef DEBUG
-       printk("Probe got IRQ: %d\n", irq);
-#endif
-}
-
 unsigned long probe_irq_on (void)
 {
        unsigned int i, irqs = 0, irqmask;
@@ -399,7 +375,7 @@ unsigned long probe_irq_on (void)
 
        /* first, snaffle up any unassigned irqs */
        for (i = 15; i > 0; i--) {
-               if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
+               if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
                        enable_irq(i);
                        irqs |= (1 << i);
                }
@@ -409,7 +385,7 @@ unsigned long probe_irq_on (void)
        for (delay = jiffies + 2; delay > jiffies; );   /* min 10ms delay */
 
        /* now filter out any obviously spurious interrupts */
-       irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+       irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
        for (i = 15; i > 0; i--) {
                if (irqs & (1 << i) & irqmask) {
                        irqs ^= (1 << i);
@@ -426,13 +402,13 @@ int probe_irq_off (unsigned long irqs)
 {
        unsigned int i, irqmask;
 
-       irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+       irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
        for (i = 15; i > 0; i--) {
                if (irqs & (1 << i)) {
                        free_irq(i, NULL);
                }
        }
-#ifdef DEBUG
+#ifdef SHOW_IRQ
        printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 #endif
        irqs &= irqmask;
@@ -443,209 +419,65 @@ int probe_irq_off (unsigned long irqs)
                i = -i;
        return i;
 }
-void init_IRQ(void)
-{
-  int i;
-
-  if ((_get_PVR()>>16) == 1)  /* PPC 601 */
-  { /* Nobis? */
-    reset_int_controllers();
-  }
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
-  /* set the clock to 100 Hz */
-  outb_p(0x34,TIMER_CONTROL);          /* binary, mode 2, LSB/MSB, ch 0 */
-  outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
-  outb(LATCH >> 8 , TIMER0_COUNT);     /* MSB */
-  if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
-    printk("Unable to get IRQ2 for cascade\n");
-  request_region(0x20,0x20,"pic1");
-  request_region(0xa0,0x20,"pic2");
-  
-  /* Make sure IRQ2 (cascade) interrupt is "level" based */
-  outb(inb(0x4D0)|0x04, 0x4D0); /* IRQ2 level based */
-  
-  /* Set up PCI interrupts */
-  route_PCI_interrupts();
-  
-  if (isBeBox[0])
-  {
-    BeBox_init_IRQ();
-  }
-}
 
-/*
- * Wrapper for "bottom 1/2" of interrupt processing.  This routine
- * is called whenever an interrupt needs non-interrupt-time service.
- */
-
-void _do_bottom_half(void)
-{
-  _enable_interrupts(1);
-  do_bottom_half();
-  _disable_interrupts();
-}
-
-void hard_disk_LED(int state)
-{
-  if (_Processor == _PROC_IBM) {
-    outb(state, IBM_HDD_LED);
-  }
-}
-
-/*
- * Support for interrupts on the BeBox
- */
-
-#define CPU0_INT_MASK  (volatile unsigned long *)(BeBox_IO_page+0x0F0)
-#define CPU1_INT_MASK  (volatile unsigned long *)(BeBox_IO_page+0x1F0)
-#define INT_SOURCE     (volatile unsigned long *)(BeBox_IO_page+0x2F0)
-#define CPU_RESET      (volatile unsigned long *)(BeBox_IO_page+0x4F0)
-
-#define _CPU0_INT_MASK (volatile unsigned long *)(0xA0000000+0x0F0)
-#define _CPU1_INT_MASK (volatile unsigned long *)(0xA0000000+0x1F0)
-#define _INT_SOURCE    (volatile unsigned long *)(0xA0000000+0x2F0)
-#define _CPU_RESET     (volatile unsigned long *)(0xA0000000+0x4F0)
-
-#define CPU_HRESET     0x20000000
-#define CPU_SRESET     0x40000000
-
-#define SCSI_IRQ       16
-
-#define INT_SCSI       (1<<21)
-#define INT_8259       (1<<5)
-
-/*
- * Map of pseudo IRQs to actual bits
- * Note: We give out IRQ #16..31 for all interrupt sources which are
- * not found in the 8259 PIC.
- */
-unsigned long BeBox_IRQ_map[] =
-   {
-       INT_SCSI,       /* 16 - SCSI */
-       0x00000000,     /* 17 - Unused */
-       0x00000000,     /* 18 - Unused */
-       0x00000000,     /* 19 - Unused */
-       0x00000000,     /* 20 - Unused */
-       0x00000000,     /* 21 - Unused */
-       0x00000000,     /* 22 - Unused */
-       0x00000000,     /* 23 - Unused */
-       0x00000000,     /* 24 - Unused */
-       0x00000000,     /* 25 - Unused */
-       0x00000000,     /* 26 - Unused */
-       0x00000000,     /* 27 - Unused */
-       0x00000000,     /* 28 - Unused */
-       0x00000000,     /* 29 - Unused */
-       0x00000000,     /* 30 - Unused */
-       0x00000000,     /* 31 - Unused */
-   };
-
-volatile int CPU1_alive;
-volatile int CPU1_trace;
-
-static
-_NOP(void)
-{
-}
-
-static
-_delay(void)
+void init_IRQ(void)
 {
-       int i;
-       for (i = 0;  i < 100;  i++) _NOP();
-}
+#ifdef CONFIG_PMAC  
+       extern void xmon_irq(int, void *, struct pt_regs *);
 
-void
-BeBox_init_IRQ(void)
-{
-       int tmr;
-       volatile extern long BeBox_CPU1_vector;
-       *CPU0_INT_MASK = 0x0FFFFFFC;  /* Clear all bits? */     
-       *CPU0_INT_MASK = 0x80000003 | INT_8259;
-       *CPU1_INT_MASK = 0x0FFFFFFC;  
-printk("Start CPU #1 - CPU Status: %x\n", *CPU_RESET);
-       BeBox_CPU1_vector = 0x0100;  /* Reset */
-       tmr = 0;
-       while (CPU1_alive == 0)
-       {
-               if (++tmr == 1000)
-               {
-printk("CPU #1 not there? - CPU Status: %x, Trace: %x\n", *CPU_RESET, CPU1_trace);
-                       break;
-               }
-               _delay();
-       }
-printk("CPU #1 running!\n");
-}
+       *IRQ_ENABLE = 0;
+       request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#else /* CONFIG_PMAC */
+       /* Initialize interrupt controllers */
+       outb(0x11, 0x20); /* Start init sequence */
+       outb(0x40, 0x21); /* Vector base */
+#if 1
+       outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+#else
+       outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+#endif 
+       
+       outb(0x01, 0x21); /* Select 8086 mode */
+       outb(0xFF, 0x21); /* Mask all */
 
-void
-BeBox_disable_irq(int irq)
-{
-       /* Note: this clears the particular bit */
-       *CPU0_INT_MASK = BeBox_IRQ_map[irq-16];
-}
+       outb(0x11, 0xA0); /* Start init sequence */
+       outb(0x48, 0xA1); /* Vector base */
+#if 1
+       outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
+#else
+       outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+#endif
+       outb(0x01, 0xA1); /* Select 8086 mode */
+       outb(0xFF, 0xA1); /* Mask all */
 
-void
-BeBox_enable_irq(int irq)
-{
-       int s = _disable_interrupts();
-       /* Sets a single bit */
+       /*
+        * Program level mode for irq's that 'can' be level triggered.
+        * This does not effect irq's 0,1,2 and 8 since they must be
+        * edge triggered. This is not the PIC controller.  The default
+        * here is for edge trigger mode.  -- Cort
+        */
 #if 0  
-printk("BeBox IRQ Mask = %x", *CPU0_INT_MASK);
+       outb(0xf8, 0x4d0); /* level triggered */
+       outb(0xff, 0x4d1);
 #endif
-       *CPU0_INT_MASK = 0x80000000 | BeBox_IRQ_map[irq-16];
-#if 0
-printk("/%x\n", *CPU0_INT_MASK);
-#endif 
-       _enable_interrupts(s);  
-}
-
-void
-show_BeBox_state(void)
-{
-       unsigned long cpu0_int_mask;
-       unsigned long int_state;
-       cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
-       int_state = cpu0_int_mask & *INT_SOURCE;
-       printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-}
-
-int
-BeBox_irq(void)
-{
-       int i;
-       unsigned long cpu0_int_mask;
-       unsigned long int_state;
-       cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
-       int_state = cpu0_int_mask & *INT_SOURCE;
-       if (int_state)
-       { /* Determine the pseudo-interrupt # */
 #if 0  
-               printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-#endif         
-               for (i = 0;  i < 16;  i++)
-               {
-                       if (BeBox_IRQ_map[i] & int_state)
-                       {
-                               return (i+16);
-                       }
-               }
-printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-printk("Can't find BeBox IRQ!\n");
-       }
-       return (0);
-}
-
-void BeBox_state(void)
-{
-       printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
-}
-
-void BeBox_CPU1(void)
-{
-       CPU1_alive++;
-       while (1) ;
+       outb(0x00, 0x4D0); /* All edge triggered */
+       outb(0xCF, 0x4D1); /* Trigger mode */
+#endif
+       outb(cached_A1, 0xA1);
+       outb(cached_21, 0x21);
+       if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
+               printk("Unable to get IRQ2 for cascade\n");
+       enable_irq(2);  /* Enable cascade interrupt */
+       
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+       /* set timer to periodic mode */
+       outb_p(0x34,TIMER_CONTROL);             /* binary, mode 2, LSB/MSB, ch 0 */
+       /* set the clock to ~100 Hz */
+       outb_p(LATCH & 0xff , TIMER0_COUNT);    /* LSB */
+       outb(LATCH >> 8 , TIMER0_COUNT);        /* MSB */
+
+       route_pci_interrupts();
+#endif /* CONFIG_PMAC */
 }
index b59b8964e4980ae207541257053d9a2f02137d42..b246fa6df5ebad819024921c06739e37f1bc6703 100644 (file)
@@ -1,4 +1,40 @@
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void handle_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+unsigned long sys_call_table[];
+
+extern struct task_struct *current_set[1];
 
 /* platform dependent support */
+EXPORT_SYMBOL(current_set);
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(handle_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(FloatingPointCheckException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(sys_call_table);
index c2a2989ec965b68f297a6e9dcff04d6ca2b829cf..430cd7a5d7025eda92eca5c61b92e2cf34615395 100644 (file)
 /*
- * This module contains the PowerPC interrupt fielders
- * set of code at specific locations, based on function
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
  */
 
-#include "ppc_asm.tmpl"
+#include <linux/config.h>
 #include <linux/sys.h>
+#include <asm/unistd.h>
 #include <asm/errno.h>
-#include "ppc_defs.h"
 #include <asm/processor.h>
-               
-/* Keep track of low-level exceptions - rather crude, but informative */       
-#define STATS
-
-/*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
- */
-#define BUMP(ctr) \
-       lis     r2,ctr@h; \
-       ori     r2,r2,ctr@l; \
-       lwz     r3,4(r2); \
-       addic   r3,r3,1; \
-       stw     r3,4(r2); \
-       lwz     r3,0(r2); \
-       addze   r3,r3; \
-       stw     r3,0(r2)
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
 
-/*#ifdef CONFIG_603*/
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 601 or 603 */
 #define tlbia \
-       li      r4,64; \
+       li      r4,128; \
        mtspr   CTR,r4; \
        li      r4,0; \
 0:     tlbie   r4; \
        addi    r4,r4,0x1000; \
        bdnz    0b
-/*#endif*/ /* CONFIG_603*/
        
 _TEXT()
-#define CPU_CTL     0x80000092
-_GLOBAL(hard_reset_now)
-        mfmsr   r3              /* Disable interrupts */
-        li      r4,0            
-        ori     r4,r4,MSR_EE    
-        andc    r3,r3,r4        
-        ori     r3,r3,MSR_IP    /* Set FLASH/ROM interrupt handlers */
-        sync
-        mtmsr   r3
-        lis     r3,CPU_CTL>>16
-        ori     r3,r3,(CPU_CTL&0xFFFF)
-        lbz     r4,0(r3)        /* Turn on SRESET */
-        li      r5,1
-        andc    r4,r4,r5        /* Make sure we go from 0->1 */
-        stb     r4,0(r3)
-        ori     r4,r4,1
-        stb     r4,0(r3)        /* This should do it! */
-99:     nop
-        b       99b
-
-#if 0  
-/*
-  unsigned short
-     le16_to_cpu(unsigned short val)
-*/
-_GLOBAL(le16_to_cpu)
-       lis     r4,_le_scratch@h
-       ori     r4,r4,_le_scratch@l
-       sth     r3,0(r4)
-       li      r5,0
-       lhbrx   r3,r4,r5
-       blr
-
-_GLOBAL(le32_to_cpu)
-       lis     r4,_le_scratch@h
-       ori     r4,r4,_le_scratch@l
-       stw     r3,0(r4)
-       li      r5,0
-       lwbrx   r3,r4,r5
-       blr
-_GLOBAL(_le_scratch)
-       .space 4
-#endif 
-#if 1
-/*     
-extern int __put_user_8(char, char *);
-extern int __put_user_16(short, short *);
-extern int __put_user_32(long, long *);
-*/
-_GLOBAL(__put_user_8)
-       /* setup exception stuff */
-       lis     r2,current_set@ha
-       lwz     r2,current_set@l(r2)
-       /* increment excount */
-       lwz     r6,TSS+TSS_EXCOUNT(r2)
-       addi    r6,r6,1
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       /* set expc */
-       lis     r6,1f@h
-       ori     r6,r6,1f@l
-       stw     r6,TSS+TSS_EXPC(r2)
-       
-       stb     r3,0(r4)
-       li      r3,0            /* successful return */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-1:     li      r3,-EFAULT      /* bad access */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-               
-_GLOBAL(__put_user_16)
-       /* setup exception stuff */
-       lis     r2,current_set@ha
-       lwz     r2,current_set@l(r2)
-       /* increment excount */
-       lwz     r6,TSS+TSS_EXCOUNT(r2)
-       addi    r6,r6,1
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       /* set expc */
-       lis     r6,1f@h
-       ori     r6,r6,1f@l
-       stw     r6,TSS+TSS_EXPC(r2)
-       
-       sth     r3,0(r4)
-       li      r3,0            /* successful return */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-1:     li      r3,-EFAULT      /* bad access */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
 
-_GLOBAL(__put_user_32)
-       /* setup exception stuff */
-       lis     r2,current_set@ha
-       lwz     r2,current_set@l(r2)
-       /* increment excount */
-       lwz     r6,TSS+TSS_EXCOUNT(r2)
-       addi    r6,r6,1
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       /* set expc */
-       lis     r6,1f@h
-       ori     r6,r6,1f@l
-       stw     r6,TSS+TSS_EXPC(r2)
-       
-       stw     r3,0(r4)
-       li      r3,0            /* successful return */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-1:     li      r3,-EFAULT      /* bad access */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-       
-_GLOBAL(__get_user_8)
-       /* setup exception stuff */
-       lis     r2,current_set@ha
-       lwz     r2,current_set@l(r2)
-       /* increment excount */
-       lwz     r6,TSS+TSS_EXCOUNT(r2)
-       addi    r6,r6,1
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       /* set expc */
-       lis     r6,1f@h
-       ori     r6,r6,1f@l
-       stw     r6,TSS+TSS_EXPC(r2)
-       
-       lbz     r3,0(r4)
-       li      r4,0            /* successful return */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-1:     li      r4,-EFAULT      /* bad access */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-       
-_GLOBAL(__get_user_16)
-       /* setup exception stuff */
-       lis     r2,current_set@ha
-       lwz     r2,current_set@l(r2)
-       /* increment excount */
-       lwz     r6,TSS+TSS_EXCOUNT(r2)
-       addi    r6,r6,1
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       /* set expc */
-       lis     r6,1f@h
-       ori     r6,r6,1f@l
-       stw     r6,TSS+TSS_EXPC(r2)
-       
-       lhz     r3,0(r4)
-       li      r4,0            /* successful return */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-1:     li      r4,-EFAULT      /* bad access */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-       
-_GLOBAL(__get_user_32)
-       /* setup exception stuff */
-       lis     r2,current_set@ha
-       lwz     r2,current_set@l(r2)
-       /* increment excount */
-       lwz     r6,TSS+TSS_EXCOUNT(r2)
-       addi    r6,r6,1
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       /* set expc */
-       lis     r6,1f@h
-       ori     r6,r6,1f@l
-       stw     r6,TSS+TSS_EXPC(r2)
-       lwz     r3,0(r4)
-       li      r4,0            /* successful return */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-1:     li      r4,-EFAULT      /* bad access */
-       li      r6,0
-       stw     r6,TSS+TSS_EXCOUNT(r2)
-       blr
-#endif 
 /*
  * Disable interrupts
  *     rc = _disable_interrupts()
  */
 _GLOBAL(_disable_interrupts)
+_GLOBAL(__cli)
+_GLOBAL(_hard_cli)
        mfmsr   r0              /* Get current interrupt state */
        rlwinm  r3,r0,16+1,32-1,31      /* Extract old value of 'EE' */
        li      r4,0            /* Need [unsigned] value of MSR_EE */
@@ -244,20 +50,18 @@ _GLOBAL(_disable_interrupts)
  * turns on interrupts if state = 1.
  */
 _GLOBAL(_enable_interrupts)
-       mfmsr   r0              /* Get current state */
-       rlwimi  r0,r3,16-1,32-16,32-16  /* Insert bit */
+       cmpi    0,r3,0          /* turning them on? */
+       beqlr                   /* nothing to do if state == 0 */
+_GLOBAL(__sti)
+_GLOBAL(_hard_sti)
+       lis     r4,lost_interrupts@ha
+       lwz     r4,lost_interrupts@l(r4)
+       mfmsr   r3              /* Get current state */
+       ori     r3,r3,MSR_EE    /* Turn on 'EE' bit */
+       cmpi    0,r4,0          /* lost interrupts to process first? */
+       bne-    do_lost_interrupts
        sync                    /* Some chip revs have problems here... */
-       mtmsr   r0              /* Update machine state */
-       blr
-
-/*
- * Get 'flags' (aka machine status register)
- *     __save_flags(long *ptr)
- */
-_GLOBAL(__save_flags)
-       mfmsr   r0              /* Get current state */
-       stw     r0,0(r3)
-       mr      r3,r0
+       mtmsr   r3              /* Update machine state */
        blr
 
 /*
@@ -265,34 +69,37 @@ _GLOBAL(__save_flags)
  *     __restore_flags(long val)
  */
 _GLOBAL(__restore_flags)
-       sync                    /* Some chip revs have problems here... */
+       andi.   r0,r3,MSR_EE    /* enabling interrupts? */
+       beq     2f
+       lis     r4,lost_interrupts@ha
+       lwz     r4,lost_interrupts@l(r4)
+       cmpi    0,r4,0
+       bne     do_lost_interrupts
+2:     sync                    /* Some chip revs have problems here... */
        mtmsr   r3
        isync
        blr
 
 /*
- * Disable interrupts - like an 80x86
- *     cli()
- */
-_GLOBAL(cli)
-       mfmsr   r0              /* Get current interrupt state */
-       rlwinm  r3,r0,16+1,32-1,31      /* Extract old value of 'EE' */
-       li      r4,0            /* Need [unsigned] value of MSR_EE */
-       ori     r4,r4,MSR_EE    /* Set to turn off bit */
-       andc    r0,r0,r4        /* Clears bit in (r4) */
-       sync                    /* Some chip revs have problems here... */
-       mtmsr   r0              /* Update machine state */
-       blr                     /* Done */
-
-/*
- * Enable interrupts - like an 80x86
- *     sti()
+ * We were about to enable interrupts but we have to simulate
+ * some interrupts that were lost by enable_irq first.
  */
-_GLOBAL(sti)
-       mfmsr   r0              /* Get current state */
-       ori     r0,r0,MSR_EE    /* Turn on 'EE' bit */
-       sync                    /* Some chip revs have problems here... */
-       mtmsr   r0              /* Update machine state */
+do_lost_interrupts:
+       stwu    r1,-16(r1)
+       mflr    r0
+       stw     r0,20(r1)
+       stw     r3,8(r1)
+1:     bl      fake_interrupt
+       lis     r4,lost_interrupts@ha
+       lwz     r4,lost_interrupts@l(r4)
+       cmpi    0,r4,0
+       bne-    1b
+       lwz     r3,8(r1)
+       sync
+       mtmsr   r3
+       lwz     r0,20(r1)
+       mtlr    r0
+       addi    r1,r1,16
        blr
 
 /*
@@ -300,7 +107,6 @@ _GLOBAL(sti)
  */
 _GLOBAL(_tlbia)
        tlbia
-       BUMP(__TLBIAs)
        blr     
 
 /*
@@ -308,17 +114,7 @@ _GLOBAL(_tlbia)
  */
 _GLOBAL(_tlbie)
        tlbie   r3
-       BUMP(__TLBIEs)
        blr
-
-/*
- * Fetch the current SR register
- *   get_SR(int index)
- */
-_GLOBAL(get_SR)
-       mfsrin  r3,r3
-       blr     
-
 /*
  * Atomic [test&set] exchange
  *
@@ -340,7 +136,11 @@ _GLOBAL(xchg_u32)
  * void atomic_sub(int c, int *v)
  * void atomic_inc(int *v)
  * void atomic_dec(int *v)
- * void atomic_dec_and_test(int *v)
+ * int atomic_dec_and_test(int *v)
+ * int atomic_inc_return(int *v)
+ * int atomic_dec_return(int *v)
+ * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
+ * void atomic_set_mask(atomic_t mask, atomic_t *addr);
  */
 _GLOBAL(atomic_add)
 10:    lwarx   r5,0,r4         /* Fetch old value & reserve */
@@ -360,69 +160,46 @@ _GLOBAL(atomic_inc)
        stwcx.  r5,0,r3         /* Update with new value */
        bne-    10b             /* Retry if "reservation" (i.e. lock) lost */
        blr
+_GLOBAL(atomic_inc_return)
+10:    lwarx   r5,0,r3         /* Fetch old value & reserve */
+       addi    r5,r5,1         /* Perform 'add' operation */
+       stwcx.  r5,0,r3         /* Update with new value */
+       bne-    10b             /* Retry if "reservation" (i.e. lock) lost */
+       mr      r3,r5           /* Return new value */
+       blr
 _GLOBAL(atomic_dec)
 10:    lwarx   r5,0,r3         /* Fetch old value & reserve */
        subi    r5,r5,1         /* Perform 'add' operation */
        stwcx.  r5,0,r3         /* Update with new value */
        bne-    10b             /* Retry if "reservation" (i.e. lock) lost */
        blr
+_GLOBAL(atomic_dec_return)
+10:    lwarx   r5,0,r3         /* Fetch old value & reserve */
+       subi    r5,r5,1         /* Perform 'add' operation */
+       stwcx.  r5,0,r3         /* Update with new value */
+       bne-    10b             /* Retry if "reservation" (i.e. lock) lost */
+       mr      r3,r5           /* Return new value */
+       blr
 _GLOBAL(atomic_dec_and_test)
 10:    lwarx   r5,0,r3         /* Fetch old value & reserve */
        subi    r5,r5,1         /* Perform 'add' operation */
        stwcx.  r5,0,r3         /* Update with new value */
        bne-    10b             /* Retry if "reservation" (i.e. lock) lost */
        cmpi    0,r5,0          /* Return 'true' IFF 0 */
-       bne     15f
        li      r3,1
+       beqlr
+       li      r3,0
        blr
-15:    li      r3,0
-       blr     
-       
-
-/*
- * Delay for a specific # of "loops"
- *     __delay(int loops)
- */
-_GLOBAL(__delay)
-       mtctr   r3
-00:    addi    r3,r3,0         /* NOP */
-       bdnz    00b
-       blr
-
-/*
- * Delay for a number of microseconds
- *     udelay(int usecs)
- */
-_GLOBAL(udelay)
-00:    li      r0,86   /* Instructions / microsecond? */
-       mtctr   r0
-10:    addi    r0,r0,0 /* NOP */
-       bdnz    10b
-       subic.  r3,r3,1
-       bne     00b
-       blr
-
-/*
- * Atomically increment [intr_count]
- */
-_GLOBAL(start_bh_atomic)
-       lis     r3,intr_count@h
-       ori     r3,r3,intr_count@l
-10:    lwarx   r4,0,r3
-       addi    r4,r4,1
-       stwcx.  r4,0,r3
+_GLOBAL(atomic_clear_mask)
+10:    lwarx   r5,0,r4
+       andc    r5,r5,r3
+       stwcx.  r5,0,r4
        bne-    10b
        blr
-
-/*
- * Atomically decrement [intr_count]
- */
-_GLOBAL(end_bh_atomic)
-       lis     r3,intr_count@h
-       ori     r3,r3,intr_count@l
-10:    lwarx   r4,0,r3
-       subic   r4,r4,1
-       stwcx.  r4,0,r3
+_GLOBAL(atomic_set_mask)
+10:    lwarx   r5,0,r4
+       or      r5,r5,r3
+       stwcx.  r5,0,r4
        bne-    10b
        blr
 
@@ -431,6 +208,8 @@ _GLOBAL(end_bh_atomic)
  *
  * insw(port, buf, len)
  * outsw(port, buf, len)
+ * insl(port, buf, len)
+ * outsl(port, buf, len)
  */
 _GLOBAL(_insw)
        mtctr   r5
@@ -448,135 +227,39 @@ _GLOBAL(_outsw)
        bdnz    00b
        blr     
 
-#if 0  
-/*
- *extern inline int find_first_zero_bit(void * vaddr, unsigned size)
- *{
- *     unsigned long res;
- *     unsigned long *p;
- *     unsigned long *addr = vaddr;
- *
- *     if (!size)
- *             return 0;
- *     __asm__ __volatile__ ("    moveq #-1,d0\n\t"
- *                           "1:"
- *                           "    cmpl  %1@+,d0\n\t"
- *                           "    bne   2f\n\t"
- *                           "    subql #1,%0\n\t"
- *                           "    bne   1b\n\t"
- *                           "    bra   5f\n\t"
- *                           "2:"
- *                           "    movel %1@-,d0\n\t"
- *                           "    notl  d0\n\t"
- *                           "    bfffo d0{#0,#0},%0\n\t"
- *                           "5:"
- *                           : "=d" (res), "=a" (p)
- *                           : "0" ((size + 31) >> 5), "1" (addr)
- *                           : "d0");
- *     return ((p - addr) << 5) + res;
- *}
- */
-_GLOBAL(find_first_zero_bit)
-       li      r5,0            /* bit # */
-       subi    r3,r3,4         /* Adjust pointer for auto-increment */
-00:    lwzu    r0,4(r3)        /* Get next word */
-       not.    r7,r0           /* Complement to find ones */
-       beq     10f             /* Jump if all ones */
-02:    andi.   r7,r0,1         /* Check low-order bit */
-       beq     20f             /* All done when zero found */
-       srawi   r0,r0,1
-       addi    r5,r5,1
-       b       02b
-10:    addi    r5,r5,32        /* Update bit # */
-       subic.  r4,r4,32        /* Any more? */
-       bgt     00b
-20:    mr      r3,r5           /* Compute result */    
+_GLOBAL(_insl)
+       mtctr   r5
+       subi    r4,r4,4
+00:    lwbrx   r5,0,r3
+       stwu    r5,4(r4)
+       bdnz    00b
        blr
-/*
- *static inline int find_next_zero_bit (void *vaddr, int size,
- *                                   int offset)
- *{
- *     unsigned long *addr = vaddr;
- *     unsigned long *p = addr + (offset >> 5);
- *     int set = 0, bit = offset & 31, res;
- *
- *     if (bit) {
- *             // Look for zero in first longword 
- *             __asm__("bfffo %1{#0,#0},%0"
- *                     : "=d" (set)
- *                     : "d" (~*p << bit));
- *             if (set < (32 - bit))
- *                     return set + offset;
- *                set = 32 - bit;
- *             p++;
- *     }
- *     // No zero yet, search remaining full bytes for a zero 
- *     res = find_first_zero_bit (p, size - 32 * (p - addr));
- *     return (offset + set + res);
- *}
- */
-_GLOBAL(find_next_zero_bit)
-       addi    r5,r5,1         /* bump offset to start */
-       srawi   r6,r5,5         /* word offset */
-       add     r6,r6,r6        /* byte offset */
-       add     r6,r6,r6        /* byte offset */
-       add     r3,r3,r6        /* compute byte position */
-       sub     r4,r4,r5        /* adjust size by starting index */
-       andi.   r0,r5,0x1F      /* offset in current word? */
-       beq     10f             /* at start of word */
-       lwz     r0,0(r3)        /* get word */
-       sraw    r0,r0,r5        /* shift right */
-       not.    r7,r0
-       beq     07f             /* jump if only ones remain */
-05:    andi.   r7,r0,1         /* found zero? */
-       beq     90f             /* yes - all done */
-       srawi   r0,r0,1
-       addi    r5,r5,1
-       b       05b
-07:    andi.   r6,r5,0x1F
-       subfic  r0,r6,32
-       add     r5,r5,r0
-       sub     r4,r4,r0
-       b       20f
-10:    subi    r3,r3,4         /* Adjust pointer for auto-increment */
-20:    lwzu    r0,4(r3)        /* Get next word */
-       not.    r7,r0           /* Complement to find ones */
-       beq     40f             /* Jump if all ones */
-30:    andi.   r7,r0,1         /* Check low-order bit */
-       beq     90f             /* All done when zero found */
-       srawi   r0,r0,1
-       addi    r5,r5,1
-       b       30b
-40:    addi    r5,r5,32        /* Update bit # */
-       subic.  r4,r4,32        /* Any more? */
-       bgt     20b
-90:    mr      r3,r5           /* Compute result */    
+
+_GLOBAL(_outsl)
+       mtctr   r5
+       subi    r4,r4,4
+00:    lwzu    r5,4(r4)
+       stwbrx  r5,0,r3 
+       bdnz    00b
+       blr     
+
+#ifdef CONFIG_PMAC
+_GLOBAL(ide_insw)
+       mtctr   r5
+       subi    r4,r4,2
+00:    lhzx    r5,0,r3
+       sthu    r5,2(r4)
+       bdnz    00b
        blr
+
+_GLOBAL(ide_outsw)
+       mtctr   r5
+       subi    r4,r4,2
+00:    lhzu    r5,2(r4)
+       sthx    r5,0,r3 
+       bdnz    00b
+       blr     
 #endif
-/*
- *
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- *
- *extern inline unsigned long ffz(unsigned long word)
- *{
- *     __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
- *                           : "=d" (word)
- *                           : "d" (~(word)));
- *     return word;
- *}
- */
-_GLOBAL(ffz)
-       mr      r4,r3
-       li      r3,0
-10:    andi.   r0,r4,1         /* Find the zero we know is there */
-       srawi   r4,r4,1
-       beq     90f
-       addi    r3,r3,1
-       b       10b
-90:    blr
 
 /*
  * Extended precision shifts
@@ -605,43 +288,7 @@ _GLOBAL(__ashldi3)
        slw     r3,r3,r5        /* YYY--- */
        or      r3,r3,r7        /* YYYZZZ */
        blr
-       
-_GLOBAL(abort)
-       .long   0
-       
-/* in include/asm/string.h now -- Cort */
-#if 0
-_GLOBAL(bzero)
-#define bufp r3
-#define len  r4
-#define pat  r5
-/* R3 has buffer */
-/* R4 has length */
-/* R5 has pattern */
-       cmpi    0,len,0         /* Exit if len <= 0 */
-       ble     99f
-       andi.   r0,bufp,3       /* Must be on longword boundary */
-       bne     10f             /* Use byte loop if not aligned */
-       andi.   r0,len,3        /* Check for overrage */
-       subi    bufp,bufp,4     /* Adjust pointer */
-       srawi   len,len,2       /* Divide by 4 */
-       blt     99f             /* If negative - bug out! */
-       mtspr   CTR,len         /* Set up counter */
-       li      pat,0
-00:    stwu    pat,4(bufp)     /* Store value */
-       bdnz    00b             /* Loop [based on counter] */
-       mr      len,r0          /* Get remainder (bytes) */
-10:    cmpi    0,len,0         /* Any bytes left */
-       ble     99f             /* No - all done */
-       mtspr   CTR,len         /* Set up counter */
-       subi    bufp,bufp,1     /* Adjust pointer */
-       li      pat,0
-20:    stbu    pat,1(bufp)     /* Store value */
-       bdnz    20b             /* Loop [based on counter] */
-99:    blr
-#endif
 
-       
 _GLOBAL(abs)
        cmpi    0,r3,0
        bge     10f
@@ -651,39 +298,72 @@ _GLOBAL(abs)
 _GLOBAL(_get_SP)
        mr      r3,r1           /* Close enough */
        blr
-
-_GLOBAL(_get_SDR1)
-       mfspr   r3,SDR1
+       
+_GLOBAL(_get_PVR)
+       mfspr   r3,PVR
        blr
 
-_GLOBAL(_get_SRx)
-       mfsrin  r3,r3
+_GLOBAL(cvt_fd)
+cvt_fd:
+       lfs     0,0(r3)
+       stfd    0,0(r4)
+       blr
+/*
+ * Fetch the current SR register
+ *   get_SR(int index)
+ */
+_GLOBAL(get_SR)
+       mfsrin  r4,r3
+       mr      r3,r4
        blr
 
-_GLOBAL(_get_PVR)
-       mfspr   r3,PVR
+       
+_GLOBAL(cvt_df)
+cvt_df:
+       lfd     0,0(r3)
+       stfs    0,0(r4)
        blr
 
 /*
  * Create a kernel thread
  *   __kernel_thread(flags, fn, arg)
  */
-#if 1
-#define SYS_CLONE      120
 _GLOBAL(__kernel_thread)
-__kernel_thread:
-       li      r0,SYS_CLONE
+       li      r0,__NR_clone
        sc
        cmpi    0,r3,0          /* parent or child? */
        bnelr                   /* return if parent */
        mtlr    r4              /* fn addr in lr */
        mr      r3,r5           /* load arg and call fn */
-       blr
-       li      0, 1            /* exit after child exits */
-        li     3, 0
+       blrl
+       li      r0,__NR_exit    /* exit after child exits */
+        li     r3,0
        sc
-#endif
-       
+
+#define SYSCALL(name) \
+_GLOBAL(name) \
+       li      r0,__NR_##name; \
+       sc; \
+       bnslr; \
+       lis     r4,errno@ha; \
+       stw     r3,errno@l(r4); \
+       li      r3,-1; \
+       blr
+
+#define __NR__exit __NR_exit
+
+SYSCALL(idle)
+SYSCALL(setup)
+SYSCALL(sync)
+SYSCALL(setsid)
+SYSCALL(write)
+SYSCALL(dup)
+SYSCALL(execve)
+SYSCALL(open)
+SYSCALL(close)
+SYSCALL(waitpid)
+
+
 /* Why isn't this a) automatic, b) written in 'C'? */  
        .data
        .align 4
@@ -694,12 +374,12 @@ sys_call_table:
        .long sys_fork
        .long sys_read
        .long sys_write
-       .long sys_open                  /* 5 */
+       .long sys_open          /* 5 */
        .long sys_close
        .long sys_waitpid
        .long sys_creat
        .long sys_link
-       .long sys_unlink                /* 10 */
+       .long sys_unlink        /* 10 */
        .long sys_execve
        .long sys_chdir
        .long sys_time
@@ -709,7 +389,7 @@ sys_call_table:
        .long sys_break
        .long sys_stat
        .long sys_lseek
-       .long sys_getpid                /* 20 */
+       .long sys_getpid        /* 20 */
        .long sys_mount
        .long sys_umount
        .long sys_setuid
@@ -734,12 +414,12 @@ sys_call_table:
        .long sys_pipe
        .long sys_times
        .long sys_prof
-       .long sys_brk                   /* 45 */
+       .long sys_brk           /* 45 */
        .long sys_setgid
        .long sys_getgid
        .long sys_signal
        .long sys_geteuid
-       .long sys_getegid               /* 50 */
+       .long sys_getegid       /* 50 */
        .long sys_acct
        .long sys_phys
        .long sys_lock
@@ -754,57 +434,57 @@ sys_call_table:
        .long sys_ustat
        .long sys_dup2
        .long sys_getppid
-       .long sys_getpgrp               /* 65 */
+       .long sys_getpgrp       /* 65 */
        .long sys_setsid
        .long sys_sigaction
        .long sys_sgetmask
        .long sys_ssetmask
-       .long sys_setreuid              /* 70 */
+       .long sys_setreuid      /* 70 */
        .long sys_setregid
        .long sys_sigsuspend
        .long sys_sigpending
        .long sys_sethostname
-       .long sys_setrlimit             /* 75 */
+       .long sys_setrlimit     /* 75 */
        .long sys_getrlimit
        .long sys_getrusage
        .long sys_gettimeofday
        .long sys_settimeofday
-       .long sys_getgroups             /* 80 */
+       .long sys_getgroups     /* 80 */
        .long sys_setgroups
-       .long sys_select
+       .long ppc_select
        .long sys_symlink
        .long sys_lstat
-       .long sys_readlink              /* 85 */
+       .long sys_readlink      /* 85 */
        .long sys_uselib
        .long sys_swapon
        .long sys_reboot
        .long old_readdir               /* was sys_readdir */
-       .long sys_mmap                  /* 90 */
+       .long sys_mmap          /* 90 */
        .long sys_munmap
        .long sys_truncate
        .long sys_ftruncate
        .long sys_fchmod
-       .long sys_fchown                /* 95 */
+       .long sys_fchown        /* 95 */
        .long sys_getpriority
        .long sys_setpriority
        .long sys_profil
        .long sys_statfs
-       .long sys_fstatfs               /* 100 */
+       .long sys_fstatfs       /* 100 */
        .long sys_ioperm
        .long sys_socketcall
        .long sys_syslog
        .long sys_setitimer
-       .long sys_getitimer             /* 105 */
+       .long sys_getitimer     /* 105 */
        .long sys_newstat
        .long sys_newlstat
        .long sys_newfstat
        .long sys_uname
-       .long sys_iopl                  /* 110 */
+       .long sys_iopl          /* 110 */
        .long sys_vhangup
        .long sys_idle
        .long sys_vm86
        .long sys_wait4
-       .long sys_swapoff               /* 115 */
+       .long sys_swapoff       /* 115 */
        .long sys_sysinfo
        .long sys_ipc
        .long sys_fsync
@@ -814,7 +494,7 @@ sys_call_table:
        .long sys_newuname
        .long sys_modify_ldt
        .long sys_adjtimex
-       .long sys_mprotect              /* 125 */
+       .long sys_mprotect      /* 125 */
        .long sys_sigprocmask
        .long sys_create_module
        .long sys_init_module
@@ -829,9 +509,9 @@ sys_call_table:
        .long 0                         /* for afs_syscall */
        .long sys_setfsuid
        .long sys_setfsgid
-       .long sys_llseek                /* 140 */
+       .long sys_llseek        /* 140 */
         .long sys_getdents
-       .long sys_newselect
+       .long ppc_select
        .long sys_flock
        .long sys_msync
        .long sys_readv         /* 145 */
@@ -844,7 +524,7 @@ sys_call_table:
        .long sys_mlockall
        .long sys_munlockall
        .long sys_sched_setparam
-       .long sys_sched_getparam   /* 155 */
+       .long sys_sched_getparam        /* 155 */
        .long sys_sched_setscheduler
        .long sys_sched_getscheduler
        .long sys_sched_yield
@@ -853,8 +533,11 @@ sys_call_table:
        .long sys_sched_rr_get_interval
        .long sys_nanosleep
        .long sys_mremap
-       .long SYMBOL_NAME(sys_setresuid)
-       .long SYMBOL_NAME(sys_getresuid)
-       .long SYMBOL_NAME(sys_nfsservctl)
-       .space (NR_syscalls-166)*4
+       .long sys_setresuid
+       .long sys_getresuid             /* 165 */
+       .long sys_query_module
+       .long sys_poll
+       .long sys_nfsservctl
+       .long sys_debug
+       .space (NR_syscalls-170)*4
 
index 5e6789a1d550299e5ceb52af4b568f915256f159..3f404a37a81a3abd024d055c29c0a11276546914 100644 (file)
@@ -1,11 +1,14 @@
 /*
  * This program is used to generate definitions needed by
  * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
  */
-#define MK_DEFS
-#include <stdio.h> 
 
-#include <linux/config.h>
+#include <stddef.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/head.h>
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/processor.h>
 
-extern int errno;
+#define DEFINE(sym, val) \
+       asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
 
-main(int argc, char *argv[])
+void
+main(void)
 {
-       FILE *out;
-       struct task_struct task;
-       struct thread_struct tss;
-       int i;
-       char s[256];
-       struct pt_regs regs;
-       if (!(out = fopen(argv[1], "w")))
-       {
-               fprintf(stderr, "Can't create output file: %s\n", strerror(errno));
-               exit(1);
-       }
-       fprintf(out, "/*\n");
-       fprintf(out, " * WARNING! This file is automatically generated - DO NOT EDIT!\n");
-       fprintf(out, " */\n");
-       put_line(out, "STATE", (int)&task.state-(int)&task);
-       put_line(out, "COUNTER", (int)&task.counter-(int)&task);
-       put_line(out, "BLOCKED", (int)&task.blocked-(int)&task);
-       put_line(out, "SIGNAL", (int)&task.signal-(int)&task);
-       put_line(out, "KERNEL_STACK_PAGE", (int)&task.kernel_stack_page-(int)&task);
-       put_line(out, "TSS", (int)&task.tss-(int)&task);
-       put_line(out, "KSP", (int)&tss.ksp-(int)&tss);
-       put_line(out, "LAST_PC", (int)&tss.last_pc-(int)&tss);
-       put_line(out, "USER_STACK", (int)&tss.user_stack-(int)&tss);
-       put_line(out, "PT_REGS", (int)&tss.regs-(int)&tss);
-       put_line(out, "PF_TRACESYS", PF_TRACESYS);
-       put_line(out, "TASK_FLAGS", (int)&task.flags-(int)&task);
-       put_line(out, "MMU_SEG0", (int)&tss.segs[0]-(int)&tss);
-       put_line(out, "MMU_SEG1", (int)&tss.segs[1]-(int)&tss);
-       put_line(out, "MMU_SEG2", (int)&tss.segs[2]-(int)&tss);
-       put_line(out, "MMU_SEG3", (int)&tss.segs[3]-(int)&tss);
-       put_line(out, "MMU_SEG4", (int)&tss.segs[4]-(int)&tss);
-       put_line(out, "MMU_SEG5", (int)&tss.segs[5]-(int)&tss);
-       put_line(out, "MMU_SEG6", (int)&tss.segs[6]-(int)&tss);
-       put_line(out, "MMU_SEG7", (int)&tss.segs[7]-(int)&tss);
-       put_line(out, "MMU_SEG8", (int)&tss.segs[8]-(int)&tss);
-       put_line(out, "MMU_SEG9", (int)&tss.segs[9]-(int)&tss);
-       put_line(out, "MMU_SEG10", (int)&tss.segs[10]-(int)&tss);
-       put_line(out, "MMU_SEG11", (int)&tss.segs[11]-(int)&tss);
-       put_line(out, "MMU_SEG12", (int)&tss.segs[12]-(int)&tss);
-       put_line(out, "MMU_SEG13", (int)&tss.segs[13]-(int)&tss);
-       put_line(out, "MMU_SEG14", (int)&tss.segs[14]-(int)&tss);
-       put_line(out, "MMU_SEG15", (int)&tss.segs[15]-(int)&tss);
-       put_line(out, "TSS_EXPC", (int)&tss.expc-(int)&tss);
-       put_line(out, "TSS_EXCOUNT", (int)&tss.excount-(int)&tss);              
-       put_line(out, "TSS_FPR0", (int)&tss.fpr[0]-(int)&tss);
-       put_line(out, "TSS_FPR1", (int)&tss.fpr[1]-(int)&tss);
-       put_line(out, "TSS_FPR2", (int)&tss.fpr[2]-(int)&tss);
-       put_line(out, "TSS_FPR3", (int)&tss.fpr[3]-(int)&tss);
-       put_line(out, "TSS_FPR4", (int)&tss.fpr[4]-(int)&tss);
-       put_line(out, "TSS_FPR5", (int)&tss.fpr[5]-(int)&tss);
-       put_line(out, "TSS_FPR6", (int)&tss.fpr[6]-(int)&tss);
-       put_line(out, "TSS_FPR7", (int)&tss.fpr[7]-(int)&tss);
-       put_line(out, "TSS_FPR8", (int)&tss.fpr[8]-(int)&tss);
-       put_line(out, "TSS_FPR9", (int)&tss.fpr[9]-(int)&tss);
-       put_line(out, "TSS_FPR10", (int)&tss.fpr[10]-(int)&tss);
-       put_line(out, "TSS_FPR11", (int)&tss.fpr[11]-(int)&tss);
-       put_line(out, "TSS_FPR12", (int)&tss.fpr[12]-(int)&tss);
-       put_line(out, "TSS_FPR13", (int)&tss.fpr[13]-(int)&tss);
-       put_line(out, "TSS_FPR14", (int)&tss.fpr[14]-(int)&tss);
-       put_line(out, "TSS_FPR15", (int)&tss.fpr[15]-(int)&tss);
-       put_line(out, "TSS_FPR16", (int)&tss.fpr[16]-(int)&tss);
-       put_line(out, "TSS_FPR17", (int)&tss.fpr[17]-(int)&tss);
-       put_line(out, "TSS_FPR18", (int)&tss.fpr[18]-(int)&tss);
-       put_line(out, "TSS_FPR19", (int)&tss.fpr[19]-(int)&tss);
-       put_line(out, "TSS_FPR20", (int)&tss.fpr[20]-(int)&tss);
-       put_line(out, "TSS_FPR21", (int)&tss.fpr[21]-(int)&tss);
-       put_line(out, "TSS_FPR22", (int)&tss.fpr[22]-(int)&tss);
-       put_line(out, "TSS_FPR23", (int)&tss.fpr[23]-(int)&tss);
-       put_line(out, "TSS_FPR24", (int)&tss.fpr[24]-(int)&tss);
-       put_line(out, "TSS_FPR25", (int)&tss.fpr[25]-(int)&tss);
-       put_line(out, "TSS_FPR26", (int)&tss.fpr[26]-(int)&tss);
-       put_line(out, "TSS_FPR27", (int)&tss.fpr[27]-(int)&tss);
-       put_line(out, "TSS_FPR28", (int)&tss.fpr[28]-(int)&tss);
-       put_line(out, "TSS_FPR29", (int)&tss.fpr[29]-(int)&tss);
-       put_line(out, "TSS_FPR30", (int)&tss.fpr[30]-(int)&tss);
-       put_line(out, "TSS_FPR31", (int)&tss.fpr[31]-(int)&tss);
-       put_line(out, "TSS_FP_USED", (int)&tss.fp_used-(int)&tss);
-       /* Interrupt register frame */
-       put_line(out, "INT_FRAME_SIZE", sizeof(regs));
-       put_line(out, "GPR0", (int)&regs.gpr[0]-(int)&regs);
-       put_line(out, "GPR1", (int)&regs.gpr[1]-(int)&regs);
-       put_line(out, "GPR2", (int)&regs.gpr[2]-(int)&regs);
-       put_line(out, "GPR3", (int)&regs.gpr[3]-(int)&regs);
-       put_line(out, "GPR4", (int)&regs.gpr[4]-(int)&regs);
-       put_line(out, "GPR5", (int)&regs.gpr[5]-(int)&regs);
-       put_line(out, "GPR6", (int)&regs.gpr[6]-(int)&regs);
-       put_line(out, "GPR7", (int)&regs.gpr[7]-(int)&regs);
-       put_line(out, "GPR8", (int)&regs.gpr[8]-(int)&regs);
-       put_line(out, "GPR9", (int)&regs.gpr[9]-(int)&regs);
-       put_line(out, "GPR10", (int)&regs.gpr[10]-(int)&regs);
-       put_line(out, "GPR11", (int)&regs.gpr[11]-(int)&regs);
-       put_line(out, "GPR12", (int)&regs.gpr[12]-(int)&regs);
-       put_line(out, "GPR13", (int)&regs.gpr[13]-(int)&regs);
-       put_line(out, "GPR14", (int)&regs.gpr[14]-(int)&regs);
-       put_line(out, "GPR15", (int)&regs.gpr[15]-(int)&regs);
-       put_line(out, "GPR16", (int)&regs.gpr[16]-(int)&regs);
-       put_line(out, "GPR17", (int)&regs.gpr[17]-(int)&regs);
-       put_line(out, "GPR18", (int)&regs.gpr[18]-(int)&regs);
-       put_line(out, "GPR19", (int)&regs.gpr[19]-(int)&regs);
-       put_line(out, "GPR20", (int)&regs.gpr[20]-(int)&regs);
-       put_line(out, "GPR21", (int)&regs.gpr[21]-(int)&regs);
-       put_line(out, "GPR22", (int)&regs.gpr[22]-(int)&regs);
-       put_line(out, "GPR23", (int)&regs.gpr[23]-(int)&regs);
-       put_line(out, "GPR24", (int)&regs.gpr[24]-(int)&regs);
-       put_line(out, "GPR25", (int)&regs.gpr[25]-(int)&regs);
-       put_line(out, "GPR26", (int)&regs.gpr[26]-(int)&regs);
-       put_line(out, "GPR27", (int)&regs.gpr[27]-(int)&regs);
-       put_line(out, "GPR28", (int)&regs.gpr[28]-(int)&regs);
-       put_line(out, "GPR29", (int)&regs.gpr[29]-(int)&regs);
-       put_line(out, "GPR30", (int)&regs.gpr[30]-(int)&regs);
-       put_line(out, "GPR31", (int)&regs.gpr[31]-(int)&regs);
-#if 0  
-       for ( i = 0 ; i <= 31 ; i++)
-       {
-         sprintf(s,"FPR%d",i);
-         put_line(out, s, (int)&regs.fpr[i]-(int)&regs);
-       }
+       /*DEFINE(KERNELBASE, KERNELBASE);*/
+       DEFINE(STATE, offsetof(struct task_struct, state));
+       DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
+       DEFINE(COUNTER, offsetof(struct task_struct, counter));
+       DEFINE(BLOCKED, offsetof(struct task_struct, blocked));
+       DEFINE(SIGNAL, offsetof(struct task_struct, signal));
+       DEFINE(TSS, offsetof(struct task_struct, tss));
+       DEFINE(KSP, offsetof(struct thread_struct, ksp));
+       DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
+#ifdef CONFIG_PMAC     
+       DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
+       DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
+#endif 
+       DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
+       DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
+       DEFINE(PF_TRACESYS, PF_TRACESYS);
+       DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+       DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
+#if 0
+       DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
+       DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
+       DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
+       DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
+       DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
+       DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
+       DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
+       DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
+       DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
+       DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
+       DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
+       DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
+       DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
+       DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
+       DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
+       DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
+       DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
+       DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
+       DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
+       DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
+       DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
+       DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
+       DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
+       DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
+       DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
+       DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
+       DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
+       DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
+       DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
+       DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
+       DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
 #endif
-       put_line(out, "FPCSR", (int)&regs.fpcsr-(int)&regs);
-       /* Note: these symbols include "_" because they overlap with special register names */
-       put_line(out, "_NIP", (int)&regs.nip-(int)&regs);
-       put_line(out, "_MSR", (int)&regs.msr-(int)&regs);
-       /*              put_line(out, "_SRR1", (int)&regs.srr1-(int)&regs);     
-       put_line(out, "_SRR0", (int)&regs.srr0-(int)&regs);     */
-       put_line(out, "_CTR", (int)&regs.ctr-(int)&regs);
-       put_line(out, "_LINK", (int)&regs.link-(int)&regs);
-       put_line(out, "_CCR", (int)&regs.ccr-(int)&regs);
-       put_line(out, "_XER", (int)&regs.xer-(int)&regs);
-       put_line(out, "_DAR", (int)&regs.dar-(int)&regs);
-       put_line(out, "_DSISR", (int)&regs.dsisr-(int)&regs);
-       put_line(out, "_HASH1", (int)&regs.hash1-(int)&regs);
-       put_line(out, "_HASH2", (int)&regs.hash2-(int)&regs);
-       put_line(out, "_IMISS", (int)&regs.imiss-(int)&regs);
-       put_line(out, "_DMISS", (int)&regs.dmiss-(int)&regs);
-       put_line(out, "_ICMP", (int)&regs.icmp-(int)&regs);
-       put_line(out, "_DCMP", (int)&regs.dcmp-(int)&regs);
-       put_line(out, "ORIG_GPR3", (int)&regs.orig_gpr3-(int)&regs);
-       put_line(out, "RESULT", (int)&regs.result-(int)&regs);
-       put_line(out, "TRAP", (int)&regs.trap-(int)&regs);
-       put_line(out, "MARKER", (int)&regs.marker-(int)&regs);
-       exit(0);
-}
-
-put_line(FILE *out, char *name, int offset)
-{
-       fprintf(out, "#define %s %d\n", name, offset);
+       DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+       /* Interrupt register frame */
+       DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
+       DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
+       DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+       DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+       DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+       DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
+       DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
+       DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
+       DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
+       DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
+       DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
+       DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
+       DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
+       DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
+       DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
+       DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
+       DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
+       DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14]));
+       DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15]));
+       DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16]));
+       DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17]));
+       DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18]));
+       DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19]));
+       DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
+       DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
+       DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
+       DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
+       DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24]));
+       DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25]));
+       DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26]));
+       DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27]));
+       DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28]));
+       DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29]));
+       DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30]));
+       DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31]));
+       /* Note: these symbols include _ because they overlap with special register names */
+       DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
+       DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
+       DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
+       DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
+       DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+       DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
+       DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+       DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+       DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
+       DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
+       DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
 }
index 74f796792e1f86c903c61ad6a8c144814bba257e..612a24bffaaeeb39a5b8be1325e839231085cef5 100644 (file)
 #include <linux/bios32.h>
 #include <linux/pci.h>
 
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+
 /*
  * PCI interrupt configuration.  This is motherboard specific.
  */
 /* Which PCI interrupt line does a given device [slot] use? */
 /* Note: This really should be two dimensional based in slot/pin used */
 unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
 
 /* How is the 82378 PIRQ mapping setup? */
 unsigned char *Motherboard_routes;
@@ -27,7 +31,7 @@ unsigned char *Motherboard_routes;
 
 /* Motorola PowerStack */
 static char Blackhawk_pci_IRQ_map[16] =
-  {
+{
        0,      /* Slot 0  - unused */
        0,      /* Slot 1  - unused */
        0,      /* Slot 2  - unused */
@@ -44,20 +48,20 @@ static char Blackhawk_pci_IRQ_map[16] =
        0,      /* Slot 13 - unused */
        1,      /* Slot 14 - Ethernet */
        0,      /* Slot 15 - unused */
-  };
+};
 
 static char Blackhawk_pci_IRQ_routes[] =
-   {
+{
        0,      /* Line 0 - Unused */
        9,      /* Line 1 */
        11,     /* Line 2 */
        14,     /* Line 3 */
        15      /* Line 4 */
-   };
+};
    
 /* Motorola MVME16xx */
 static char Genesis_pci_IRQ_map[16] =
-  {
+{
        0,      /* Slot 0  - unused */
        0,      /* Slot 1  - unused */
        0,      /* Slot 2  - unused */
@@ -74,20 +78,20 @@ static char Genesis_pci_IRQ_map[16] =
        0,      /* Slot 13 - unused */
        1,      /* Slot 14 - Ethernet */
        0,      /* Slot 15 - unused */
-  };
+};
 
 static char Genesis_pci_IRQ_routes[] =
-   {
+{
        0,      /* Line 0 - Unused */
        10,     /* Line 1 */
        11,     /* Line 2 */
        14,     /* Line 3 */
        15      /* Line 4 */
-   };
+};
    
 /* Motorola Series-E */
 static char Comet_pci_IRQ_map[16] =
-  {
+{
        0,      /* Slot 0  - unused */
        0,      /* Slot 1  - unused */
        0,      /* Slot 2  - unused */
@@ -104,20 +108,20 @@ static char Comet_pci_IRQ_map[16] =
        0,      /* Slot 13 - unused */
        1,      /* Slot 14 - Ethernet */
        0,      /* Slot 15 - unused */
-  };
+};
 
 static char Comet_pci_IRQ_routes[] =
-   {
+{
        0,      /* Line 0 - Unused */
        10,     /* Line 1 */
        11,     /* Line 2 */
        14,     /* Line 3 */
        15      /* Line 4 */
-   };
+};
 
 /* BeBox */
 static char BeBox_pci_IRQ_map[16] =
-  {
+{
        0,      /* Slot 0  - unused */
        0,      /* Slot 1  - unused */
        0,      /* Slot 2  - unused */
@@ -134,20 +138,20 @@ static char BeBox_pci_IRQ_map[16] =
        0,      /* Slot 13 - unused */
        0,      /* Slot 14 - unused */
        0,      /* Slot 15 - unused */
-  };
+};
 
 static char BeBox_pci_IRQ_routes[] =
-   {
+{
        0,      /* Line 0 - Unused */
        9,      /* Line 1 */
        11,     /* Line 2 */
        14,     /* Line 3 */
        15      /* Line 4 */
-   };
+};
 
 /* IBM Nobis */
 static char Nobis_pci_IRQ_map[16] =
-  {
+{
        0,      /* Slot 0  - unused */
        0,      /* Slot 1  - unused */
        0,      /* Slot 2  - unused */
@@ -164,54 +168,83 @@ static char Nobis_pci_IRQ_map[16] =
        0,      /* Slot 13 - unused */
        0,      /* Slot 14 - unused */
        0,      /* Slot 15 - unused */
-  };
+};
 
 static char Nobis_pci_IRQ_routes[] =
-   {
+{
        0,      /* Line 0 - Unused */
        13,     /* Line 1 */
        13,     /* Line 2 */
        13,     /* Line 3 */
        13      /* Line 4 */
-   };
+};
+
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - FireCoral */
+        4, /* Slot 12 - Ethernet  PCIINTD# */
+        2, /* Slot 13 - PCI Slot #2 */
+        2, /* Slot 14 - S3 Video PCIINTD# */
+        0, /* Slot 15 - onboard SCSI (INDI) [1] */
+        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+        0, /* Slot 17 - unused */
+        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+        0, /* Slot 19 - unused */
+        0, /* Slot 20 - unused */
+        0, /* Slot 21 - unused */
+        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+static char ibm8xx_pci_IRQ_routes[] = {
+        0,      /* Line 0 - unused */
+        13,     /* Line 1 */
+        10,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
+ * it really needs some logic to set them to unique IRQ's, or even
+ * add some logic to the drivers to ask an irq.c routine to re-map
+ * the IRQ if it needs one to itself...
+ */
+static char Carolina_PIRQ_routes[] = {
+   0xad,       /* INTB# = 10, INTA# = 13 */
+   0xff                /* INTD# = 15, INTC# = 15 */
+};
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+#define CAROLINA_IRQ_EDGE_MASK_LO   0x00  /* IRQ's 0-7  */
+#define CAROLINA_IRQ_EDGE_MASK_HI   0xA4  /* IRQ's 8-15 [10,13,15] */
+#define PCI_DEVICE_ID_IBM_CORAL                0x000a
 
-#define PCI_DEBUG
 #undef  PCI_DEBUG
 
 #ifdef PCI_STATS
 int PCI_conversions[2];
 #endif
 
-unsigned long pcibios_init(unsigned long mem_start,
-                          unsigned long mem_end)
-{
-       return mem_start;
-}
 
 unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
 {
-  return mem_start;
-}
-
-
-unsigned long
-_LE_to_BE_long(unsigned long val)
-{
-       unsigned char *p = (unsigned char *)&val;
-#ifdef PCI_STATS
-       PCI_conversions[0]++;
-#endif 
-       return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0] << 0));
-}
-
-unsigned short
-_LE_to_BE_short(unsigned long val)
-{
-       unsigned char *p = (unsigned char *)&val;
-#ifdef PCI_STATS
-       PCI_conversions[1]++;
-#endif 
-       return ((p[3] << 8) | (p[2] << 0));
+       return mem_start;
 }
 
 int
@@ -225,7 +258,7 @@ pcibios_present (void)
 
 int
 pcibios_read_config_dword (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned int *val)
+                          unsigned char dev, unsigned char offset, unsigned int *val)
 {
        unsigned long _val;
        unsigned long *ptr;
@@ -243,7 +276,7 @@ pcibios_read_config_dword (unsigned char bus,
 #ifdef PCI_DEBUG       
                printk("[%x] ", ptr);
 #endif         
-               _val = _LE_to_BE_long(*ptr);
+               _val = le32_to_cpu(*ptr);
        }
 #ifdef PCI_DEBUG       
        printk("%x\n", _val);
@@ -254,27 +287,27 @@ pcibios_read_config_dword (unsigned char bus,
 
 int
 pcibios_read_config_word (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned short *val)
+                         unsigned char dev, unsigned char offset, unsigned short *val)
 {
        unsigned short _val;
        unsigned short *ptr;
        dev >>= 3;
-#ifdef PCI_DEBUG       
+#ifdef PCI_DEBUG
        printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
 #endif 
        if ((bus != 0) || (dev < 11) || (dev > 16))
        {
-               *val = 0xFFFFFFFF;
+               *val = (unsigned short)0xFFFFFFFF;
                return PCIBIOS_DEVICE_NOT_FOUND;
        } else
        {
                ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG       
+#ifdef PCI_DEBUG
                printk("[%x] ", ptr);
 #endif         
-               _val = _LE_to_BE_short(*ptr);
+               _val = le16_to_cpu(*ptr);
        }
-#ifdef PCI_DEBUG       
+#ifdef PCI_DEBUG
        printk("%x\n", _val);
 #endif         
        *val = _val;
@@ -283,7 +316,7 @@ pcibios_read_config_word (unsigned char bus,
 
 int
 pcibios_read_config_byte (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned char *val)
+                         unsigned char dev, unsigned char offset, unsigned char *val)
 {
        unsigned char _val;
        volatile unsigned char *ptr;
@@ -294,6 +327,9 @@ pcibios_read_config_byte (unsigned char bus,
                if (Motherboard_map[dev] <= 4)
                {
                        *val = Motherboard_routes[Motherboard_map[dev]];
+                       /*printk("dev %d map %d route %d\n",
+                         dev,Motherboard_map[dev],
+                         Motherboard_routes[Motherboard_map[dev]]);*/
                } else
                { /* Pseudo interrupts [for BeBox] */
                        *val = Motherboard_map[dev];
@@ -327,12 +363,12 @@ pcibios_read_config_byte (unsigned char bus,
 
 int
 pcibios_write_config_dword (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned int val)
+                           unsigned char dev, unsigned char offset, unsigned int val)
 {
        unsigned long _val;
        unsigned long *ptr;
        dev >>= 3;
-       _val = _LE_to_BE_long(val);
+       _val = le32_to_cpu(val);
 #ifdef PCI_DEBUG       
        printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
 #endif         
@@ -349,12 +385,12 @@ pcibios_write_config_dword (unsigned char bus,
 
 int
 pcibios_write_config_word (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned short val)
+                          unsigned char dev, unsigned char offset, unsigned short val)
 {
        unsigned short _val;
        unsigned short *ptr;
        dev >>= 3;
-       _val = _LE_to_BE_short(val);
+       _val = le16_to_cpu(val);
 #ifdef PCI_DEBUG       
        printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
 #endif         
@@ -371,7 +407,7 @@ pcibios_write_config_word (unsigned char bus,
 
 int
 pcibios_write_config_byte (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned char val)
+                          unsigned char dev, unsigned char offset, unsigned char val)
 {
        unsigned char _val;
        unsigned char *ptr;
@@ -420,7 +456,7 @@ pcibios_find_device (unsigned short vendor, unsigned short device_id,
 
 int
 pcibios_find_class (unsigned int class_code, unsigned short index, 
-    unsigned char *bus, unsigned char *dev)
+                   unsigned char *bus, unsigned char *dev)
 {
        int dev_nr, class, indx;
        indx = 0;
@@ -437,7 +473,7 @@ pcibios_find_class (unsigned int class_code, unsigned short index,
                                *bus = 0;
                                *dev = dev_nr<<3;
 #ifdef PCI_DEBUG
-       printk(" - device: %x\n", dev_nr);
+                               printk(" - device: %x\n", dev_nr);
 #endif 
                                return (0);
                        }
@@ -455,22 +491,22 @@ const char *pcibios_strerror(int error)
        static char buf[32];
        switch (error)
        {       case PCIBIOS_SUCCESSFUL:
-                       return ("PCI BIOS: no error");
-               case PCIBIOS_FUNC_NOT_SUPPORTED:
-                       return ("PCI BIOS: function not supported");
-               case PCIBIOS_BAD_VENDOR_ID:
-                       return ("PCI BIOS: bad vendor ID");
-               case PCIBIOS_DEVICE_NOT_FOUND:
-                       return ("PCI BIOS: device not found");
-               case PCIBIOS_BAD_REGISTER_NUMBER:
-                       return ("PCI BIOS: bad register number");
-               case PCIBIOS_SET_FAILED:
-                       return ("PCI BIOS: set failed");
-               case PCIBIOS_BUFFER_TOO_SMALL:
-                       return ("PCI BIOS: buffer too small");
-               default:
-                       sprintf(buf, "PCI BIOS: invalid error #%d", error);
-                       return(buf);
+               return ("PCI BIOS: no error");
+       case PCIBIOS_FUNC_NOT_SUPPORTED:
+               return ("PCI BIOS: function not supported");
+       case PCIBIOS_BAD_VENDOR_ID:
+               return ("PCI BIOS: bad vendor ID");
+       case PCIBIOS_DEVICE_NOT_FOUND:
+               return ("PCI BIOS: device not found");
+       case PCIBIOS_BAD_REGISTER_NUMBER:
+               return ("PCI BIOS: bad register number");
+       case PCIBIOS_SET_FAILED:
+               return ("PCI BIOS: set failed");
+       case PCIBIOS_BUFFER_TOO_SMALL:
+               return ("PCI BIOS: buffer too small");
+       default:
+               sprintf(buf, "PCI BIOS: invalid error #%d", error);
+               return(buf);
        }
 }
 
@@ -478,42 +514,112 @@ const char *pcibios_strerror(int error)
  * Note: This routine has to access the PCI configuration space
  * for the PCI bridge chip (Intel 82378).
  */
-void route_PCI_interrupts(void)
+unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
+{
+       return mem_start;
+}
+
+unsigned long route_pci_interrupts(void)
 {
        unsigned char *ibc_pirq = (unsigned char *)0x80800860;
        unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
        extern unsigned long isBeBox[];
        int i;
-       /* Decide which motherboard this is & how the PCI interrupts are routed */
-       if (isBeBox[0])
-       {
-               Motherboard_map = BeBox_pci_IRQ_map;
-               Motherboard_routes = BeBox_pci_IRQ_routes;
-       } else
-       if ((_get_PVR()>>16) == 1)
-       { /* Nobis */
-               Motherboard_map = Nobis_pci_IRQ_map;
-               Motherboard_routes = Nobis_pci_IRQ_routes;
-       } else
-       { /* Motorola hardware */
+       
+       if ( _machine == _MACH_Motorola)
+       { 
                switch (inb(0x800) & 0xF0)
                {
-                       case 0x10: /* MVME16xx */
-                               Motherboard_map = Genesis_pci_IRQ_map;
-                               Motherboard_routes = Genesis_pci_IRQ_routes;
-                               break;
-                       case 0x20: /* Series E */
-                               Motherboard_map = Comet_pci_IRQ_map;
-                               Motherboard_routes = Comet_pci_IRQ_routes;
-                               break;
-                       case 0x40: /* PowerStack */
-                       default: /* Can't hurt, can it? */
-                               Motherboard_map = Blackhawk_pci_IRQ_map;
-                               Motherboard_routes = Blackhawk_pci_IRQ_routes;
-                               break;
+               case 0x10: /* MVME16xx */
+                       Motherboard_map_name = "Genesis";
+                       Motherboard_map = Genesis_pci_IRQ_map;
+                       Motherboard_routes = Genesis_pci_IRQ_routes;
+                       break;
+               case 0x20: /* Series E */
+                       Motherboard_map_name = "Series E";
+                       Motherboard_map = Comet_pci_IRQ_map;
+                       Motherboard_routes = Comet_pci_IRQ_routes;
+                       break;
+               case 0x40: /* PowerStack */
+               default: /* Can't hurt, can it? */
+                       Motherboard_map_name = "Blackhawk (Powerstack)";
+                       Motherboard_map = Blackhawk_pci_IRQ_map;
+                       Motherboard_routes = Blackhawk_pci_IRQ_routes;
+                       break;
+               }
+       } else
+       {
+               if ( _machine == _MACH_IBM )
+               {
+                       unsigned char pl_id;
+                       unsigned long flags;
+                       unsigned index;
+                       unsigned char fn, bus;
+                       unsigned int addr;
+                       unsigned char dma_mode, ide_mode;
+                       int i;
+                       
+                       Motherboard_map_name = "IBM 8xx (Carolina)";
+                       Motherboard_map = ibm8xx_pci_IRQ_map;
+                       Motherboard_routes = ibm8xx_pci_IRQ_routes;
+ll_printk("before loop\n");                    
+                       
+                       for (index = 0;
+                            !pcibios_find_device (PCI_VENDOR_ID_IBM, 
+                                                  PCI_DEVICE_ID_IBM_CORAL, 
+                                                  index, &bus, &fn); ++index)
+                       {
+                               pcibios_read_config_dword(bus, fn, 0x10, &addr);
+                               addr &= ~0x3;
+                               outb(0x26, addr);
+                               dma_mode = inb(addr+4);
+                               outb(0x25, addr);
+                               ide_mode = inb(addr+4);
+                               /*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x", 
+                                      addr, dma_mode, ide_mode);*/
+                               /* Make CDROM non-DMA */
+                               ide_mode = (ide_mode & 0x0F) | 0x20;
+                               outb(0x25, addr);
+                               outb(ide_mode, addr+4);
+                               dma_mode = dma_mode & ~0x80;
+                               outb(0x26, addr);
+                               outb(dma_mode, addr+4);
+                               outb(0x26, addr);
+                               dma_mode = inb(addr+4);
+                               outb(0x25, addr);
+                               ide_mode = inb(addr+4);
+                               /*printk("=> DMA mode: %x, IDE mode: %x\n", 
+                                      dma_mode, ide_mode);*/
+                       }
+                       
+                       /* Setup the PCI INT mappings for the Carolina */
+                       /* These are PCI Interrupt Route Control [1|2] Register */
+                       outb(Carolina_PIRQ_routes[0], 0x0890);
+                       outb(Carolina_PIRQ_routes[1], 0x0891);
+                       
+                       pl_id=inb(0x0852);
+                       /*printk("CPU Planar ID is %#0x\n", pl_id);*/
+                       
+                       if (pl_id == 0x0C) {
+                               /* INDI */
+                               Motherboard_map[12] = 1;
+                       }
+ll_printk("before edge/level\n");                      
+#if 0                  
+                       /*printk("Changing IRQ mode\n");*/
+                       pl_id=inb(0x04d0);
+                       /*printk("Low mask is %#0x\n", pl_id);*/
+                       outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
+                       
+                       pl_id=inb(0x04d1);
+                       /*printk("Hi mask is  %#0x\n", pl_id);*/
+                       outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
+                       pl_id=inb(0x04d1);
+                       /*printk("Hi mask now %#0x\n", pl_id);*/
+#endif                 
                }
        }
+       
        /* Set up mapping from slots */
        for (i = 1;  i <= 4;  i++)
        {
@@ -521,4 +627,4 @@ void route_PCI_interrupts(void)
        }
        /* Enable PCI interrupts */
        *ibc_pcicon |= 0x20;
-} 
+}
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
new file mode 100644 (file)
index 0000000..468025f
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Derived from "arch/alpha/kernel/setup.c"
+ *    Copyright (C) 1995 Linus Torvalds
+ *
+ *  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.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/ide.h>
+
+extern int root_mountflags;
+
+extern char command_line[];
+char saved_command_line[256];
+
+unsigned char aux_device_present;      /* XXX */
+unsigned char kbd_read_mask;
+unsigned char drive_info;
+
+#define DEFAULT_ROOT_DEVICE 0x0801     /* sda1 - slightly silly choice */
+
+extern unsigned long find_available_memory(void);
+
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+       return memory_start;
+}
+
+void setup_arch(char **cmdline_p,
+       unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+       extern unsigned long *end_of_DRAM;
+       struct device_node *cpu;
+       int *fp;
+
+       strcpy(saved_command_line, command_line);
+       *cmdline_p = command_line;
+
+       *memory_start_p = find_available_memory();
+       *memory_end_p = (unsigned long) end_of_DRAM;
+
+       set_prom_callback();
+
+       *memory_start_p = copy_device_tree(*memory_start_p, *memory_end_p);
+
+       /* Set loops_per_sec to a half-way reasonable value,
+          for use until calibrate_delay gets called. */
+       cpu = find_type_devices("cpu");
+       if (cpu != 0) {
+               fp = (int *) get_property(cpu, "clock-frequency", NULL);
+               if (fp != 0) {
+                       switch (_get_PVR() >> 16) {
+                       case 4:         /* 604 */
+                               loops_per_sec = *fp;
+                               break;
+                       default:        /* 601, 603, etc. */
+                               loops_per_sec = *fp / 2;
+                       }
+               } else
+                       loops_per_sec = 50000000;
+       }
+}
+
+char *bootpath;
+char bootdevice[256];
+void *boot_host;
+int boot_target;
+int boot_part;
+kdev_t boot_dev;
+
+unsigned long
+pmac_find_devices(unsigned long mem_start, unsigned long mem_end)
+{
+       struct device_node *chosen_np;
+
+       nvram_init();
+       via_cuda_init();
+       read_rtc_time();
+       pmac_find_display();
+       bootpath = NULL;
+       chosen_np = find_devices("chosen");
+       if (chosen_np != NULL)
+               bootpath = (char *) get_property(chosen_np, "bootpath", NULL);
+       if (bootpath != NULL) {
+               /*
+                * There's a bug in the prom.  (Why am I not surprised.)
+                * If you pass a path like scsi/sd@1:0 to canon, it returns
+                * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+                * That is, the scsi target number doesn't get preserved.
+                */
+               call_prom("canon", 3, 1, bootpath, bootdevice, sizeof(bootdevice));
+       }
+       return mem_start;
+}
+
+void
+note_scsi_host(struct device_node *node, void *host)
+{
+       int l;
+       char *p;
+
+       l = strlen(node->full_name);
+       if (strncmp(node->full_name, bootdevice, l) == 0
+           && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+               boot_host = host;
+               p = strstr(bootpath, "/sd@");
+               if (p != NULL) {
+                       p += 4;
+                       boot_target = simple_strtoul(p, NULL, 10);
+                       p = strchr(p, ':');
+                       if (p != NULL)
+                               boot_part = simple_strtoul(p + 1, NULL, 10);
+               }
+       }
+}
+
+void find_scsi_boot()
+{
+       int dev;
+
+       if (kdev_t_to_nr(ROOT_DEV) != 0)
+               return;
+       ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+       if (boot_host == NULL)
+               return;
+       dev = sd_find_target(boot_host, boot_target);
+       if (dev == 0)
+               return;
+       boot_dev = to_kdev_t(dev + boot_part);
+}
+
+void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+       struct device_node *np;
+       int i;
+       static struct device_node *atas;
+       static int atas_valid;
+
+       *p = 0;
+       *irq = 0;
+       if (!atas_valid) {
+               atas = find_devices("ATA");
+               atas_valid = 1;
+       }
+       for (i = (int)base, np = atas; i > 0 && np != NULL; --i, np = np->next)
+               ;
+       if (np == NULL)
+               return;
+       if (np->n_addrs == 0) {
+               printk("ide: no addresses for device %s\n", np->full_name);
+               return;
+       }
+       if (np->n_intrs == 0) {
+               printk("ide: no intrs for device %s, using 13\n",
+                      np->full_name);
+               np->intrs[0] = 13;
+       }
+       base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
+       for (i = 0; i < 8; ++i)
+               *p++ = base + i * 0x10;
+       *p = base + 0x160;
+       *irq = np->intrs[0];
+}
+
+int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+       return -EIO;
+}
+
+#if 0
+extern char builtin_ramdisk_image;
+extern long builtin_ramdisk_size;
+#endif
+
+void
+builtin_ramdisk_init(void)
+{
+#if 0
+       if ((ROOT_DEV == to_kdev_t(DEFAULT_ROOT_DEVICE)) && (builtin_ramdisk_size != 0))
+       {
+               rd_preloaded_init(&builtin_ramdisk_image, builtin_ramdisk_size);
+       } else
+#endif
+       {  /* Not ramdisk - assume root needs to be mounted read only */
+               root_mountflags |= MS_RDONLY;
+       }
+}
+
+int
+get_cpuinfo(char *buffer)
+{
+       int pvr = _get_PVR();
+       char *model;
+       struct device_node *cpu;
+       int l, *fp;
+
+       l = 0;
+       cpu = find_type_devices("cpu");
+       if (cpu != 0) {
+               fp = (int *) get_property(cpu, "clock-frequency", NULL);
+               if (fp != 0)
+                       l += sprintf(buffer, "%dMHz ", *fp / 1000000);
+       }
+
+       switch (pvr>>16) {
+       case 1:
+               model = "601";
+               break;
+       case 3:
+               model = "603";
+               break;
+       case 4:
+               model = "604";
+               break;
+       case 6:
+               model = "603e";
+               break;
+       case 7:
+               model = "603ev";
+               break;
+       default:
+               model = "unknown";
+               break;
+       }
+       return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
+                          (pvr & 0xff) >> 8, pvr & 0xff);
+}
diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c
new file mode 100644 (file)
index 0000000..ad2c0fb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ */
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+
+void hard_reset_now(void)
+{
+       struct cuda_request req;
+
+       cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+       for (;;)
+               cuda_poll();
+}
+
+void poweroff_now(void)
+{
+       struct cuda_request req;
+
+       cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
+       for (;;)
+               cuda_poll();
+}
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+
+void nvram_init(void)
+{
+       struct device_node *dp;
+
+       dp = find_devices("nvram");
+       if (dp == NULL)
+               panic("Can't find NVRAM device");
+       nvram_naddrs = dp->n_addrs;
+       if (nvram_naddrs == 1)
+               nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+       else if (nvram_naddrs == 2) {
+               nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+               nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+       } else {
+               printk("Found %d addresses for NVRAM\n", nvram_naddrs);
+               panic("don't understand NVRAM");
+       }
+}
+
+int nvram_readb(int addr)
+{
+       switch (nvram_naddrs) {
+       case 1:
+               return nvram_data[(addr & 0x1fff) << 4];
+       case 2:
+               *nvram_addr = addr >> 5;
+               eieio();
+               return nvram_data[(addr & 0x1f) << 4];
+       }
+       return -1;
+}
+
+void nvram_writeb(int addr, int val)
+{
+       switch (nvram_naddrs) {
+       case 1:
+               nvram_data[(addr & 0x1fff) << 4] = val;
+               break;
+       case 2:
+               *nvram_addr = addr >> 5;
+               eieio();
+               nvram_data[(addr & 0x1f) << 4] = val;
+               break;
+       }
+       eieio();
+}
diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c
new file mode 100644 (file)
index 0000000..25df5ff
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * At present, we use the decrementer register in the 601 CPU
+ * for our periodic interrupts.  This will probably have to be
+ * changed for other processors.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+static int get_dec(void);
+static void set_dec(int);
+static unsigned long get_rtc_time(void);
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET     2082844800
+
+/* Accessor functions for the decrementer register. */
+static inline int
+get_dec()
+{
+    int ret;
+
+    asm volatile("mfspr %0,22" : "=r" (ret) :);
+    return ret;
+}
+
+static inline void
+set_dec(int val)
+{
+    asm volatile("mtspr 22,%0" : : "r" (val));
+}
+
+/* The decrementer counts down by 128 every 128ns on a 601. */
+#define DECREMENTER_COUNT_601  (1000000000 / HZ)
+#define COUNT_PERIOD_NUM_601   1
+#define COUNT_PERIOD_DEN_601   1000
+
+unsigned decrementer_count;    /* count value for 1e6/HZ microseconds */
+unsigned count_period_num;     /* 1 decrementer count equals */
+unsigned count_period_den;     /* count_period_num / count_period_den us */
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       *tv = xtime;
+       tv->tv_usec += (decrementer_count - get_dec())
+           * count_period_num / count_period_den;
+       if (tv->tv_usec >= 1000000) {
+               tv->tv_usec -= 1000000;
+               tv->tv_sec++;
+       }
+       restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+       int frac_tick;
+
+       frac_tick = tv->tv_usec % (1000000 / HZ);
+       save_flags(flags);
+       cli();
+       xtime.tv_sec = tv->tv_sec;
+       xtime.tv_usec = tv->tv_usec - frac_tick;
+       set_dec(frac_tick * count_period_den / count_period_num);
+       restore_flags(flags);
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * We set it up to overflow again in 1/HZ seconds.
+ */
+void timer_interrupt(struct pt_regs * regs)
+{
+       int dval, d;
+
+       while ((dval = get_dec()) < 0) {
+               /*
+                * Wait for the decrementer to change, then jump
+                * in and add decrementer_count to its value
+                * (quickly, before it changes again!)
+                */
+               while ((d = get_dec()) == dval)
+                       ;
+               set_dec(d + decrementer_count);
+               do_timer(regs);
+       }
+
+}
+
+void
+time_init(void)
+{
+       struct device_node *cpu;
+       int freq, *fp, divisor;
+
+       if ((_get_PVR() >> 16) == 1) {
+               /* 601 processor: dec counts down by 128 every 128ns */
+               decrementer_count = DECREMENTER_COUNT_601;
+               count_period_num = COUNT_PERIOD_NUM_601;
+               count_period_den = COUNT_PERIOD_DEN_601;
+       } else {
+               /*
+                * The cpu node should have a timebase-frequency property
+                * to tell us the rate at which the decrementer counts.
+                */
+               cpu = find_type_devices("cpu");
+               if (cpu == 0)
+                       panic("can't find cpu node in time_init");
+               fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+               if (fp == 0)
+                       panic("can't get cpu timebase frequency");
+               freq = *fp * 60;        /* try to make freq/1e6 an integer */
+               divisor = 60;
+               printk("time_init: decrementer frequency = %d/%d\n",
+                      freq, divisor);
+               decrementer_count = freq / HZ / divisor;
+               count_period_num = divisor;
+               count_period_den = freq / 1000000;
+       }
+       set_dec(decrementer_count);
+}
+
+/*
+ * We can't do this in time_init, because via_cuda_init hasn't
+ * been called at that stage.
+ */
+void
+read_rtc_time(void)
+{
+       xtime.tv_sec = get_rtc_time();
+       xtime.tv_usec = 0;
+}
+
+static unsigned long
+get_rtc_time()
+{
+       struct cuda_request req;
+
+       /* Get the time from the RTC */
+       cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
+       while (!req.got_reply)
+               cuda_poll();
+       if (req.reply_len != 7)
+               panic("get_rtc_time: didn't expect %d byte reply",
+                     req.reply_len);
+       return (req.reply[3] << 24) + (req.reply[4] << 16)
+               + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+}
index e886705e10f3f652b1d545cbe22cd6d535363e88..cc8626a3a237f623efa8a931113211bf9c64b1bd 100644 (file)
 /*
  * I/O 'port' access routines
  */
+#include <asm/byteorder.h>
+#include <asm/io.h>
 
-/* This is really only correct for the MVME16xx (PreP)? */
+#define inb_asm(port) {( \
+  unsigned char ret; \
+  asm ( "lbz %0,0(%1)\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" : "=r" (ret) : "r" (port+_IO_BASE)); \
+  return ret; \
+})
 
-#define _IO_BASE ((unsigned long)0x80000000)
-
-unsigned char
+inline unsigned char
 inb(int port)
 {
-       return (*((unsigned  char *)(_IO_BASE+port)));
+  unsigned char ret;
+  asm("/*inb*/\n");
+  asm ( "lbz %0,0(%1)" : "=r" (ret) : "r" (port+_IO_BASE));
+  return ret;
 }
 
-unsigned short
+inline unsigned short
 inw(int port)
 {
-       return (_LE_to_BE_short(*((unsigned short *)(_IO_BASE+port))));
+  unsigned short ret;
+  asm("/*inw*/\n");
+  asm ( "lhbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
+  return ret;
 }
 
-unsigned long
+inline unsigned long
 inl(int port)
 {
-       return (_LE_to_BE_long(*((unsigned  long *)(_IO_BASE+port))));
+  unsigned long ret;
+  asm("/*inl*/\n");
+  asm ( "lwbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
+  return ret;
 }
 
-void insb(int port, char *ptr, int len)
+inline unsigned char
+outb(unsigned char val,int port)
 {
-       unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
-       while (len-- > 0)
-       {
-               *ptr++ = *io_ptr;
-       }
+  asm("/*outb*/\n");
+  asm ( "stb %0,0(%1)" :: "r" (val), "r" (port+_IO_BASE));
+  return (val);
 }
 
-#if 0
-void insw(int port, short *ptr, int len)
-{
-       unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-       while (len-- > 0)
-       {
-               *ptr++ = _LE_to_BE_short(*io_ptr);
-       }
-}
-#else
-void insw(int port, short *ptr, int len)
+inline unsigned short
+outw(unsigned short val,int port)
 {
-       unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-       _insw(io_ptr, ptr, len);
+  asm("/*outw*/\n");
+  asm ( "sthbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
+  return (val);
 }
-#endif
 
-void insw_unswapped(int port, short *ptr, int len)
+inline unsigned long
+outl(unsigned long val,int port)
 {
-       unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-       while (len-- > 0)
-       {
-               *ptr++ = *io_ptr;
-       }
+  asm("/*outl*/\n");
+  asm ( "stwbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
+  return (val);
 }
 
-void insl(int port, long *ptr, int len)
+void insb(int port, char *ptr, int len)
 {
-       unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
-       while (len-- > 0)
-       {
-               *ptr++ = _LE_to_BE_long(*io_ptr);
-       }
+  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len);
 }
 
-unsigned char  inb_p(int port) {return (inb(port)); }
-unsigned short inw_p(int port) {return (inw(port)); }
-unsigned long  inl_p(int port) {return (inl(port)); }
-
-unsigned char
-outb(unsigned char val,int port)
+void insw(int port, short *ptr, int len)
 {
-       *((unsigned  char *)(_IO_BASE+port)) = (val);
-       return (val);
+  asm ("mtctr  %2 \n\t"
+       "subi   %1,%1,2 \n\t"
+       "00:\n\t"
+       "lhbrx  %2,0,%0 \n\t"
+       "sthu   %2,2(%1) \n\t"
+       "bdnz 00b \n\t"
+       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
 }
 
-unsigned short
-outw(unsigned short val,int port)
+void insw_unswapped(int port, short *ptr, int len)
 {
-       *((unsigned  short *)(_IO_BASE+port)) = _LE_to_BE_short(val);
-       return (val);
+  memcpy( (void *)ptr, (void *)(port+_IO_BASE), (len*sizeof(short)) );
 }
 
-unsigned long
-outl(unsigned long val,int port)
+void insl(int port, long *ptr, int len)
 {
-       *((unsigned  long *)(_IO_BASE+port)) = _LE_to_BE_long(val);
-       return (val);
+  asm ("mtctr  %2 \n\t"
+       "subi   %1,%1,4 \n\t"
+       "00:\n\t"
+       "lhbrx  %2,0,%0 \n\t"
+       "sthu   %2,4(%1) \n\t"
+       "bdnz 00b \n\t"
+       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
 }
 
 void outsb(int port, char *ptr, int len)
 {
-       unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
-       while (len-- > 0)
-       {
-               *io_ptr = *ptr++;
-       }
+  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len );
 }
 
-#if 0
 void outsw(int port, short *ptr, int len)
 {
-       unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-       while (len-- > 0)
-       {
-               *io_ptr = _LE_to_BE_short(*ptr++);
-       }
+  asm ("mtctr  %2\n\t"
+       "subi   %1,%1,2\n\t"
+       "00:lhzu        %2,2(%1)\n\t"
+       "sthbrx %2,0,%0\n\t"
+       "bdnz   00b\n\t"
+       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
 }
-#else
-void outsw(int port, short *ptr, int len)
-{
-       unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-       _outsw(io_ptr, ptr, len);
-}
-#endif
 
 void outsw_unswapped(int port, short *ptr, int len)
 {
-       unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-       while (len-- > 0)
-       {
-               *io_ptr = *ptr++;
-       }
+  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len*sizeof(short) );  
 }
 
 void outsl(int port, long *ptr, int len)
 {
-       unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
-       while (len-- > 0)
-       {
-               *io_ptr = _LE_to_BE_long(*ptr++);
-       }
+  asm ("mtctr  %2\n\t"
+       "subi   %1,%1,4\n\t"
+       "00:lwzu        %2,4(%1)\n\t"
+       "sthbrx %2,0,%0\n\t"
+       "bdnz   00b\n\t"
+       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
 }
 
-unsigned char  outb_p(unsigned char val,int port) { return (outb(val,port)); }
-unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
-unsigned long  outl_p(unsigned long val,int port) { return (outl(val,port)); }
-
+void insl_unswapped(int port, long *ptr, int len)
+{
+        unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+        /* Ensure I/O operations complete */
+        __asm__ volatile("eieio");
+        while (len-- > 0)
+        {
+                *ptr++ = (*io_ptr);
+        }
+}
 
-/* makes writing to the ibm acorn power management stuff easier -- Cort */
-/* args in forn of PA.B as in tech spec for ibm carolina */
-void ibm_write(unsigned char val,unsigned int port)
+void outsl_unswapped(int port, long *ptr, int len)
 {
+        unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+        /* Ensure I/O operations complete */
+        __asm__ volatile("eieio");
+        while (len-- > 0)
+        {
+                *io_ptr = (*ptr++);
+        }
 }
index 5d357be226bd1be3a11bee69feef5131b5fc4e21..e31dea266bd4bdf7641a39dc06e287a224033113 100644 (file)
@@ -2,19 +2,10 @@
  * This file contains all the macros and symbols which define
  * a PowerPC assembly language environment.
  */
-
+#include <linux/config.h>      
 #define _TEXT()\
        .text
 
-#if 0 /* Old way */    
-#define _EXTERN(n) .##n        
-
-#define _GLOBAL(n)\
-       .globl n;\
-n:     .long   _EXTERN(n);\
-       .globl _EXTERN(n);\
-_EXTERN(n):
-#else
 #define _EXTERN(n) n   
 
 #define SYMBOL_NAME(x) x
@@ -22,7 +13,6 @@ _EXTERN(n):
 #define _GLOBAL(n)\
        .globl n;\
 n:
-#endif
 
 #ifndef FALSE
 #define FALSE  0
@@ -136,9 +126,13 @@ n:
 #define SDR1   25      /* MMU hash base register */
 #define DAR    19      /* Data Address Register */
 #define SPR0   272     /* Supervisor Private Registers */
+#define SPRG0   272
 #define SPR1   273
+#define SPRG1   273
 #define SPR2   274
+#define SPRG2   274
 #define SPR3   275
+#define SPRG3   275
 #define DSISR  18
 #define SRR0   26      /* Saved Registers (exception) */
 #define SRR1   27
@@ -164,7 +158,36 @@ n:
 #define SR14   14
 #define SR15   15
 
+#define curptr r2
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)      stw     n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base)    SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)    SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)    SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)   SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base)      lwz     n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base)    REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)    REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)    REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)   REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base)      stfd    n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base)    SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base)    SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base)    SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base)   SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base)   SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base)      lfd     n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base)    REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base)    REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base)    REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base)   REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base)   REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+
 /* Missing instructions */
 #define bdne   bc 0,2,
 
-#include "asm/ppc_machine.h"
diff --git a/arch/ppc/kernel/ppc_defs.h b/arch/ppc/kernel/ppc_defs.h
new file mode 100644 (file)
index 0000000..2accaa4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
+#define        STATE   0
+#define        NEXT_TASK       68
+#define        COUNTER 4
+#define        BLOCKED 16
+#define        SIGNAL  12
+#define        TSS     544
+#define        KSP     0
+#define        PG_TABLES       4
+#define        LAST_SYSCALL    288
+#define        PT_REGS 280
+#define        PF_TRACESYS     32
+#define        TASK_FLAGS      20
+#define        TSS_FPR0        16
+#define        TSS_FPSCR       12
+#define        TASK_UNION_SIZE 8192
+#define        STACK_FRAME_OVERHEAD    16
+#define        INT_FRAME_SIZE  192
+#define        GPR0    16
+#define        GPR1    20
+#define        GPR2    24
+#define        GPR3    28
+#define        GPR4    32
+#define        GPR5    36
+#define        GPR6    40
+#define        GPR7    44
+#define        GPR8    48
+#define        GPR9    52
+#define        GPR10   56
+#define        GPR11   60
+#define        GPR12   64
+#define        GPR13   68
+#define        GPR14   72
+#define        GPR15   76
+#define        GPR16   80
+#define        GPR17   84
+#define        GPR18   88
+#define        GPR19   92
+#define        GPR20   96
+#define        GPR21   100
+#define        GPR22   104
+#define        GPR23   108
+#define        GPR24   112
+#define        GPR25   116
+#define        GPR26   120
+#define        GPR27   124
+#define        GPR28   128
+#define        GPR29   132
+#define        GPR30   136
+#define        GPR31   140
+#define        _NIP    144
+#define        _MSR    148
+#define        _CTR    152
+#define        _LINK   156
+#define        _CCR    160
+#define        _XER    164
+#define        _DAR    168
+#define        _DSISR  172
+#define        ORIG_GPR3       176
+#define        RESULT  180
+#define        TRAP    184
diff --git a/arch/ppc/kernel/ppc_defs.head b/arch/ppc/kernel/ppc_defs.head
new file mode 100644 (file)
index 0000000..fbe9264
--- /dev/null
@@ -0,0 +1,3 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
new file mode 100644 (file)
index 0000000..8784e95
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* for the mac fs */
+kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+unsigned char aux_device_present;
+
+#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 */
+#endif
+
+/* copy of the residual data */
+RESIDUAL res;
+/* ptr to residual data from hw, must be initialized so not in bss (gets cleared )*/
+unsigned long resptr = 0;
+int _machine;
+extern unsigned long _TotalMemory;
+
+#define COMMAND_LINE_SIZE 256
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+char saved_command_line[COMMAND_LINE_SIZE];
+#ifdef HASHSTATS
+unsigned long evicts;
+#endif
+
+struct screen_info screen_info = {
+       0, 25,                  /* orig-x, orig-y */
+       { 0, 0 },               /* unused */
+       0,                      /* orig-video-page */
+       0,                      /* orig-video-mode */
+       80,                     /* orig-video-cols */
+       0,0,0,                  /* ega_ax, ega_bx, ega_cx */
+       25,                     /* orig-video-lines */
+       1,                      /* orig-video-isVGA */
+       16                      /* orig-video-points */
+};
+
+void machine_halt(void)
+{
+       machine_restart(NULL);
+}
+
+void machine_power_off(void)
+{
+       machine_restart(NULL);
+}
+
+void machine_restart(char *cmd)
+{
+       unsigned char ctl;
+       unsigned long flags;
+       unsigned long i = 10000;
+       
+       _disable_interrupts();
+
+       /* set exception prefix high - to the prom */
+       save_flags( flags );
+       restore_flags( flags|MSR_IP );
+
+       /* make sure bit 0 (reset) is a 0 */
+       outb( inb(0x92) & ~1L , 0x92 );
+       /* signal a reset to system control port A - soft reset */
+       outb( inb(0x92) | 1 , 0x92 );
+
+       while ( i != 0 ) i++;
+       panic("restart failed\n");
+}
+
+int
+get_cpuinfo(char *buffer)
+{
+       extern char *Motherboard_map_name;
+       int i;
+       int pvr = _get_PVR();
+       int len;
+       char *model;
+       PTE *ptr;
+       unsigned long kptes = 0, uptes = 0, overflow = 0;
+       unsigned int ti;
+  
+  
+       switch (pvr>>16)
+       {
+       case 1:
+               model = "601";
+               break;
+       case 3:
+               model = "603";
+               break;
+       case 4:
+               model = "604";
+               break;
+       case 6:
+               model = "603e";
+               break;
+       case 7:
+               model = "603ev";
+               break;
+       default:
+               model = "unknown";
+               break;
+       }
+  
+#ifdef __SMP__
+#define CD(X)          (cpu_data[n].X)  
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+  
+       len = sprintf(buffer,"processor\t: %d\n"
+                     "cpu\t\t: %s\n"
+                     "revision\t: %d.%d\n"
+                     "upgrade\t\t: %s\n"
+                     "clock\t\t: %dMHz\n"
+                     "bus clock\t: %dMHz\n"
+                     "machine\t\t: %s (sn %s)\n"
+                     "pci map\t\t: %s\n",
+                     CPUN,
+                     model,
+                     MAJOR(pvr), MINOR(pvr),
+                     (inb(IBM_EQUIP_PRESENT) & 2) ? "not upgrade" : "upgrade",
+                     (res.VitalProductData.ProcessorHz > 1024) ?
+                     res.VitalProductData.ProcessorHz>>20 :
+                     res.VitalProductData.ProcessorHz,
+                     (res.VitalProductData.ProcessorBusHz > 1024) ?
+                     res.VitalProductData.ProcessorBusHz>>20 :
+                     res.VitalProductData.ProcessorBusHz,
+                     res.VitalProductData.PrintableModel,
+                     res.VitalProductData.Serial,
+                     Motherboard_map_name
+               );
+  
+       /* print info about SIMMs */
+       len += sprintf(buffer+len,"simms\t\t: ");
+       for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
+       {
+               if ( res.Memories[i].SIMMSize != 0 )
+                       len += sprintf(buffer+len,"%d:%dM ",i,
+                                      (res.Memories[i].SIMMSize > 1024) ?
+                                      res.Memories[i].SIMMSize>>20 :
+                                      res.Memories[i].SIMMSize);
+       }
+       len += sprintf(buffer+len,"\n");
+
+       /* TLB */
+       len += sprintf(buffer+len,"tlb\t\t:");
+       switch(res.VitalProductData.TLBAttrib)
+       {
+       case CombinedTLB:
+               len += sprintf(buffer+len," %d entries\n",
+                              res.VitalProductData.TLBSize);
+               break;
+       case SplitTLB:
+               len += sprintf(buffer+len," (split I/D) %d/%d entries\n",
+                              res.VitalProductData.I_TLBSize,
+                              res.VitalProductData.D_TLBSize);
+               break;
+       case NoneTLB:
+               len += sprintf(buffer+len," not present\n");
+               break;
+       }
+
+       /* L1 */
+       len += sprintf(buffer+len,"l1\t\t: ");
+       switch(res.VitalProductData.CacheAttrib)
+       {
+       case CombinedCAC:
+               len += sprintf(buffer+len,"%dkB LineSize\n",
+                              res.VitalProductData.CacheSize,
+                              res.VitalProductData.CacheLineSize);
+               break;
+       case SplitCAC:
+               len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
+                              res.VitalProductData.I_CacheSize,
+                              res.VitalProductData.D_CacheSize,
+                              res.VitalProductData.D_CacheLineSize,
+                              res.VitalProductData.D_CacheLineSize);
+               break;
+       case NoneCAC:
+               len += sprintf(buffer+len,"not present\n");
+               break;
+       }
+
+       /* L2 */
+       if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
+       {
+               int size;
+    
+               len += sprintf(buffer+len,"l2\t\t: %dkB %s\n",
+                              ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
+                              (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
+       }
+       else
+       {
+               len += sprintf(buffer+len,"l2\t\t: not present\n");
+       }
+
+
+       len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
+                      CD(loops_per_sec+2500)/500000,
+                      (CD(loops_per_sec+2500)/5000) % 100);
+  
+       /*
+        * Ooh's and aah's info about zero'd pages in idle task
+        */ 
+       {
+               extern unsigned int zerocount, zerototal, zeropage_hits;
+               len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
+                              "current: %u (%uKb) hits: %u\n",
+                              zerototal, (zerototal*PAGE_SIZE)>>10,
+                              zerocount, (zerocount*PAGE_SIZE)>>10,
+                              zeropage_hits);
+       }
+
+
+       /* ram/hash table info */
+       len += sprintf(buffer+len,"hash table\t: %dkB (%dk buckets)\n",
+                      Hash_size>>10,(Hash_size/(sizeof(PTE)*8)) >> 10);
+
+       /* if booted print info about hash table use (overflows, etc) */
+#ifdef HASHSTATS
+       for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr++)
+       {
+               if (ptr->v)
+               {
+                       /* user not allowed read or write */
+                       if (ptr->pp == PP_RWXX)
+                               kptes++;
+                       else
+                               uptes++;
+                       if (ptr->h == 1)
+                               overflow++;
+               }
+       }
+       /*len+=sprintf(buffer+len,"Hash %x Hash+Hash_size %x MemEnd %x\n",
+         Hash,Hash+Hash_size,KERNELBASE+_TotalMemory);*/
+       /*len += sprintf(buffer+len,"PTEs: (user/kernel/max) %d (%d%%)/%d "
+         "(%d%%)/%d (%d%% full)\n",
+         uptes,(uptes*100)/(Hash_size/sizeof(PTE)),
+         kptes,(kptes*100)/(Hash_size/sizeof(PTE)),
+         Hash_size/sizeof(PTE),
+         ((uptes+kptes)*100)/(Hash_size/sizeof(PTE)));
+         len += sprintf(buffer+len,"Current Ovflw PTE's: %d Total Evicts: %u\n",
+         overflow,evicts);*/
+#endif /* HASHSTATS */
+       return len;
+}
+
+__initfunc(unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end))
+{
+       return memory_start;
+}
+
+__initfunc(void
+setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+          unsigned long * memory_end_p))
+{
+       extern char cmd_line[];
+       extern char _etext[], _edata[], _end[];
+       unsigned char reg;
+       extern int panic_timeout;
+
+       /* Save unparsed command line copy for /proc/cmdline */
+       strcpy( saved_command_line, cmd_line );
+       *cmdline_p = cmd_line;
+  
+       *memory_start_p = (unsigned long) Hash+Hash_size;
+       (unsigned long *)*memory_end_p = (unsigned long *)(_TotalMemory+KERNELBASE);
+
+       /* init to some ~sane value until calibrate_delay() runs */
+       loops_per_sec = 50000000;
+       
+       /* reboot on panic */   
+       /*panic_timeout = 180;*/
+       
+       init_task.mm->start_code = PAGE_OFFSET;
+       init_task.mm->end_code = (unsigned long) _etext;
+       init_task.mm->end_data = (unsigned long) _edata;
+       init_task.mm->brk = (unsigned long) _end;       
+       
+       aux_device_present = 0xaa;
+       
+       switch ( _machine )
+       {
+       case _MACH_IBM:
+               ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+               break;
+       case _MACH_Motorola:
+               ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+               break;
+       }
+       /*ROOT_DEV = to_kdev_t(0x0811);*/ /* sdb1 */
+#if 0
+       strcpy(cmd_line+strlen(cmd_line),"console=1,9600,n8");
+#endif
+       
+#if 0  
+       if ( _machine == _MACH_Motorola )
+       {
+               /* get root via nfs from gordito -- only used for testing */
+               ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);   /* nfs */
+               /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
+               strcpy(cmd_line+strlen(cmd_line),
+                      "nfsaddrs=129.138.6.13:129.138.6.101:129.138.6.1:255.255.255.0:"
+                      "pandora nfsroot=/usr/src/root/");
+       }
+#endif
+  
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+       ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
+       rd_prompt = 1;
+       rd_doload = 1;
+       rd_image_start = 0;
+#endif
+#endif
+       
+       request_region(0x20,0x20,"pic1");
+       request_region(0xa0,0x20,"pic2");
+       request_region(0x00,0x20,"dma1");
+       request_region(0x40,0x20,"timer");
+       request_region(0x80,0x10,"dma page reg");
+       request_region(0xc0,0x20,"dma2");
+}
+
diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c
new file mode 100644 (file)
index 0000000..8d1384c
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ *  linux/arch/i386/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * Adapted for PowerPC (PreP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  copied and modified from intel version
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+static int set_rtc_mmss(unsigned long nowtime);
+unsigned long get_cmos_time(void);
+static inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
+                                  unsigned int, unsigned int, unsigned int);
+#define TIMER_IRQ 0
+
+/* Cycle counter value at the previous timer interrupt.. */
+static unsigned long long last_timer_cc = 0;
+static unsigned long long init_timer_cc = 0;
+
+#define TICK_SIZE tick
+#define FEBRUARY       2
+#define        STARTOFTIME     1970
+#define SECDAY         86400L
+#define SECYR          (SECDAY * 365)
+#define        leapyear(year)          ((year) % 4 == 0)
+#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
+#define        days_in_month(a)        (month_days[(a) - 1])
+
+static int      month_days[12] = {
+       31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static unsigned long do_slow_gettimeoffset(void)
+{
+       int count;
+       unsigned long offset = 0;
+
+       /* timer count may underflow right here */
+       outb_p(0x00, 0x43);     /* latch the count ASAP */
+       count = inb_p(0x40);    /* read the latched count */
+       count |= inb(0x40) << 8;
+       /* we know probability of underflow is always MUCH less than 1% */
+       if (count > (LATCH - LATCH/100)) {
+               /* check for pending timer interrupt */
+               outb_p(0x0a, 0x20);
+               if (inb(0x20) & 1)
+                       offset = TICK_SIZE;
+       }
+       count = ((LATCH-1) - count) * TICK_SIZE;
+       count = (count + LATCH/2) / LATCH;
+       return offset + count;
+}
+
+static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+       save_flags(flags);
+       cli();
+       *tv = xtime;
+       tv->tv_usec += do_gettimeoffset();
+       if (tv->tv_usec >= 1000000) {
+               tv->tv_usec -= 1000000;
+               tv->tv_sec++;
+       }
+       restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+       cli();
+       tv->tv_usec -= do_gettimeoffset();
+  
+       if (tv->tv_usec < 0) {
+               tv->tv_usec += 1000000;
+               tv->tv_sec--;
+       }
+  
+       xtime = *tv;
+       time_state = TIME_ERROR;
+       time_maxerror = 0x70000000;
+       time_esterror = 0x70000000;
+       sti();
+}
+
+void to_tm(int tim, struct rtc_time * tm)
+{
+       register int    i;
+       register long   hms, day;
+
+       day = tim / SECDAY;
+       hms = tim % SECDAY;
+
+       /* Hours, minutes, seconds are easy */
+       tm->tm_hour = hms / 3600;
+       tm->tm_min = (hms % 3600) / 60;
+       tm->tm_sec = (hms % 3600) % 60;
+
+       /* Number of years in days */
+       for (i = STARTOFTIME; day >= days_in_year(i); i++)
+               day -= days_in_year(i);
+       tm->tm_year = i;
+
+       /* Number of months in days left */
+       if (leapyear(tm->tm_year))
+               days_in_month(FEBRUARY) = 29;
+       for (i = 1; day >= days_in_month(i); i++)
+               day -= days_in_month(i);
+       days_in_month(FEBRUARY) = 28;
+       tm->tm_mon = i;
+
+       /* Days are what is left over (+1) from all that. */
+       tm->tm_mday = day + 1;
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+       int retval = 0;
+       int real_seconds, real_minutes, cmos_minutes;
+       unsigned char save_control, save_freq_select;
+       struct rtc_time tm;
+
+       to_tm(nowtime, &tm);
+
+       save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+       CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+       save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+        tm.tm_year -= 1900;
+       if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+               BIN_TO_BCD(tm.tm_sec);
+               BIN_TO_BCD(tm.tm_min);
+               BIN_TO_BCD(tm.tm_hour);
+               BIN_TO_BCD(tm.tm_mon);
+               BIN_TO_BCD(tm.tm_mday);
+               BIN_TO_BCD(tm.tm_year);
+       }
+       CMOS_WRITE(tm.tm_sec,RTC_SECONDS);
+       CMOS_WRITE(tm.tm_min,RTC_MINUTES);
+       CMOS_WRITE(tm.tm_hour,RTC_HOURS);
+       CMOS_WRITE(tm.tm_mon,RTC_MONTH);
+       CMOS_WRITE(tm.tm_mday,RTC_DAY_OF_MONTH);
+       CMOS_WRITE(tm.tm_year,RTC_YEAR);
+       
+       /* The following flags have to be released exactly in this order,
+        * otherwise the DS12887 (popular MC146818A clone with integrated
+        * battery and quartz) will not reset the oscillator and will not
+        * update precisely 500 ms later. You won't find this mentioned in
+        * the Dallas Semiconductor data sheets, but who believes data
+        * sheets anyway ...                           -- Markus Kuhn
+        */
+       CMOS_WRITE(save_control, RTC_CONTROL);
+       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+       if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+               time_state = TIME_OK;
+       return 0;
+}
+
+unsigned long get_cmos_time(void)
+{
+       unsigned int year, mon, day, hour, min, sec;
+       int i;
+
+       /* The Linux interpretation of the CMOS clock register contents:
+        * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+        * RTC registers show the second which has precisely just started.
+        * Let's hope other operating systems interpret the RTC the same way.
+        */
+       /* read RTC exactly on falling edge of update flag */
+       for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+               if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+                       break;
+       for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+               if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+                       break;
+       do { /* Isn't this overkill ? UIP above should guarantee consistency */
+               sec = CMOS_READ(RTC_SECONDS);
+               min = CMOS_READ(RTC_MINUTES);
+               hour = CMOS_READ(RTC_HOURS);
+               day = CMOS_READ(RTC_DAY_OF_MONTH);
+               mon = CMOS_READ(RTC_MONTH);
+               year = CMOS_READ(RTC_YEAR);
+       } while (sec != CMOS_READ(RTC_SECONDS));
+       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+         {
+           BCD_TO_BIN(sec);
+           BCD_TO_BIN(min);
+           BCD_TO_BIN(hour);
+           BCD_TO_BIN(day);
+           BCD_TO_BIN(mon);
+           BCD_TO_BIN(year);
+         }
+       if ((year += 1900) < 1970)
+               year += 100;
+       return mktime(year, mon, day, hour, min, sec);
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
+{
+       do_timer(regs);
+
+       /* update the hw clock if:
+        * the time is marked out of sync (TIME_ERROR)
+        * or ~11 minutes have expired since the last update -- Cort
+        * If we have an externally synchronized Linux clock, then update
+        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+        * called as close as possible to 500 ms before the new second starts.
+        */
+       if ( time_state == TIME_BAD ||
+            xtime.tv_sec > last_rtc_update + 660 )
+       /*if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+           xtime.tv_usec > 500000 - (tick >> 1) &&
+           xtime.tv_usec < 500000 + (tick >> 1))*/
+               if (set_rtc_mmss(xtime.tv_sec) == 0)
+                       last_rtc_update = xtime.tv_sec;
+               else
+                       last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+
+
+#ifdef CONFIG_HEARTBEAT
+       /* use hard disk LED as a heartbeat instead -- much more useful
+          for debugging -- Cort */
+       switch(kstat.interrupts[0] % 101)
+       {
+       /* act like an actual heart beat -- ie thump-thump-pause... */
+       case 0:
+       case 20:
+               outb(1,IBM_HDD_LED);
+               break;
+       case 7:
+       case 27:
+               outb(0,IBM_HDD_LED);
+               break;
+       case 100:
+               break;
+       }
+#endif
+}
+
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+                                  unsigned int day, unsigned int hour,
+                                  unsigned int min, unsigned int sec)
+{
+       if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
+               mon += 12;      /* Puts Feb last since it has leap day */
+               year -= 1;
+       }
+       return (((
+               (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+               year*365 - 719499
+               )*24 + hour /* now have hours */
+               )*60 + min /* now have minutes */
+               )*60 + sec; /* finally seconds */
+}
+
+void time_init(void)
+{
+       void (*irq_handler)(int, void *,struct pt_regs *);
+       xtime.tv_sec = get_cmos_time();
+       xtime.tv_usec = 0;
+
+       /* If we have the CPU hardware time counters, use them */
+       irq_handler = timer_interrupt;
+       if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+               panic("Could not allocate timer IRQ!");
+}
index ee21c5cbe99058e86c8339f446dafc471d841db6..f248720632cb58f1a29efa23dfd363e07266c129 100644 (file)
@@ -1,13 +1,20 @@
 /*
  *  linux/arch/ppc/kernel/process.c
  *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted for PowerPC by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu) 
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/kernel/process.c"
+ *    Copyright (C) 1995  Linus Torvalds
+ *
+ *  Modified by Cort Dougan (cort@cs.nmt.edu) and
+ *  Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
  */
 
 #include <linux/errno.h>
 #include <linux/malloc.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
+#include <linux/config.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/smp_lock.h>
 
-#include <asm/ppc_machine.h>
+int dump_fpu(void);
+void switch_to(struct task_struct *, struct task_struct *);
+void print_backtrace(unsigned long *);
+void show_regs(struct pt_regs * regs);
+void inline zero_paged(void);
+extern unsigned long _get_SP(void);
 
-/*
- * Initial task structure. Make this a per-architecture thing,
- * because different architectures tend to have different
- * alignment requirements and potentially different initial
- * setup.
- */
-static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+#undef SHOW_TASK_SWITCHES 1
+#undef CHECK_STACK 1
+#undef IDLE_ZERO 1
+
+unsigned long
+kernel_stack_top(struct task_struct *tsk)
+{
+       return ((unsigned long)tsk) + sizeof(union task_union);
+}
+
+unsigned long
+task_top(struct task_struct *tsk)
+{
+       return ((unsigned long)tsk) + sizeof(struct task_struct);
+}
+       
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 
 struct mm_struct init_mm = INIT_MM;
-struct task_struct init_task = INIT_TASK;
-
-
-int dump_fpu(void);
-void hard_reset_now(void);
-void switch_to(struct task_struct *, struct task_struct *);
-void copy_thread(int,unsigned long,unsigned long,struct task_struct *,
-                struct pt_regs *);
-void print_backtrace(unsigned long *);
+union task_union init_task_union = { INIT_TASK };
 
 int
 dump_fpu(void)
 {
-  return (1);
+       return (1);
 }
 
-
 /* check to make sure the kernel stack is healthy */
 int check_stack(struct task_struct *tsk)
 {
-  extern unsigned long init_kernel_stack[PAGE_SIZE/sizeof(long)];
-  int ret = 0;
-  int i;
-  
-  /* skip check in init_kernel_task -- swapper */
-  if ( tsk->kernel_stack_page == (unsigned long)&init_kernel_stack )
-    return;
-  /* check bounds on stack -- above/below kstack page */
-  if ( (tsk->tss.ksp-1 & KERNEL_STACK_MASK) != tsk->kernel_stack_page )
-  {
-    printk("check_stack(): not in bounds %s/%d ksp %x/%x\n",
-          tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page);
-    ret |= 1;
-  }
-
-  /* check for magic on kstack */
-  if ( *(unsigned long *)(tsk->kernel_stack_page) != STACK_MAGIC)
-  {
-    printk("check_stack(): no magic %s/%d ksp %x/%x magic %x\n",
-          tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
-          *(unsigned long *)(tsk->kernel_stack_page));
-    ret |= 2;
-  }
-
-#ifdef KERNEL_STACK_BUFFER
-  /* check extra padding page under kernel stack */
-  for ( i = PAGE_SIZE/sizeof(long) ; i >= 1; i--)
-  {
-    struct pt_regs *regs;
-    
-    if ( *((unsigned long *)(tsk->kernel_stack_page)-1) )
-    {
-      printk("check_stack(): padding touched %s/%d ksp %x/%x value %x/%d\n",
-            tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
-            *(unsigned long *)(tsk->kernel_stack_page-i),i*sizeof(long));
-      regs = (struct pt_regs *)(tsk->kernel_stack_page-(i*sizeof(long)));
-      printk("marker %x trap %x\n", regs->marker,regs->trap);
-      print_backtrace((unsigned long *)(tsk->tss.ksp));
-      
-      ret |= 4;
-      break;
-    }
-  }
+       unsigned long stack_top = kernel_stack_top(tsk);
+       unsigned long tsk_top = task_top(tsk);
+       int ret = 0;
+       unsigned long *i;
+
+#if 0  
+       /* check tss magic */
+       if ( tsk->tss.magic != TSS_MAGIC )
+       {
+               ret |= 1;
+               printk("tss.magic bad: %08x\n", tsk->tss.magic);
+       }
 #endif
-  
-#if 0
-  if (ret)
-    panic("bad stack");
+       
+       if ( !tsk )
+               printk("check_stack(): tsk bad tsk %p\n",tsk);
+       
+       /* check if stored ksp is bad */
+       if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
+       {
+               printk("stack out of bounds: %s/%d\n"
+                      " tsk_top %08x ksp %08x stack_top %08x\n",
+                      tsk->comm,tsk->pid,
+                      tsk_top, tsk->tss.ksp, stack_top);
+               ret |= 2;
+       }
+       
+       /* check if stack ptr RIGHT NOW is bad */
+       if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
+       {
+               printk("current stack ptr out of bounds: %s/%d\n"
+                      " tsk_top %08x sp %08x stack_top %08x\n",
+                      current->comm,current->pid,
+                      tsk_top, _get_SP(), stack_top);
+               ret |= 4;
+       }
+
+#if 0  
+       /* check amount of free stack */
+       for ( i = (unsigned long *)task_top(tsk) ; i < kernel_stack_top(tsk) ; i++ )
+       {
+               if ( !i )
+                       printk("check_stack(): i = %p\n", i);
+               if ( *i != 0 )
+               {
+                       /* only notify if it's less than 900 bytes */
+                       if ( (i - (unsigned long *)task_top(tsk))  < 900 )
+                               printk("%d bytes free on stack\n",
+                                      i - task_top(tsk));
+                       break;
+               }
+       }
 #endif
-  return(ret);
-}
 
+       if (ret)
+       {
+               panic("bad kernel stack");
+       }
+       return(ret);
+}
 
 void
 switch_to(struct task_struct *prev, struct task_struct *new)
 {
-       struct pt_regs *regs;
        struct thread_struct *new_tss, *old_tss;
        int s = _disable_interrupts();
-       regs = (struct pt_regs *)(new->tss.ksp);
-#if 1
+       struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
+
+#if CHECK_STACK
        check_stack(prev);
        check_stack(new);
 #endif
-       /* if a process has used fp 15 times, then turn
-          on the fpu for good otherwise turn it on with the fp
-          exception handler as needed.
-          skip this for kernel tasks.
-                   -- Cort */
-       if ( (regs->msr & MSR_FP)&&(regs->msr & MSR_PR)&&(new->tss.fp_used < 15) )
-       {
-#if 0
-         printk("turning off fpu: %s/%d fp_used %d\n",
-                new->comm,new->pid,new->tss.fp_used);
-#endif
-         regs->msr = regs->msr & ~MSR_FP;
-       }
-#if 0
-       printk("%s/%d -> %s/%d\n",prev->comm,prev->pid,new->comm,new->pid);
+        /* turn off fpu for task last to run */
+       /*prev->tss.regs->msr &= ~MSR_FP;*/
+       
+#ifdef SHOW_TASK_SWITCHES
+       printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
+              prev->comm,prev->pid,prev->tss.regs->nip,
+              new->comm,new->pid,new->tss.regs->nip,new->mm->context);
 #endif
        new_tss = &new->tss;
        old_tss = &current->tss;
-       current_set[0] = new;
-       _switch(old_tss, new_tss);
+       _switch(old_tss, new_tss, new->mm->context);
+        /* turn off fpu for task last to run */        
        _enable_interrupts(s);
 }
+       
+#include <linux/mc146818rtc.h>
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
+{
+#if 1
+       struct task_struct *p;
+       printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
+       printk("last %x\n", last_task_used_math);
+       printk("cur %x regs %x/%x tss %x/%x\n",
+              current, current->tss.regs,regs,&current->tss,current->tss);
+       for_each_task(p)
+       {
+               if ((long)p < KERNELBASE)
+               {
+                       printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
+                       print_mm_info();
+                       __cli();
+                       while(1);
+               }
+       }
+       return regs->gpr[3];
+#endif
+#if 0
+       /* set the time in the cmos clock */
+       unsigned long hwtime, nowtime;
+       struct rtc_time tm;
+       
+       hwtime = get_cmos_time();
+       to_tm(hwtime, &tm);
+       printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n", 
+              tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
+              tm.tm_mday, tm.tm_year);
+       return;
+#endif
+}
 
-asmlinkage int sys_debug(unsigned long r3)
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0;   /* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0;   /* pointer into the currently being zero'd page */
+unsigned long zerocount = 0;   /* # currently pre-zero'd pages */
+unsigned long zerototal = 0;   /* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0;     /* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
 {
-       lock_kernel();
-       if (!strcmp(current->comm,"crashme"))
-               printk("sys_debug(): r3 (syscall) %d\n", r3);
-       unlock_kernel();
+       unsigned long page;
+       unsigned long s;
+
+       if ( zero_list )
+       {
+               /* atomically remove this page from the list */
+               asm (   "101:lwarx  %1,0,%2\n"  /* reserve zero_list */
+                       "    lwz    %0,0(%1)\n" /* get next -- new zero_list */
+                       "    stwcx. %0,0,%2\n"  /* update zero_list */
+                       "    bne-   101b\n"     /* if lost reservation try again */
+                       : "=&r" (zero_list), "=&r" (page)
+                       : "r" (&zero_list)
+                       : "cc" );
+               /* we can update zerocount after the fact since it is not
+                * used for anything but control of a loop which doesn't
+                * matter since it won't effect anything if it zero's one
+                * less page -- Cort
+                */
+               atomic_inc((atomic_t *)&zeropage_hits);
+               atomic_dec((atomic_t *)&zerocount);
+               /* zero out the pointer to next in the page */
+               *(unsigned long *)page = 0;
+               return page;
+       }
        return 0;
 }
 
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+void inline zero_paged(void)
+{
+       extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+       unsigned long tmp;
+       pte_t ptep;
+       pgd_t *dir;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       sprintf(current->comm, "zero_paged");
+       printk("Started zero_paged\n");
+       /* want priority over idle task and powerd */
+       current->priority = -98;
+       current->counter = -98;
+       __sti();
+       
+       while ( zerocount < 128 )
+       {
+               /*
+                * Mark a page as reserved so we can mess with it
+                * If we're interrupted we keep this page and our place in it
+                * since we validly hold it and it's reserved for us.
+                */
+               pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+               if ( !pageptr )
+               {
+                       printk("!pageptr in zero_paged\n");
+                       goto retry;
+               }
+               
+               if ( need_resched )
+                       schedule();
+               
+               /*
+                * Make the page no cache so we don't blow our cache with 0's
+                */
+               dir = pgd_offset( init_task.mm, pageptr );
+               if (dir)
+               {
+                       pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+                       if (pmd && pmd_present(*pmd))
+                       {
+                               pte = pte_offset(pmd, pageptr & PAGE_MASK);
+                               if (pte && pte_present(*pte))
+                               {                       
+                                       pte_uncache(*pte);
+                                       flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+                               }
+                       }
+               }
+       
+               /*
+                * Important here to not take time away from real processes.
+                */
+               for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+               {
+                       if ( need_resched )
+                               schedule();
+                       *(unsigned long *)(bytecount + pageptr) = 0;
+               }
+               
+               /*
+                * If we finished zero-ing out a page add this page to
+                * the zero_list atomically -- we can't use
+                * down/up since we can't sleep in idle.
+                * Disabling interrupts is also a bad idea since we would
+                * steal time away from real processes.
+                * We can also have several zero_paged's running
+                * on different processors so we can't interfere with them.
+                * So we update the list atomically without locking it.
+                * -- Cort
+                */
+               /* turn cache on for this page */
+               pte_cache(*pte);
+               flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+               
+               /* atomically add this page to the list */
+               asm (   "101:lwarx  %0,0,%1\n"  /* reserve zero_list */
+                       "    stw    %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+                       "    sync\n"            /* let store settle */
+#endif                 
+                       "    mr     %0,%2\n"    /* update zero_list in reg */
+                       "    stwcx. %2,0,%1\n"  /* update zero_list in mem */
+                       "    bne-   101b\n"     /* if lost reservation try again */
+                       : "=&r" (zero_list)
+                       : "r" (&zero_list), "r" (pageptr)
+                       : "cc" );
+               /*
+                * This variable is used in the above loop and nowhere
+                * else so the worst that could happen is we would
+                * zero out one more or one less page than we want
+                * per processor on the machine.  This is because
+                * we could add our page to the list but not have
+                * zerocount updated yet when another processor
+                * reads it.  -- Cort
+                */
+               atomic_inc((atomic_t *)&zerocount);
+               atomic_inc((atomic_t *)&zerototal);
+retry: 
+               schedule();
+       }
+}
+
+void powerd(void)
+{
+       unsigned long msr, hid0;
+
+       sprintf(current->comm, "powerd");
+       __sti();
+       while (1)
+       {
+               /* want priority over idle task 'swapper' -- Cort */
+               current->priority = -99;
+               current->counter = -99;
+               asm volatile(
+                       /* clear powersaving modes and set nap mode */
+                       "mfspr %3,1008 \n\t"
+                       "andc  %3,%3,%4 \n\t"
+                       "or    %3,%3,%5 \n\t"
+                       "mtspr 1008,%3 \n\t"
+                       /* enter the mode */
+                       "mfmsr %0 \n\t"
+                       "oris  %0,%0,%2 \n\t"
+                       "sync \n\t"
+                       "mtmsr %0 \n\t"
+                       "isync \n\t"
+                       : "=&r" (msr)
+                       : "0" (msr), "i" (MSR_POW>>16),
+                       "r" (hid0),
+                       "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+                       "r" (HID0_NAP));
+               if ( need_resched )
+                       schedule();
+               /*
+                * The ibm carolina spec says that the eagle memory
+                * controller will detect the need for a snoop
+                * and wake up the processor so we don't need to
+                * check for cache operations that need to be
+                * snooped.  The ppc book says the run signal
+                * must be asserted while napping for this though.
+                * -- Cort
+                */
+       }
+}
+       
 asmlinkage int sys_idle(void)
 {
        int ret = -EPERM;
-
-       lock_kernel();
        if (current->pid != 0)
                goto out;
 
-       /* endless idle loop with no priority at all */
+#ifdef IDLE_ZERO
+       /*
+        * want one per cpu since it would be nice to have all
+        * processors who aren't doing anything
+        * zero-ing pages since this daemon is lock-free
+        * -- Cort
+        */
+       kernel_thread(zero_paged, NULL, 0);
+#endif /* IDLE_ZERO */
+
+#ifdef CONFIG_POWERSAVING
+       /* no powersaving modes on 601 - one per processor */
+       if(  (_get_PVR()>>16) != 1 )
+               kernel_thread(powerd, NULL, 0);
+#endif /* CONFIG_POWERSAVING */
+       
+       /* endless loop with no priority at all */
+       current->priority = -100;
        current->counter = -100;
-       for (;;) {
+       for (;;) 
+       {
                schedule();
        }
        ret = 0;
 out:
-       unlock_kernel();
        return ret;
 }
 
 void show_regs(struct pt_regs * regs)
 {
+       int i;
+
+       printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+              regs->nip, regs->xer, regs->link, regs,regs->trap);
+       printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+              regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+              regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+              regs->msr&MSR_IR ? 1 : 0,
+              regs->msr&MSR_DR ? 1 : 0);
+       printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+              current, current->pid, current->comm, current->mm->pgd);
+       printk("Last syscall: %d ", current->tss.last_syscall);
+       printk("\nlast math %08X\n", last_task_used_math);
+       for (i = 0;  i < 32;  i++)
+       {
+               long r;
+               if ((i % 8) == 0)
+               {
+                       printk("GPR%02d: ", i);
+               }
+
+               if ( get_user(r, &(regs->gpr[i])) )
+                   goto out;
+               printk("%08X ", r);
+               if ((i % 8) == 7)
+               {
+                       printk("\n");
+               }
+       }
+out:
 }
 
 void exit_thread(void)
 {
+       if (last_task_used_math == current)
+               last_task_used_math = NULL;
 }
 
 void flush_thread(void)
 {
+       if (last_task_used_math == current)
+               last_task_used_math = NULL;
 }
 
 void
@@ -197,50 +480,25 @@ release_thread(struct task_struct *t)
 }
 
 /*
- * Copy a thread..
- */
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
-       struct task_struct * p, struct pt_regs * regs)
+  * Copy a thread..
+  */
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+           struct task_struct * p, struct pt_regs * regs)
 {
        int i;
-       SEGREG *segs;
        struct pt_regs * childregs;
-       
-       /* Construct segment registers */
-       segs = (SEGREG *)(p->tss.segs);
-       for (i = 0;  i < 8;  i++)
-       {
-               segs[i].ks = 0;
-               segs[i].kp = 1;
-#if 0
-               segs[i].vsid = i | (nr << 4);
-#else
-               segs[i].vsid = i | ((nr * 10000) << 4);         
-#endif
-       }
-       if ((p->mm->context == 0) || (p->mm->count == 1))
-       {
-#if 0
-         p->mm->context = ((nr)<<4);
-#else    
-         p->mm->context = ((nr*10000)<<4);       
-#endif
-       }
-       
-       /* Last 8 are shared with kernel & everybody else... */
-       for (i = 8;  i < 16;  i++)
-       {
-               segs[i].ks = 0;
-               segs[i].kp = 1;
-               segs[i].vsid = i;
-       }
-       
        /* Copy registers */
-       childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 2;
+       childregs = ((struct pt_regs *)
+                    ((unsigned long)p + sizeof(union task_union)
+                     - STACK_FRAME_OVERHEAD)) - 2;
+       *childregs = *regs;
 
-       *childregs = *regs;     /* STRUCT COPY */
+       if ((childregs->msr & MSR_PR) == 0)
+               childregs->gpr[2] = (unsigned long) p;  /* `current' in new task */
        childregs->gpr[3] = 0;  /* Result from fork() */
-       p->tss.ksp = (unsigned long)(childregs);
+       p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
+       p->tss.regs = (struct pt_regs *)(childregs);
        if (usp >= (unsigned long)regs)
        { /* Stack is in kernel space - must adjust */
                childregs->gpr[1] = (long)(childregs+1);
@@ -248,23 +506,29 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        { /* Provided stack is in user space */
                childregs->gpr[1] = usp;
        }
-       p->tss.fp_used = 0;
 
-       return 0;
-}
+       p->tss.last_syscall = -1;
 
-/*
- * fill in the user structure for a core dump..
- */
-void dump_thread(struct pt_regs * regs, struct user * dump)
-{
+       /*
+        * copy fpu info - assume lazy fpu switch now always
+        * this should really be conditional on whether or
+        * not the process has used the fpu
+        *  -- Cort
+        */
+       if ( last_task_used_math == current )
+               giveup_fpu();
+       
+       memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
+       p->tss.fpscr = current->tss.fpscr;
+       childregs->msr &= ~MSR_FP;
+       
+       return 0;
 }
 
-
-asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+                       struct pt_regs *regs)
 {
        int ret;
-
        lock_kernel();
        ret = do_fork(SIGCHLD, regs->gpr[1], regs);
        unlock_kernel();
@@ -272,46 +536,21 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct p
 }
 
 asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
-       unsigned long a3, unsigned long a4, unsigned long a5,
-       struct pt_regs *regs)
+                         unsigned long a3, unsigned long a4, unsigned long a5,
+                         struct pt_regs *regs)
 {
        int error;
        char * filename;
-
-       lock_kernel();
-       /* getname does it's own verification of the address
-          when it calls get_max_filename() but
-          it will assume it's valid if get_fs() == KERNEL_DS
-          which is always true on the ppc so we check
-          it here
-          
-          this doesn't completely check any of these data structures,
-          it just makes sure that the 1st long is in a good area
-          and from there we assume that it's safe then
-          -- Cort
-          */
-       /* works now since get_fs/set_fs work properly */
-#if 0
-       if ( verify_area(VERIFY_READ,(void *)a0,1)
-            && verify_area(VERIFY_READ,(void *)a1,1)
-            && verify_area(VERIFY_READ,(void *)a2,1)
-            )
-       {
-         return -EFAULT;
-       }
-#endif
-       error = getname((char *) a0, &filename);
-       if (error)
+       filename = (int) getname((char *) a0);
+       error = PTR_ERR(filename);
+       if(IS_ERR(filename))
                goto out;
-       flush_instruction_cache();
+       if ( last_task_used_math == current )
+               last_task_used_math = NULL;
        error = do_execve(filename, (char **) a1, (char **) a2, regs);
-#if 0
-if (error)
-{      
-printk("EXECVE - file = '%s', error = %d\n", filename, error);
-}
-#endif
+
        putname(filename);
+
 out:
        unlock_kernel();
        return error;
@@ -321,7 +560,7 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct
 {
        unsigned long clone_flags = p1;
        int res;
-
+       
        lock_kernel();
        res = do_fork(clone_flags, regs->gpr[1], regs);
        unlock_kernel();
@@ -331,13 +570,17 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct
 void
 print_backtrace(unsigned long *sp)
 {
-#if 0
        int cnt = 0;
-       printk("... Call backtrace:\n");
-       while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
+       int i;
+       printk("Call backtrace: ");
+       while ( !get_user(i, sp) && i)
        {
-               printk("%08X ", sp[1]);
-               sp = (unsigned long *)*sp;
+               if ( get_user( i, &sp[1] ) )
+                       return;
+               printk("%08X ", i);
+               if ( get_user( (ulong)sp, sp) )
+                   return;
+               if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
                if (++cnt == 8)
                {
                        printk("\n");
@@ -345,43 +588,66 @@ print_backtrace(unsigned long *sp)
                if (cnt > 32) break;
        }
        printk("\n");
-#endif
-}
-
-void
-print_user_backtrace(unsigned long *sp)
-{
-#if 0
-       int cnt = 0;
-       printk("... [User] Call backtrace:\n");
-       while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
-       {
-               printk("%08X ", sp[1]);
-               sp = (unsigned long *)*sp;
-               if (++cnt == 8)
-               {
-                       printk("\n");
-               }
-               if (cnt > 16) break;
-       }
-       printk("\n");
-#endif
 }
 
-void
-print_kernel_backtrace(void)
-{
-#if 0
-       unsigned long *_get_SP(void);
-       print_backtrace(_get_SP());
-#endif
-}
 inline void start_thread(struct pt_regs * regs,
                          unsigned long eip, unsigned long esp)
 {
+       set_fs(USER_DS);
        regs->nip = eip;
        regs->gpr[1] = esp;
        regs->msr = MSR_USER;
-       set_fs(USER_DS);
 }
 
+/*
+ * Low level print for debugging - Cort
+ */
+int ll_printk(const char *fmt, ...)
+{
+        va_list args;
+       char buf[256];
+        int i;
+
+        va_start(args, fmt);
+        i=sprintf(buf,fmt,args);
+       ll_puts(buf);
+        va_end(args);
+        return i;
+}
+
+char *vidmem = (char *)0xC00B8000;
+int lines = 24, cols = 80;
+int orig_x = 0, orig_y = 0;
+
+void ll_puts(const char *s)
+{
+       int x,y;
+       char c;
+
+       x = orig_x;
+       y = orig_y;
+
+       while ( ( c = *s++ ) != '\0' ) {
+               if ( c == '\n' ) {
+                       x = 0;
+                       if ( ++y >= lines ) {
+                               /*scroll();*/
+                               /*y--;*/
+                               y = 0;
+                       }
+               } else {
+                       vidmem [ ( x + cols * y ) * 2 ] = c; 
+                       if ( ++x >= cols ) {
+                               x = 0;
+                               if ( ++y >= lines ) {
+                                       /*scroll();*/
+                                       /*y--;*/
+                                       y = 0;
+                               }
+                       }
+               }
+       }
+
+       orig_x = x;
+       orig_y = y;
+}
index dc8a95302985ac88df501e7e4ccef261dc5ad1d9..a5ec62d204e7b51e32ea1fc62c7d65e35c301abb 100644 (file)
@@ -1,12 +1,14 @@
 /*
  *  linux/arch/ppc/kernel/ptrace.c
  *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/m68k/kernel/ptrace.c"
  *  Copyright (C) 1994 by Hamish Macdonald
  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
  *
- * Adapted from 'linux/arch/m68k/kernel/ptrace.c'
- * PowerPC version by Gary Thomas (gdt@linuxppc.org)
  * Modified by Cort Dougan (cort@cs.nmt.edu) 
  *
  * This file is subject to the terms and conditions of the GNU General
  * in exit.c or in signal.c.
  */
 
-/* Find the stack offset for a register, relative to tss.ksp. */
-#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
-/* Mapping from PT_xxx to the stack offset at which the register is
-   saved.  Notice that usp has no stack-slot and needs to be treated
-   specially (see get_reg/put_reg below). */
-static int regoff[] = {
-};
-
 /*
  * Get contents of register REGNO in task TASK.
  */
 static inline long get_reg(struct task_struct *task, int regno)
 {
-       struct pt_regs *regs = task->tss.regs;
-       if (regno <= PT_R31)
-       {
-               return (regs->gpr[regno]);
-       } else
-       if (regno == PT_NIP)
-       {
-               return (regs->nip);
-       } else
-       if (regno == PT_MSR)
-       {
-               return (regs->msr);
-       } else
-       if (regno == PT_ORIG_R3)
-       {
-               return (regs->orig_gpr3);
-       } else
-       if (regno == PT_CTR)
-       {
-               return (regs->ctr);
-       } else
-       if (regno == PT_LNK)
-       {
-               return (regs->link);
-       } else
-       if (regno == PT_XER)
-       {
-               return (regs->xer);
-       } else
-       if (regno == PT_CCR)
-       {
-               return (regs->ccr);
-       }
+       if (regno <= PT_CCR)
+               return ((unsigned long *)task->tss.regs)[regno];
        return (0);
 }
 
@@ -89,52 +52,21 @@ static inline long get_reg(struct task_struct *task, int regno)
 static inline int put_reg(struct task_struct *task, int regno,
                          unsigned long data)
 {
-       struct pt_regs *regs = task->tss.regs;
-       if (regno <= PT_R31)
-       {
-               regs->gpr[regno] = data;
-       } else
-       if (regno == PT_NIP)
-       {
-               regs->nip = data;
-       } else
-       if (regno == PT_MSR)
-       {
-               regs->msr = data;
-       } else
-       if (regno == PT_CTR)
-       {
-               regs->ctr = data;
-       } else
-       if (regno == PT_LNK)
-       {
-               regs->link = data;
-       } else
-       if (regno == PT_XER)
-       {
-               regs->xer = data;
-       } else
-       if (regno == PT_CCR)
-       {
-               regs->ccr = data;
-       } else
-       { /* Invalid register */
-               return (-1);
+       if (regno <= PT_CCR) {
+               ((unsigned long *)task->tss.regs)[regno] = data;
+               return 0;
        }
-       return (0);
+       return -1;
 }
 
-static inline
+static inline void
 set_single_step(struct task_struct *task)
 {
        struct pt_regs *regs = task->tss.regs;
-printk("Set single step - Task: %x, Regs: %x", task, regs);
-printk(", MSR: %x/", regs->msr);       
        regs->msr |= MSR_SE;
-printk("%x\n", regs->msr);     
 }
 
-static inline
+static inline void
 clear_single_step(struct task_struct *task)
 {
        struct pt_regs *regs = task->tss.regs;
@@ -159,33 +91,32 @@ static unsigned long get_long(struct task_struct * tsk,
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
        if (pgd_none(*pgdir)) {
-               do_no_page(tsk, vma, addr, 0);
+               handle_mm_fault(tsk, vma, addr, 0);
                goto repeat;
        }
        if (pgd_bad(*pgdir)) {
-               printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+               printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir));
                pgd_clear(pgdir);
                return 0;
        }
        pgmiddle = pmd_offset(pgdir,addr);
        if (pmd_none(*pgmiddle)) {
-               do_no_page(tsk, vma, addr, 0);
+               handle_mm_fault(tsk, vma, addr, 0);
                goto repeat;
        }
        if (pmd_bad(*pgmiddle)) {
-               printk("ptrace: bad page directory %08lx\n",
-                      pmd_val(*pgmiddle));
+               printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle));
                pmd_clear(pgmiddle);
                return 0;
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               do_no_page(tsk, vma, addr, 0);
+               handle_mm_fault(tsk, vma, addr, 0);
                goto repeat;
        }
        page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
-       if (page >= high_memory)
+       if (MAP_NR(page) >= max_mapnr)
                return 0;
        page += addr & ~PAGE_MASK;
        return *(unsigned long *) page;
@@ -200,8 +131,8 @@ repeat:
  * Now keeps R/W state of page so that a text page stays readonly
  * even if a debugger scribbles breakpoints into it.  -M.U-
  */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
-       unsigned long data)
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+                    unsigned long addr, unsigned long data)
 {
        pgd_t *pgdir;
        pmd_t *pgmiddle;
@@ -211,42 +142,40 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
        if (!pgd_present(*pgdir)) {
-               do_no_page(tsk, vma, addr, 1);
+               handle_mm_fault(tsk, vma, addr, 1);
                goto repeat;
        }
        if (pgd_bad(*pgdir)) {
-               printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+               printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir));
                pgd_clear(pgdir);
                return;
        }
        pgmiddle = pmd_offset(pgdir,addr);
        if (pmd_none(*pgmiddle)) {
-               do_no_page(tsk, vma, addr, 1);
+               handle_mm_fault(tsk, vma, addr, 1);
                goto repeat;
        }
        if (pmd_bad(*pgmiddle)) {
-               printk("ptrace: bad page directory %08lx\n",
-                      pmd_val(*pgmiddle));
+               printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle));
                pmd_clear(pgmiddle);
                return;
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               do_no_page(tsk, vma, addr, 1);
+               handle_mm_fault(tsk, vma, addr, 1);
                goto repeat;
        }
        page = pte_page(*pgtable);
        if (!pte_write(*pgtable)) {
-               do_wp_page(tsk, vma, addr, 2);
+               handle_mm_fault(tsk, vma, addr, 1);
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
-       if (page < high_memory) {
+       if (MAP_NR(page) < max_mapnr)
                *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-       }
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
-       *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+       set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
        flush_tlb_all();
 }
 
@@ -366,7 +295,6 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
-       struct user * dummy = NULL;
        int ret = -EPERM;
 
        lock_kernel();
@@ -436,8 +364,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                case PTRACE_PEEKUSR: {
                        unsigned long tmp;
                        
-                       if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-                               return -EIO;
+                       if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+                               ret = -EIO;
+                               goto out;
+                       }
                        
                        ret = verify_area(VERIFY_WRITE, (void *) data,
                                          sizeof(long));
@@ -445,15 +375,19 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                goto out;
                        tmp = 0;  /* Default return condition */
                        addr = addr >> 2; /* temporary hack. */
-                       if (addr < PT_FPR0)
+                       if (addr < PT_FPR0) {
                                tmp = get_reg(child, addr);
-#if 0                  
-                       else if (addr >= PT_FPR0 && addr < PT_FPR31)
-                               tmp = child->tss.fpr[addr - PT_FPR0];
-#endif                         
+                       }
+#if 1
+                       else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+                               if (last_task_used_math == child)
+                                       giveup_fpu();
+                               tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
+                       }
+#endif
                        else
                                ret = -EIO;
-                       if(!ret)
+                       if (!ret)
                                put_user(tmp,(unsigned long *) data);
                        goto out;
                }
@@ -486,13 +420,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                ret = 0;
                                goto out;
                        }
-#if 0                  
-                       if (addr >= 21 && addr < 48) {
-                               child->tss.fp[addr - 21] = data;
+                       if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+                               if (last_task_used_math == child)
+                                       giveup_fpu();
+                               ((long *)child->tss.fpr)[addr - PT_FPR0] = data;
                                ret = 0;
                                goto out;
                        }
-#endif                 
                        goto out;
 
                case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
deleted file mode 100644 (file)
index 25f03cc..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- *  linux/arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-
-extern unsigned long *end_of_DRAM;
-extern PTE *Hash;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-unsigned long empty_zero_page[1024];
-
-unsigned char aux_device_present;
-#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 */
-#endif
-
-#undef HASHSTATS
-
-extern unsigned long isBeBox[];
-
-/* copy of the residual data */
-RESIDUAL res;
-unsigned long resptr = 0; /* ptr to residual data from hw */
-
-/*
- * The format of "screen_info" is strange, and due to early
- * i386-setup code. This is just enough to make the console
- * code think we're on a EGA+ colour display.
- */
- /* this is changed only in minor ways from the original
-        -- Cort
- */
-struct screen_info screen_info = {
-  0, 25,                       /* orig-x, orig-y */
-  { 0, 0 },            /* unused */
-  0,                   /* orig-video-page */
-  0,                   /* orig-video-mode */
-  80,                  /* orig-video-cols */
-  0,0,0,                       /* ega_ax, ega_bx, ega_cx */
-  25,                  /* orig-video-lines */
-  1,                   /* orig-video-isVGA */
-  16                   /* orig-video-points */
-};
-
-
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
-  return memory_start;
-}
-
-#ifdef HASHSTATS
-unsigned long *hashhits;
-#endif
-
-extern unsigned long _TotalMemory;
-/* find the physical size of RAM and setup hardware hash table */
-unsigned long *find_end_of_memory(void)
-{
-  extern BAT BAT2;
-  _TotalMemory = res.TotalMemory;
-  
-  if (_TotalMemory == 0 )
-  {
-    printk("Ramsize from residual data was 0 -- Probing for value\n");
-    /* this needs be done differently since the bats actually map
-       addresses beyond physical memory! -- Cort */
-#if 0
-    probingmem = 1;
-    while ( probingmem )
-    {
-       _TotalMemory += 0x00800000; /* 8M */
-       *(unsigned long *)_TotalMemory+KERNELBASE;
-    }
-    _TotalMemory -= 0x00800000;
-#else    
-    _TotalMemory = 0x03000000;
-#endif
-    printk("Ramsize probed to be %dM\n", _TotalMemory>>20);
-  }
-  
-  /* setup BAT2 mapping so that it covers kernelbase to kernelbase+ramsize */
-  switch(_TotalMemory)
-  {
-    case 0x01000000:           /* 16M */
-      BAT2.batu.bl = BL_16M;
-      Hash_size = HASH_TABLE_SIZE_128K;
-      Hash_mask = HASH_TABLE_MASK_128K;
-      break;
-    case 0x00800000:           /* 8M */
-      BAT2.batu.bl = BL_8M;
-      Hash_size = HASH_TABLE_SIZE_64K;
-      Hash_mask = HASH_TABLE_MASK_64K;
-      break;
-    case 0x01800000:           /* 24M */
-    case 0x02000000:           /* 32M */
-      BAT2.batu.bl = BL_32M;
-      Hash_size = HASH_TABLE_SIZE_256K;
-      Hash_mask = HASH_TABLE_MASK_256K;
-      break;
-    case 0x03000000:           /* 48M */
-    case 0x04000000:           /* 64M */
-      BAT2.batu.bl = BL_64M;
-      Hash_size = HASH_TABLE_SIZE_512K;
-      Hash_mask = HASH_TABLE_MASK_512K;
-      break;
-    case 0x05000000:           /* 80M */
-      BAT2.batu.bl = BL_128M;
-      Hash_size = HASH_TABLE_SIZE_1M;
-      Hash_mask = HASH_TABLE_MASK_1M;
-      break;    
-    default:
-      printk("WARNING: setup.c: find_end_of_memory() unknown total ram size %x\n",
-            _TotalMemory);
-      break;
-  }
-  
-  Hash = (PTE *)((_TotalMemory-Hash_size)+KERNELBASE);
-  bzero(Hash, Hash_size);
-  
-#ifdef HASHSTATS
-  hashhits = (unsigned long *)Hash - (Hash_size/sizeof(struct _PTE))/2;
-  bzero(hashhits, (Hash_size/sizeof(struct _PTE))/2);
-  return ((unsigned long *)hashhits);
-#else
-  return ((unsigned long *)Hash);
-#endif
-}
-
-int size_memory;
-
-/*
- * This is set up by the setup-routine at boot-time
- */
-#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#ifdef CONFIG_APM
-#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
-#endif
-#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
-#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
-#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
-#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
-#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
-#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
-#define COMMAND_LINE ((char *) (PARAM+2048))
-#define COMMAND_LINE_SIZE 256
-
-#define RAMDISK_IMAGE_START_MASK       0x07FF
-#define RAMDISK_PROMPT_FLAG            0x8000
-#define RAMDISK_LOAD_FLAG              0x4000  
-
-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)
-{
-  extern int _end;
-  extern char cmd_line[];
-  unsigned char reg;
-  extern int panic_timeout;
-  char inf[512];
-  int i;
-
-  if (isBeBox[0])
-    _Processor = _PROC_Be;
-  else
-  {
-    if (strncmp(res.VitalProductData.PrintableModel,"IBM",3))
-    {
-      _Processor = _PROC_Motorola;
-    }
-    else
-      _Processor = _PROC_IBM;
-  }
-  
-  get_cpuinfo(&inf);
-  printk("%s",inf);
-  
-  /* Set up floppy in PS/2 mode */
-  outb(0x09, SIO_CONFIG_RA);
-  reg = inb(SIO_CONFIG_RD);
-  reg = (reg & 0x3F) | 0x40;
-  outb(reg, SIO_CONFIG_RD);
-  outb(reg, SIO_CONFIG_RD);    /* Have to write twice to change! */
-
-  switch ( _Processor )
-  {
-    case _PROC_IBM:
-        ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
-       break;
-    case _PROC_Motorola:
-        ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
-        break;
-  }
-  aux_device_present = 0xaa;
-
-  panic_timeout = 300;         /* reboot on panic */
-  
-#if 0
-  /* get root via nfs from charon -- was only used for testing */
-  ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);        /* nfs */
-  /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
-  strcpy(cmd_line,
-        "nfsaddrs=129.138.6.101:129.138.6.90:129.138.6.1:255.255.255.0:gordito nfsroot=/joplin/ppc/root/");
-#endif
-  *cmdline_p = cmd_line;
-  *memory_start_p = (unsigned long) &_end;
-  (unsigned long *)*memory_end_p = (unsigned long *)end_of_DRAM;
-  size_memory = *memory_end_p - KERNELBASE;  /* Relative size of memory */
-
-#ifdef CONFIG_BLK_DEV_RAM
-  rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-  rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-  rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#if 1
-  rd_prompt = 1;
-  rd_doload = 1;
-  rd_image_start = 0;
-#endif
-#endif
-
-  /* Save unparsed command line copy for /proc/cmdline */
-  memcpy(saved_command_line, cmd_line,strlen(cmd_line)+1);
-  printk("Command line: %s\n", cmd_line);
-}
-
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-  return -EIO;
-}
-
-
-int
-get_cpuinfo(char *buffer)
-{
-  extern unsigned long loops_per_sec;
-  int i;
-  int pvr = _get_PVR();
-  int len;
-  char *model;
-  unsigned long full = 0, overflow = 0;
-  unsigned int ti;
-  PTE *ptr;  
-  
-  switch (pvr>>16)
-    {
-    case 3:
-      model = "603";
-      break;
-    case 4:
-      model = "604";
-      break;
-    case 6:
-      model = "603e";
-      break;
-    case 7:
-      model = "603ev";
-      break;
-    default:
-      model = "unknown";
-      break;
-    }
-  
-#ifdef __SMP__
-#define CD(X)          (cpu_data[n].X)  
-#else
-#define CD(X) (X)
-#define CPUN 0
-#endif
-  
-  len = sprintf(buffer, "PowerPC %s/%dMHz revision %d.%d %s\n",
-               model,
-               (res.VitalProductData.ProcessorHz > 1024) ?
-               res.VitalProductData.ProcessorHz>>20 :
-               res.VitalProductData.ProcessorHz,
-               MAJOR(pvr), MINOR(pvr),
-               (inb(IBM_EQUIP_PRESENT) & 2) ? "" : "upgrade");
-#if 1
-  if ( res.VitalProductData.PrintableModel[0] )
-    len += sprintf(buffer+len,"%s\n",res.VitalProductData.PrintableModel);
-  
-  len += sprintf(buffer+len,"Bus %dMHz\n",
-               (res.VitalProductData.ProcessorBusHz > 1024) ?
-               res.VitalProductData.ProcessorBusHz>>20 :
-               res.VitalProductData.ProcessorBusHz);
-  
-  /* make sure loops_per_sec has been setup -- ie not at boottime -- Cort */
-  if ( CD(loops_per_sec+2500)/500000 > 0)
-    len += sprintf(buffer+len,
-                  "bogomips: %lu.%02lu\n",
-                  CD(loops_per_sec+2500)/500000,
-                  (CD(loops_per_sec+2500)/5000) % 100);
-
-
-  len += sprintf(buffer+len,"Total Ram: %dM Hash Table: %dkB (%dk buckets)\n",
-        _TotalMemory>>20, Hash_size>>10,
-        (Hash_size/(sizeof(PTE)*8)) >> 10);
-  
-  for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
-  {
-    if (i == 0)
-      len += sprintf(buffer+len,"SIMM Banks: ");
-    if ( res.Memories[i].SIMMSize != 0 )
-      len += sprintf(buffer+len,"%d:%dM ",i,
-                    (res.Memories[i].SIMMSize > 1024) ?
-                    res.Memories[i].SIMMSize>>20 :
-                    res.Memories[i].SIMMSize);
-    if ( i == MAX_MEMS-1)
-      len += sprintf(buffer+len,"\n");
-  }
-
-  /* TLB */
-  len += sprintf(buffer+len,"TLB");
-  switch(res.VitalProductData.TLBAttrib)
-  {
-    case CombinedTLB:
-      len += sprintf(buffer+len,": %d entries\n",
-                    res.VitalProductData.TLBSize);
-      break;
-    case SplitTLB:
-      len += sprintf(buffer+len,": (split I/D) %d/%d entries\n",
-                    res.VitalProductData.I_TLBSize,
-                    res.VitalProductData.D_TLBSize);
-      break;
-    case NoneTLB:
-      len += sprintf(buffer+len,": not present\n");
-      break;
-  }
-
-  /* L1 */
-  len += sprintf(buffer+len,"L1: ");
-  switch(res.VitalProductData.CacheAttrib)
-  {
-    case CombinedCAC:
-      len += sprintf(buffer+len,"%dkB LineSize\n",
-                    res.VitalProductData.CacheSize,
-                    res.VitalProductData.CacheLineSize);
-      break;
-    case SplitCAC:
-      len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
-                    res.VitalProductData.I_CacheSize,
-                    res.VitalProductData.D_CacheSize,
-                    res.VitalProductData.D_CacheLineSize,
-                    res.VitalProductData.D_CacheLineSize);
-      break;
-    case NoneCAC:
-      len += sprintf(buffer+len,"not present\n");
-      break;
-  }
-
-  /* L2 */
-  if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
-  {
-    int size;
-    
-    len += sprintf(buffer+len,"L2: %dkB %s\n",
-                  ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
-                   (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
-  }
-  else
-  {
-    len += sprintf(buffer+len,"L2: not present\n");
-  }
-#if 0  
-  len+= sprintf(buffer+len,"Equip register %x\n",
-               inb(IBM_EQUIP_PRESENT));
-  len+= sprintf(buffer+len,"L2Status register %x\n",
-               inb(IBM_L2_STATUS));
-#endif
-#endif
-
-  
-  return len;
-}
index ba8864251f7afebccbbc2d7b005564e8ce3bd013..2f602059c6c635a0fe808eb3d4d4f796a2fbd824 100644 (file)
@@ -1,9 +1,17 @@
 /*
  *  linux/arch/ppc/kernel/signal.c
  *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Adapted for PowerPC by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/kernel/signal.c"
+ *    Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
  */
 
 #include <linux/sched.h>
 
 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
+#define DEBUG_SIGNALS
+#undef  DEBUG_SIGNALS
+
+#define PAUSE_AFTER_SIGNAL
+#undef  PAUSE_AFTER_SIGNAL
+
 asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 
 /*
@@ -30,79 +44,85 @@ asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs)
 {
        unsigned long mask;
-       int ret = -EINTR;
 
-       lock_kernel();
+       spin_lock_irq(&current->sigmask_lock);
        mask = current->blocked;
        current->blocked = set & _BLOCKABLE;
+       spin_unlock_irq(&current->sigmask_lock);
+
        regs->gpr[3] = -EINTR;
-#if 0
+#ifdef DEBUG_SIGNALS
 printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set);  
 #endif
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                schedule();
-               if (do_signal(mask,regs))
-                       goto out;
+               if (do_signal(mask,regs)) {
+                       /*
+                        * If a signal handler needs to be called,
+                        * do_signal() has set R3 to the signal number (the
+                        * first argument of the signal handler), so don't
+                        * overwrite that with EINTR !
+                        * In the other cases, do_signal() doesn't touch 
+                        * R3, so it's still set to -EINTR (see above).
+                        */
+                       return regs->gpr[3];
+               }
        }
-out:
-       unlock_kernel();
-       return ret;
 }
 
+/*
+ * This sets regs->esp even though we don't actually use sigstacks yet..
+ */
 asmlinkage int sys_sigreturn(struct pt_regs *regs)
 {
        struct sigcontext_struct *sc;
        struct pt_regs *int_regs;
        int signo, ret;
 
-       lock_kernel();
 #if 1  
        if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
-           || (regs->gpr[1] >=KERNELBASE))
+           || (regs->gpr[1] >= KERNELBASE))
                goto badframe;
 #endif 
-       sc = (struct sigcontext_struct *)regs->gpr[1];
-       current->blocked = sc->oldmask & _BLOCKABLE;
-       int_regs = sc->regs;
-       signo = sc->signal;
-       sc++;  /* Pop signal 'context' */
+       sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
+       get_user(current->blocked, &sc->oldmask);
+       current->blocked &= _BLOCKABLE;
+       get_user(int_regs, &sc->regs);
+       get_user(signo, &sc->signal);
+       sc++;                   /* Pop signal 'context' */
+#ifdef DEBUG_SIGNALS
+printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+#endif
        if (sc == (struct sigcontext_struct *)(int_regs)) {
                /* Last stacked signal */
-#if 0  
-               /* This doesn't work - it blows away the return address! */
                memcpy(regs, int_regs, sizeof(*regs));
-#else
-               /* Don't mess up 'my' stack frame */
-               memcpy(&regs->gpr, &int_regs->gpr, sizeof(*regs)-sizeof(regs->_overhead));
-#endif         
-               if ((int)regs->orig_gpr3 >= 0 &&
+               if (regs->trap == 0x0C00 /* System Call! */ &&
                    ((int)regs->result == -ERESTARTNOHAND ||
                     (int)regs->result == -ERESTARTSYS ||
-                    (int)regs->result == -ERESTARTNOINTR))
-               {
+                    (int)regs->result == -ERESTARTNOINTR)) {
                        regs->gpr[3] = regs->orig_gpr3;
                        regs->nip -= 4; /* Back up & retry system call */
                        regs->result = 0;
                }
-               ret = (regs->result);
-       } else { /* More signals to go */
-               regs->gpr[1] = (unsigned long)sc;
-               regs->gpr[3] = sc->signal;
-               regs->gpr[4] = sc->regs;
-               regs->link = (unsigned long)((sc->regs)+1);
-               regs->nip = sc->handler;
-               ret = sc->signal;
+               ret = regs->result;
+       } else {
+               /* More signals to go */
+               regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+               get_user(regs->gpr[3], &sc->signal);
+               get_user(int_regs, (struct pt_regs **) &sc->regs);
+               regs->gpr[4] = (unsigned long) int_regs;
+               regs->link = (unsigned long) (int_regs+1);
+               get_user(regs->nip, &sc->handler);
+               ret = regs->gpr[3];
        }
-       goto out;
+       return ret;
 
 badframe:
-       /*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
-        regs,current->comm,current->pid);*/
+       lock_kernel();
        do_exit(SIGSEGV);
-out:
        unlock_kernel();
-       return ret;
+       return -EFAULT;
 }
 
 
@@ -120,21 +140,24 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
        unsigned long mask;
        unsigned long handler_signal = 0;
        unsigned long *frame = NULL;
-       unsigned long *trampoline, *regs_ptr;
+       unsigned long *trampoline;
+       unsigned long *regs_ptr;
        unsigned long nip = 0;
        unsigned long signr;
        struct sigcontext_struct *sc;
        struct sigaction * sa;
-       int bitno, s, ret;
+       int bitno;
 
-       lock_kernel();
        mask = ~current->blocked;
        while ((signr = current->signal & mask)) {
+#if 0
+               signr = ffz(~signr);  /* Compute bit # */
+#else
                for (bitno = 0;  bitno < 32;  bitno++)
                        if (signr & (1<<bitno))
                                break;
                signr = bitno;
-
+#endif
                current->signal &= ~(1<<signr);  /* Clear bit */
                sa = current->sig->action + signr;
                signr++;
@@ -150,6 +173,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                                continue;
                        if (_S(signr) & current->blocked) {
                                current->signal |= _S(signr);
+                               spin_lock_irq(&current->sigmask_lock);
+                               spin_unlock_irq(&current->sigmask_lock);
                                continue;
                        }
                        sa = current->sig->action + signr - 1;
@@ -169,32 +194,45 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                        case SIGCONT: case SIGCHLD: case SIGWINCH:
                                continue;
 
-                       case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+                       case SIGTSTP: case SIGTTIN: case SIGTTOU:
+                               if (is_orphaned_pgrp(current->pgrp))
+                                       continue;
+                       case SIGSTOP:
                                if (current->flags & PF_PTRACED)
                                        continue;
                                current->state = TASK_STOPPED;
                                current->exit_code = signr;
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
-                                     SA_NOCLDSTOP))
+                                               SA_NOCLDSTOP))
                                        notify_parent(current);
                                schedule();
                                continue;
 
                        case SIGQUIT: case SIGILL: case SIGTRAP:
                        case SIGIOT: case SIGFPE: case SIGSEGV:
+                               lock_kernel();
                                if (current->binfmt && current->binfmt->core_dump) {
                                        if (current->binfmt->core_dump(signr, regs))
                                                signr |= 0x80;
                                }
+                               unlock_kernel();
                                /* fall through */
                        default:
+                               spin_lock_irq(&current->sigmask_lock);
                                current->signal |= _S(signr & 0x7f);
+                               spin_unlock_irq(&current->sigmask_lock);
+
+                               current->flags |= PF_SIGNALED;
+
+                               lock_kernel(); /* 8-( */
                                do_exit(signr);
+                               unlock_kernel();
                        }
                }
-
-               /* handle signal */
-               if ((int)regs->orig_gpr3 >= 0) {
+               /*
+                * OK, we're invoking a handler
+                */
+               if (regs->trap == 0x0C00 /* System Call! */) {
                        if ((int)regs->result == -ERESTARTNOHAND ||
                            ((int)regs->result == -ERESTARTSYS &&
                             !(sa->sa_flags & SA_RESTART)))
@@ -203,9 +241,18 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                handler_signal |= 1 << (signr-1);
                mask &= ~sa->sa_mask;
        }
-       ret = 0;
-       if (!handler_signal)            /* no handler will be called - return 0 */
-               goto out;
+
+       if (regs->trap == 0x0C00 /* System Call! */ &&
+           ((int)regs->result == -ERESTARTNOHAND ||
+            (int)regs->result == -ERESTARTSYS ||
+            (int)regs->result == -ERESTARTNOINTR)) {
+               regs->gpr[3] = regs->orig_gpr3;
+               regs->nip -= 4; /* Back up & retry system call */
+               regs->result = 0;
+       }
+
+       if (!handler_signal)    /* no handler will be called - return 0 */
+               return 0;
 
        nip = regs->nip;
        frame = (unsigned long *) regs->gpr[1];
@@ -213,20 +260,18 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
        /* Build trampoline code on stack */
        frame -= 2;
        trampoline = frame;
-#if 1
        /* verify stack is valid for writing regs struct */
        if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
-           || (frame >= KERNELBASE ))
+           || ((unsigned long) frame >= KERNELBASE ))
                goto badframe;
-#endif
-       trampoline[0] = 0x38007777;  /* li r0,0x7777 */
-       trampoline[1] = 0x44000002;  /* sc           */
+       put_user(0x38007777UL, trampoline);      /* li r0,0x7777 */
+       put_user(0x44000002UL, trampoline+1);    /* sc           */
        frame -= sizeof(*regs) / sizeof(long);
        regs_ptr = frame;
-       memcpy(regs_ptr, regs, sizeof(*regs));
+       copy_to_user(regs_ptr, regs, sizeof(*regs));
        signr = 1;
        sa = current->sig->action;
-  
+
        for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
                if (mask > handler_signal)
                        break;
@@ -234,50 +279,39 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                        continue;
 
                frame -= sizeof(struct sigcontext_struct) / sizeof(long);
-#if 1
                if (verify_area(VERIFY_WRITE,(void *)frame,
                                sizeof(struct sigcontext_struct)/sizeof(long)))
                        goto badframe;
-#endif    
                sc = (struct sigcontext_struct *)frame;
                nip = (unsigned long) sa->sa_handler;
-#if 0 /* Old compiler */               
-               nip = *(unsigned long *)nip;
-#endif         
                if (sa->sa_flags & SA_ONESHOT)
                        sa->sa_handler = NULL;
-               sc->handler = nip;
-               sc->oldmask = current->blocked;
-               sc->regs = (unsigned long)regs_ptr;
-               sc->signal = signr;
+               put_user(nip, &sc->handler);
+               put_user(oldmask, &sc->oldmask); /* was current->blocked */
+               put_user(regs_ptr, &sc->regs);
+               put_user(signr, &sc->signal);
                current->blocked |= sa->sa_mask;
                regs->gpr[3] = signr;
                regs->gpr[4] = (unsigned long)regs_ptr;
        }
        regs->link = (unsigned long)trampoline;
        regs->nip = nip;
-       regs->gpr[1] = (unsigned long)sc;
+       regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
 
-       /* The DATA cache must be flushed here to insure coherency
-        * between the DATA & INSTRUCTION caches.  Since we just
-        * created an instruction stream using the DATA [cache] space
-        * and since the instruction cache will not look in the DATA
-        * cache for new data, we have to force the data to go on to
-        * memory and flush the instruction cache to force it to look
-        * there.  The following function performs this magic
-        */
-       flush_instruction_cache();
-       ret = 1;
-       goto out;
+       /* The DATA cache must be flushed here to insure coherency */
+       /* between the DATA & INSTRUCTION caches.  Since we just */
+       /* created an instruction stream using the DATA [cache] space */
+       /* and since the instruction cache will not look in the DATA */
+       /* cache for new data, we have to force the data to go on to */
+       /* memory and flush the instruction cache to force it to look */
+       /* there.  The following function performs this magic */
+       store_cache_range((unsigned long) trampoline,
+                         (unsigned long) (trampoline + 2));
+       return 1;
 
 badframe:
-#if 0
-       printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
-              signr, frame, regs, current->comm, current->pid);
-#endif
+       lock_kernel();
        do_exit(SIGSEGV);
-
-out:
        unlock_kernel();
-       return ret;
+       return 0;
 }
diff --git a/arch/ppc/kernel/strcase.c b/arch/ppc/kernel/strcase.c
new file mode 100644 (file)
index 0000000..a9e40bc
--- /dev/null
@@ -0,0 +1,12 @@
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+       int c1, c2;
+
+       do {
+               c1 = tolower(*s1++);
+               c2 = tolower(*s2++);
+       } while (c1 == c2 && c1 != 0);
+       return c1 - c2;
+}
diff --git a/arch/ppc/kernel/stubs.c b/arch/ppc/kernel/stubs.c
deleted file mode 100644 (file)
index 30f0282..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*#include <linux/in.h>*/
-#include <linux/autoconf.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-void sys_iopl(void)
-{
-       lock_kernel();
-       panic("sys_iopl");
-       unlock_kernel();
-}
-void sys_vm86(void)
-{
-       lock_kernel();
-       panic("sys_vm86");
-       unlock_kernel();
-}
-void sys_modify_ldt(void)
-{
-       lock_kernel();
-       panic("sys_modify_ldt");
-       unlock_kernel();
-}
-
-void sys_ipc(void)
-{
-       lock_kernel();
-       panic("sys_ipc");
-       unlock_kernel();
-}
-
-void sys_newselect(void)
-{
-       lock_kernel();
-       panic("sys_newselect");
-       unlock_kernel();
-}
-
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
-       lock_kernel();
-       panic("scsi_register_module");
-       unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
-       lock_kernel();
-       panic("scsi_unregister_module");
-       unlock_kernel();
-}
-#endif
-
-
-
diff --git a/arch/ppc/kernel/support.c b/arch/ppc/kernel/support.c
deleted file mode 100644 (file)
index cd2b58b..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Miscellaneous support routines
- */
-
-#include <asm/bitops.h>
-
-/*extern __inline__*/ int find_first_zero_bit(void *add, int len)
-{
-       int     mask, nr, i;
-       BITFIELD *addr = add;
-       nr = 0;
-       while (len)
-       {
-               if (~*addr != 0)
-               { /* Contains at least one zero */
-                       for (i = 0;  i < 32;  i++, nr++)
-                       {
-                               mask = BIT(nr);
-                               if ((mask & *addr) == 0)
-                               {
-                                       return (nr);
-                               }
-                       }
-               }
-               len -= 32;
-               addr++;
-               nr += 32;
-       }
-       return (0);  /* Shouldn't happen */
-}
-
-/*extern __inline__*/ int find_next_zero_bit(void *add, int last_bit, int nr)
-{
-       int     mask, i;
-       BITFIELD *addr = add;
-#if 0  
-printk("Find next (%x, %x)", addr, nr);
-#endif
-       addr += nr >> 5;
-#if 0  
-printk(" - Pat: %x(%08X)\n", addr, *addr);
-#endif
-       if ((nr & 0x1F) != 0)
-       { 
-               if (*addr != 0xFFFFFFFF)
-               { /* At least one more bit available in this longword */
-                       for (i = (nr&0x1F);  i < 32;  i++, nr++)
-                       {
-                               mask = BIT(nr);
-                               if ((mask & *addr) == 0)
-                               {
-#if 0                                  
-printk("(1)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
-#endif
-                                       return (nr);
-                               }
-                       }
-               }
-               addr++;
-               nr = (nr + 0x1F) & ~0x1F;
-       }
-       while (nr < last_bit)
-       {
-               if (*addr != 0xFFFFFFFF)
-               { /* Contains at least one zero */
-                       for (i = 0;  i < 32;  i++, nr++)
-                       {
-                               mask = BIT(nr);
-                               if ((mask & *addr) == 0)
-                               {
-#if 0                                  
-printk("(2)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
-#endif
-                                       return (nr);
-                               }
-                       }
-               }
-               addr++;
-               nr += 32;
-       }
-       return (nr);  /* Shouldn't happen */
-}
-
-
index 9d18c45ab2cfdb6ef22f63a0736ce8b48abbf4c9..bfdccdee6b81b85a8ea50612a849bb29da6e22eb 100644 (file)
@@ -9,6 +9,7 @@
  * platform.
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <linux/ipc.h>
 #include <asm/uaccess.h>
+#include <asm/ipc.h>
 
-/*
- * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way unix traditionally does this, though.
- */
-asmlinkage int sys_pipe(unsigned long * fildes)
-{
-       int error;
 
-       lock_kernel();
-       error = verify_area(VERIFY_WRITE,fildes,8);
-       if (error)
-               goto out;
-       error = do_pipe(fildes);
-out:
-       unlock_kernel();
-       return error;
+void
+check_bugs(void)
+{
 }
 
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
-                                  int flags, int fd, off_t offset)
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-       struct file * file = NULL;
-       int ret = -EBADF;
+       printk("sys_ioperm()\n");
+       return -EIO;
+}
 
+int sys_iopl(int a1, int a2, int a3, int a4)
+{
        lock_kernel();
-       if (!(flags & MAP_ANONYMOUS)) {
-               if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-                       goto out;
-       }
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       ret = do_mmap(file, addr, len, prot, flags, offset);
-out:
+       printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
        unlock_kernel();
-       return ret;
+       return (ENOSYS);
 }
 
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
- * block for parameter passing..
- */
-asmlinkage int old_mmap(unsigned long *buffer)
+int sys_vm86(int a1, int a2, int a3, int a4)
 {
-       int error;
-       unsigned long flags;
-       long a,b,c,d,e;
-       struct file * file = NULL;
-
        lock_kernel();
-       error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
-       if (error)
-               goto out;
-       get_user(flags,buffer+3);
-       if (!(flags & MAP_ANONYMOUS)) {
-               unsigned long fd;
-               get_user(fd,buffer+4);
-               error = -EBADF;
-               if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-                       goto out;
-       }
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       error = -EFAULT;
-       if ( get_user(a,buffer) || get_user(b,buffer+1) ||
-            get_user(c,buffer+2)||get_user(d,buffer+5) )
-               goto out;
-       error = do_mmap(file,a,b,c, flags, d);
-out:
+       printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
        unlock_kernel();
-       return error;
+       return (ENOSYS);
 }
 
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
-asmlinkage int old_select(unsigned long *buffer)
+int sys_modify_ldt(int a1, int a2, int a3, int a4)
 {
-       int n;
-       fd_set *inp;
-       fd_set *outp;
-       fd_set *exp;
-       struct timeval *tvp;
-
        lock_kernel();
-       n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
-       if (n)
-               goto out;
-       get_user(n,buffer);
-       get_user(inp,buffer+1);
-       get_user(outp,buffer+2);
-       get_user(exp,buffer+3);
-       get_user(tvp,buffer+4);
-       n = sys_select(n, inp, outp, exp, tvp);
-out:
+       printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
        unlock_kernel();
-       return n;
+       return (ENOSYS);
 }
-#if 0
 
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
@@ -145,12 +86,12 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
                        ret = -EINVAL;
                        if (!ptr)
                                goto out;
-                       if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))))
-                               goto out;
-                       fourth.__pad = (void *) get_fs_long(ptr);
+                       ret = -EFAULT;
+                       if (get_user(fourth.__pad, (void **) ptr))
+                               goto out;       
                        ret = sys_semctl (first, second, third, fourth);
                        goto out;
-                       }
+               }
                default:
                        ret = -EINVAL;
                        goto out;
@@ -168,13 +109,13 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
                                ret = -EINVAL;
                                if (!ptr)
                                        goto out;
-                               if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
-                                       goto out;
-                               memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
-                                              sizeof (tmp));
+                               ret = -EFAULT;
+                               if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, 
+                                                  sizeof (tmp)))
+                                       goto out;       
                                ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
                                goto out;
-                               }
+                       }
                        case 1: default:
                                ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
                                goto out;
@@ -195,15 +136,12 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
                        switch (version) {
                        case 0: default: {
                                ulong raddr;
-                               if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
-                                       goto out;
                                ret = sys_shmat (first, (char *) ptr, second, &raddr);
                                if (ret)
                                        goto out;
-                               put_fs_long (raddr, (ulong *) third);
-                               ret = 0;
+                               ret = put_user (raddr, (ulong *) third);
                                goto out;
-                               }
+                       }
                        case 1: /* iBCS2 emulator entry point */
                                ret = -EINVAL;
                                if (get_fs() != get_ds())
@@ -230,4 +168,81 @@ out:
        unlock_kernel();
        return ret;
 }
+
+
+#ifndef CONFIG_MODULES
+void
+scsi_register_module(void)
+{
+       lock_kernel();
+       panic("scsi_register_module");
+       unlock_kernel();
+}
+
+void
+scsi_unregister_module(void)
+{
+       lock_kernel();
+       panic("scsi_unregister_module");
+       unlock_kernel();
+}
 #endif
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+       int fd[2];
+       int error;
+
+       error = verify_area(VERIFY_WRITE,fildes,8);
+       if (error)
+               return error;
+       error = do_pipe(fd);
+       if (error)
+               return error;
+       put_user(fd[0],0+fildes);
+       put_user(fd[1],1+fildes);
+       return 0;
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+                                 unsigned long prot, unsigned long flags,
+                                 unsigned long fd, off_t offset)
+{
+       struct file * file = NULL;
+       if (!(flags & MAP_ANONYMOUS)) {
+               if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+                       return -EBADF;
+       }
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+       return do_mmap(file, addr, len, prot, flags, offset);
+}
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+/*
+ * Due to some executables calling the wrong select we sometimes
+ * get wrong args.  This determines how the args are being passed
+ * (a single ptr to them all args passed) then calls
+ * sys_select() with the appropriate args. -- Cort
+ */
+asmlinkage int 
+ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
+{
+       int err;
+       if ( (unsigned long)n >= 4096 )
+       {
+               unsigned long *buffer = (unsigned long *)n;
+               if ( get_user(n, buffer) ||
+                    get_user(inp,buffer+1) ||
+                    get_user(outp,buffer+2) ||
+                    get_user(exp,buffer+3) ||
+                    get_user(tvp,buffer+4) )
+                       return -EFAULT;
+       }
+       return sys_select(n, inp, outp, exp, tvp);
+}
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
deleted file mode 100644 (file)
index cdcad82..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- *  linux/arch/i386/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * Adapted for PowerPC (PreP) by Gary Thomas
- *
- * This file contains the PC-specific time handling details:
- * reading the RTC at bootup, etc..
- * 1994-07-02    Alan Modra
- *     fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- * 1995-03-26    Markus Kuhn
- *      fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
- *      precision CMOS clock update
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/nvram.h>
-#include <asm/mc146818rtc.h>
-#include <asm/processor.h>
-
-#include <linux/timex.h>
-#include <linux/config.h>
-
-extern int isBeBox[];
-
-#define TIMER_IRQ 0
-
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned long long last_timer_cc = 0;
-static unsigned long long init_timer_cc = 0;
-
-static inline int CMOS_READ(int addr)
-{
-       outb(addr>>8, NVRAM_AS1);
-       outb(addr, NVRAM_AS0);
-       return (inb(NVRAM_DATA));
-}
-
-static inline int CMOS_WRITE(int addr, int val)
-{
-       outb(addr>>8, NVRAM_AS1);
-       outb(addr, NVRAM_AS0);
-       return (outb(val, NVRAM_DATA));
-}
-
-/* This function must be called with interrupts disabled 
- * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
- * 
- * However, the pc-audio speaker driver changes the divisor so that
- * it gets interrupted rather more often - it loads 64 into the
- * counter rather than 11932! This has an adverse impact on
- * do_gettimeoffset() -- it stops working! What is also not
- * good is that the interval that our timer function gets called
- * is no longer 10.0002 ms, but 9.9767 ms. To get around this
- * would require using a different timing source. Maybe someone
- * could use the RTC - I know that this can interrupt at frequencies
- * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
- * it so that at startup, the timer code in sched.c would select
- * using either the RTC or the 8253 timer. The decision would be
- * based on whether there was any other device around that needed
- * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that 
- * advanced the clock by 1/1024 s. Every time that reached over 1/100
- * of a second, then do all the old code. If the time was kept correct
- * then do_gettimeoffset could just return 0 - there is no low order
- * divider that can be accessed.
- *
- * Ideally, you would be able to use the RTC for the speaker driver,
- * but it appears that the speaker driver really needs interrupt more
- * often than every 120 us or so.
- *
- * Anyway, this needs more thought....         pjsg (1993-08-28)
- * 
- * If you are really that interested, you should be reading
- * comp.protocols.time.ntp!
- */
-
-#define TICK_SIZE tick
-
-static unsigned long do_slow_gettimeoffset(void)
-{
-       int count;
-       unsigned long offset = 0;
-
-       /* timer count may underflow right here */
-       outb_p(0x00, 0x43);     /* latch the count ASAP */
-       count = inb_p(0x40);    /* read the latched count */
-       count |= inb(0x40) << 8;
-       /* we know probability of underflow is always MUCH less than 1% */
-       if (count > (LATCH - LATCH/100)) {
-               /* check for pending timer interrupt */
-               outb_p(0x0a, 0x20);
-               if (inb(0x20) & 1)
-                       offset = TICK_SIZE;
-       }
-       count = ((LATCH-1) - count) * TICK_SIZE;
-       count = (count + LATCH/2) / LATCH;
-       return offset + count;
-}
-
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
-
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       *tv = xtime;
-       tv->tv_usec += do_gettimeoffset();
-       if (tv->tv_usec >= 1000000) {
-               tv->tv_usec -= 1000000;
-               tv->tv_sec++;
-       }
-       restore_flags(flags);
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-       cli();
-       /* This is revolting. We need to set the xtime.tv_usec
-        * correctly. However, the value in this location is
-        * is value at the last tick.
-        * Discover what correction gettimeofday
-        * would have done, and then undo it!
-        */
-       tv->tv_usec -= do_gettimeoffset();
-
-       if (tv->tv_usec < 0) {
-               tv->tv_usec += 1000000;
-               tv->tv_sec--;
-       }
-
-       xtime = *tv;
-       time_state = TIME_BAD;
-       time_maxerror = 0x70000000;
-       time_esterror = 0x70000000;
-       set_rtc(xtime.tv_sec);
-       sti();
-}
-
-static int      month_days[12] = {
-       31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-#define FEBRUARY       2
-#define        STARTOFTIME     1970
-#define SECDAY         86400L
-#define SECYR          (SECDAY * 365)
-#define        leapyear(year)          ((year) % 4 == 0)
-#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
-#define        days_in_month(a)        (month_days[(a) - 1])
-
-struct _tm
-{
-       int             tm_sec;
-       int             tm_min;
-       int             tm_hour;
-       int             tm_day;
-       int             tm_month;
-       int             tm_year;
-};
-
-static _to_tm(int tim, struct _tm * tm)
-{
-       register int    i;
-       register long   hms, day;
-
-       day = tim / SECDAY;
-       hms = tim % SECDAY;
-
-       /* Hours, minutes, seconds are easy */
-       tm->tm_hour = hms / 3600;
-       tm->tm_min = (hms % 3600) / 60;
-       tm->tm_sec = (hms % 3600) % 60;
-
-       /* Number of years in days */
-       for (i = STARTOFTIME; day >= days_in_year(i); i++)
-               day -= days_in_year(i);
-       tm->tm_year = i;
-
-       /* Number of months in days left */
-       if (leapyear(tm->tm_year))
-               days_in_month(FEBRUARY) = 29;
-       for (i = 1; day >= days_in_month(i); i++)
-               day -= days_in_month(i);
-       days_in_month(FEBRUARY) = 28;
-       tm->tm_month = i;
-
-       /* Days are what is left over (+1) from all that. */
-       tm->tm_day = day + 1;
-}
-
-/*
- * Set the time into the CMOS
- */
-static void set_rtc(unsigned long nowtime)
-{
-  int retval = 0;
-  struct _tm tm;
-  unsigned char save_control, save_freq_select;
-  
-  /*if (_Processor != _PROC_IBM) return;*/
-  
-  _to_tm(nowtime, &tm);
-  
-  /* tell the clock it's being set */  
-  save_control = CMOS_MCRTC_READ(MCRTC_CONTROL); 
-  CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
-  /* stop and reset prescaler */  
-  save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT);
-  CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
-
-  printk("Set RTC H:M:S M/D/Y %d:%02d:%02d %d/%d/%d\n", 
-       tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_month, tm.tm_day, tm.tm_year);
-       if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
-               BIN_TO_BCD(tm.tm_sec);
-               BIN_TO_BCD(tm.tm_min);
-               BIN_TO_BCD(tm.tm_hour);
-               BIN_TO_BCD(tm.tm_month);
-               BIN_TO_BCD(tm.tm_day);
-               BIN_TO_BCD(tm.tm_year);
-       }
-
-       CMOS_MCRTC_WRITE(tm.tm_sec,  MCRTC_SECONDS);
-       CMOS_MCRTC_WRITE(tm.tm_min,  MCRTC_MINUTES);
-       CMOS_MCRTC_WRITE(tm.tm_hour, MCRTC_HOURS);
-       CMOS_MCRTC_WRITE(tm.tm_month,  MCRTC_MONTH);
-       CMOS_MCRTC_WRITE(tm.tm_day,  MCRTC_MINUTES);
-       CMOS_MCRTC_WRITE(tm.tm_year - 1900, MCRTC_MINUTES);
-
-       /* The following flags have to be released exactly in this order,
-        * otherwise the DS12887 (popular MC146818A clone with integrated
-        * battery and quartz) will not reset the oscillator and will not
-        * update precisely 500 ms later. You won't find this mentioned in
-        * the Dallas Semiconductor data sheets, but who believes data
-        * sheets anyway ...                           -- Markus Kuhn
-        */
-       CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
-       CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
-}
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- */
-static int set_rtc_mmss(unsigned long nowtime)
-{
-       int retval = 0;
-       int real_seconds, real_minutes, cmos_minutes;
-       unsigned char save_control, save_freq_select;
-
-#ifdef __powerpc__
-printk("%s: %d - set TOD\n", __FILE__, __LINE__);
-return (-1);  /* Not implemented */
-#else  
-
-printk("%s: %d - set TOD\n", __FILE__, __LINE__);
-       save_control = CMOS_MCRTC_READ(MCRTC_CONTROL); /* tell the clock it's being set */
-       CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
-
-       save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT); /* stop and reset prescaler */
-       CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
-
-       cmos_minutes = CMOS_MCRTC_READ(MCRTC_MINUTES);
-       if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD)
-               BCD_TO_BIN(cmos_minutes);
-
-       /*
-        * since we're only adjusting minutes and seconds,
-        * don't interfere with hour overflow. This avoids
-        * messing with unknown time zones but requires your
-        * RTC not to be off by more than 15 minutes
-        */
-       real_seconds = nowtime % 60;
-       real_minutes = nowtime / 60;
-       if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
-               real_minutes += 30;             /* correct for half hour time zone */
-       real_minutes %= 60;
-
-       if (abs(real_minutes - cmos_minutes) < 30) {
-               if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
-                       BIN_TO_BCD(real_seconds);
-                       BIN_TO_BCD(real_minutes);
-               }
-               CMOS_MCRTC_WRITE(real_seconds,MCRTC_SECONDS);
-               CMOS_MCRTC_WRITE(real_minutes,MCRTC_MINUTES);
-       } else
-               retval = -1;
-
-       /* The following flags have to be released exactly in this order,
-        * otherwise the DS12887 (popular MC146818A clone with integrated
-        * battery and quartz) will not reset the oscillator and will not
-        * update precisely 500 ms later. You won't find this mentioned in
-        * the Dallas Semiconductor data sheets, but who believes data
-        * sheets anyway ...                           -- Markus Kuhn
-        */
-       CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
-       CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
-
-       return retval;
-#endif 
-}
-
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
-{
-  static int timeints = 0;
-  
-  do_timer(regs);
-
-  /*
-   * If we have an externally synchronized Linux clock, then update
-   * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-   * called as close as possible to 500 ms before the new second starts.
-   */
-  if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
-      xtime.tv_usec > 500000 - (tick >> 1) &&
-      xtime.tv_usec < 500000 + (tick >> 1))
-    if (set_rtc_mmss(xtime.tv_sec) == 0)
-      last_rtc_update = xtime.tv_sec;
-    else
-      last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-
-
-  /* use hard disk LED as a heartbeat instead -- much more useful
-     -- Cort */
-  switch(timeints)
-  {
-    /* act like an actual heart beat -- ie thump-thump-pause... */
-    case 0:
-    case 20:
-      hard_disk_LED(1);
-      break;
-    case 7:
-    case 27:
-      hard_disk_LED(0);
-      break;
-    case 100:
-      timeints = -1;
-      break;
-  }
-  timeints++;
-}
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
-       unsigned int day, unsigned int hour,
-       unsigned int min, unsigned int sec)
-{
-       if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
-               mon += 12;      /* Puts Feb last since it has leap day */
-               year -= 1;
-       }
-       return (((
-           (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
-             year*365 - 719499
-           )*24 + hour /* now have hours */
-          )*60 + min /* now have minutes */
-         )*60 + sec; /* finally seconds */
-}
-
-unsigned long get_cmos_time(void)
-{
-  unsigned int year, mon, day, hour, min, sec;
-  int i;
-  
-  if (_Processor == _PROC_IBM)
-  {
-    do { /* Isn't this overkill ? UIP above should guarantee consistency */
-      sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
-      min = CMOS_MCRTC_READ(MCRTC_MINUTES);
-      hour = CMOS_MCRTC_READ(MCRTC_HOURS);
-      day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
-      mon = CMOS_MCRTC_READ(MCRTC_MONTH);
-      year = CMOS_MCRTC_READ(MCRTC_YEAR);
-    } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
-    BCD_TO_BIN(sec);
-    BCD_TO_BIN(min);
-    BCD_TO_BIN(hour);
-    BCD_TO_BIN(day);
-    BCD_TO_BIN(mon);
-    BCD_TO_BIN(year);
-  } else
-    if (_Processor == _PROC_Be)
-      {
-       do { /* Isn't this overkill ? UIP above should guarantee consistency */
-         sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
-         min = CMOS_MCRTC_READ(MCRTC_MINUTES);
-         hour = CMOS_MCRTC_READ(MCRTC_HOURS);
-         day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
-         mon = CMOS_MCRTC_READ(MCRTC_MONTH);
-         year = CMOS_MCRTC_READ(MCRTC_YEAR);
-       } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
-      } else
-       { /* Motorola PowerStack etc. */
-         do { /* Isn't this overkill ? UIP above should guarantee consistency */
-           sec = CMOS_READ(RTC_SECONDS);
-           min = CMOS_READ(RTC_MINUTES);
-           hour = CMOS_READ(RTC_HOURS);
-           day = CMOS_READ(RTC_DAY_OF_MONTH);
-           mon = CMOS_READ(RTC_MONTH);
-           year = CMOS_READ(RTC_YEAR);
-         } while (sec != CMOS_READ(RTC_SECONDS));
-         BCD_TO_BIN(sec);
-         BCD_TO_BIN(min);
-         BCD_TO_BIN(hour);
-         BCD_TO_BIN(day);
-         BCD_TO_BIN(mon);
-         BCD_TO_BIN(year);
-       }
-#if 0  
-printk("CMOS TOD - M/D/Y H:M:S = %d/%d/%d %d:%02d:%02d\n", mon, day, year, hour, min, sec);
-#endif
-       if ((year += 1900) < 1970)
-               year += 100;
-       return mktime(year, mon, day, hour, min, sec);
-}
-
-void time_init(void)
-{
-  void (*irq_handler)(int, struct pt_regs *);
-  xtime.tv_sec = get_cmos_time();
-  xtime.tv_usec = 0;
-  
-  /* If we have the CPU hardware time counters, use them */
-  irq_handler = timer_interrupt;
-  if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
-    panic("Could not allocate timer IRQ!");
-}
-
index a637e0acbd229f9681f70db70de648c1488804f6..84ce1c5ca39affd5b0e1d975393f41620c9b2953 100644 (file)
 #include <linux/malloc.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
 
 #include <asm/pgtable.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
-#include <asm/ppc_machine.h>
-
 /*
  * Trap & Exception support
  */
@@ -40,122 +40,98 @@ trap_init(void)
 void
 _exception(int signr, struct pt_regs *regs)
 {
-  /*   dump_regs(regs);*/
-  force_sig(signr, current);
-  if (!user_mode(regs))
-    {
-      printk("Failure in kernel at PC: %x, MSR: %x\n", regs->nip, regs->msr);
-      while (1) ;
-    }
+       if (!user_mode(regs))
+       {
+               show_regs(regs);
+               print_backtrace(regs->gpr[1]);
+               panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+       }
+       force_sig(signr, current);
 }
 
 MachineCheckException(struct pt_regs *regs)
 {
-  printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);
-  _exception(SIGSEGV, regs);   
-}
-
-ProgramCheckException(struct pt_regs *regs)
-{
-#if 0
-  printk("Program check at PC: %x[%x], SR: %x\n",
-        regs->nip, va_to_phys(regs->nip), regs->msr);
-  #endif
-  if (current->flags & PF_PTRACED)
-  {
-    _exception(SIGTRAP, regs);
-  } else
-  {
-    _exception(SIGILL, regs);
-  }
+       if ( !user_mode(regs) )
+       {
+               printk("Machine check in kernel mode.\n");
+               printk("Caused by (from msr): ");
+               printk("regs %08x ",regs);
+               switch( regs->msr & 0x0000F000)
+               {
+               case (1<<12) :
+                       printk("Machine check signal - probably due to mm fault\n"
+                               "with mmu off\n");
+               break;
+               case (1<<13) :
+                       printk("Transfer error ack signal\n");
+               break;
+               case (1<<14) :
+                       printk("Data parity signal\n");
+               break;
+               case (1<<15) :
+                       printk("Address parity signal\n");
+               break;
+               default:
+                       printk("Unknown values in msr\n");
+               }
+               show_regs(regs);
+               print_backtrace(regs->gpr[1]);
+               panic("");
+       }
+       _exception(SIGSEGV, regs);      
 }
 
-SingleStepException(struct pt_regs *regs)
+void
+UnknownException(struct pt_regs *regs)
 {
-       regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+       printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
        _exception(SIGTRAP, regs);      
 }
 
-FloatingPointCheckException(struct pt_regs *regs)
+void
+InstructionBreakpoint(struct pt_regs *regs)
 {
-  /* if fpu already on -- then exception was generated by an error */
-  if ( (unsigned long)(regs->msr) & (unsigned long)MSR_FP )
-  {
-    _exception(SIGFPE, regs);
-    return 0;
-  }
-
-#if 0
-  printk("fpu off -- turning on: %s pc %x fpscr %x msr %x ksp %x r1 %x\n",
-        current->comm,regs->nip,regs->fpcsr,regs->msr,regs,regs->gpr[1]);
+#ifdef CONFIG_XMON
+       if (xmon_iabr_match(regs))
+               return;
 #endif
-
-  /* if the fpu is off then turn it on and return */
-  regs->msr |= MSR_FP;
-  current->tss.fp_used++;
-  /* tells return_from_int to restore fp regs since fp was turned on
-     see head.S -- Cort */  
-  return MSR_FP;               
+       _exception(SIGTRAP, regs);
 }
 
-AlignmentException(struct pt_regs *regs)
+void
+RunModeException(struct pt_regs *regs)
 {
-/*     printk("Alignment error at PC: %x, SR: %x\n", regs->nip, regs->msr);
-       dump_regs(regs);
-       printk("Alignment error at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
-       _exception(SIGBUS, regs);       
+       _exception(SIGTRAP, regs);      
 }
 
+ProgramCheckException(struct pt_regs *regs)
+{
+       if (current->flags & PF_PTRACED)
+               _exception(SIGTRAP, regs);
+       else
+               _exception(SIGILL, regs);
+}
 
-/* see CHECK_STACK macro in head.S for argument definitions */
-bad_stack(unsigned int r3, unsigned int r4, unsigned int r5, unsigned int r6)
+SingleStepException(struct pt_regs *regs)
 {
-  /* r6 (was r1) kernel stack pointer */
-  /* r5 (was r2) kernel stack page */
-  /* r4 kernel stack magic */
-  /* r3 stack magic or ksp masked to page boundary */
-  printk("bad_stack(): Kernel stack bad.\n");
-  printk("ksp %x kpage %x stack magic %x r3 %x\n",
-        r6,r5,r4,r3);
-  printk("current: %s/%d\n",
-        current->comm,current->pid);
-  while(1);
+       regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+       _exception(SIGTRAP, regs);      
 }
 
-dump_regs(struct pt_regs *regs)
+AlignmentException(struct pt_regs *regs)
 {
-       int i;
-       printk("NIP: %08X, MSR: %08X, XER: %08X, LR: %08X, FRAME: %08X\n", regs->nip, regs->msr, regs->xer, regs->link, regs);
-#if 0  
-       printk("HASH = %08X/%08X, MISS = %08X/%08X, CMP = %08X/%08X\n", regs->hash1, regs->hash2, regs->imiss, regs->dmiss, regs->icmp, regs->dcmp);
-#endif 
-       printk("TASK = %x[%d] '%s'\n", current, current->pid, current->comm);
-       for (i = 0;  i < 32;  i++)
-       {
-               if ((i % 8) == 0)
-               {
-                       printk("GPR%02d: ", i);
-               }
-               printk("%08X ", regs->gpr[i]);
-               if ((i % 8) == 7)
-               {
-                       printk("\n");
-               }
-       }
-#if 0  
-       if (regs->nip >= 0x1000)
-               dump_buf(regs->nip-32, 64);
-       dump_buf((regs->nip&0x0FFFFFFF)|KERNELBASE, 32);
-#endif
+       _exception(SIGBUS, regs);       
 }
 
 trace_syscall(struct pt_regs *regs)
 {
        static int count;
-       printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n", current, current->pid, regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
+       printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+              current, current->pid, regs->nip, regs->link, regs->gpr[0],
+              regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
        if (++count == 20)
        {
                count = 0;
        }
 }
-
diff --git a/arch/ppc/kernel/usercpy.c b/arch/ppc/kernel/usercpy.c
deleted file mode 100644 (file)
index 7ef0f22..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#include <linux/types.h>
-#include <asm/string.h>
-#include <asm/errno.h>
-#include <linux/sched.h>
-
-/*
- * bad data accesses from these functions should be handled specially 
- * since they are to user areas and may or may not be valid.
- * on error -EFAULT should be returned.  -- Cort
- */
-int __copy_tofrom_user_failure(void)
-{
-  current->tss.excount = 0;
-  return -EFAULT;
-}
-
-int __copy_tofrom_user(unsigned long to, unsigned long from, int size)
-{
-  /* setup exception handling stuff */
-  current->tss.excount++;
-  current->tss.expc = (unsigned long )__copy_tofrom_user_failure;
-  
-  if (memcpy( (void *)to, (void *)from, (size_t) size) == -EFAULT )
-  {
-    /* take down exception handler stuff */
-    current->tss.excount = 0;
-    return -EFAULT;
-  }
-  current->tss.excount = 0;
-  return 0; /* successful return */
-}
-
-/* Just like strncpy except in the return value:
- *
- * -EFAULT       if an exception occurs before the terminator is copied.
- * N             if the buffer filled.
- *
- * Otherwise the length of the string is returned.
- */
-asmlinkage int __strncpy_from_user_failure(void)
-{
-  current->tss.excount = 0;
-  return -EFAULT;
-}
-
-int __strncpy_from_user(unsigned long dest, unsigned long src, int count)
-{
-  int i = 0;
-  /* setup exception handling stuff */
-  current->tss.excount++;
-  current->tss.expc = (unsigned long )__strncpy_from_user_failure;
-  
-  while ( i != count )
-  {
-    *(char *)(dest+i) = *(char *)(src+i);
-    if ( *(char *)(src+i) == 0 )
-    {
-      return i;
-    }
-    i++;
-  }
-  *(char *)(dest+i) = (char)0;
-  /* take down exception handler stuff */
-  current->tss.excount = 0;
-  return i;
-}
-
-int __clear_user_failure(void)
-{
-  current->tss.excount = 0;
-  return -EFAULT;
-}
-int __clear_user(unsigned long addr, int size)
-{
-  /* setup exception handling stuff */
-  current->tss.excount++;
-  current->tss.expc = (unsigned long )__clear_user_failure;
-
-  if ((int)memset((void *)addr,(int)0, (__kernel_size_t)size) == -EFAULT )
-    {
-      /* take down exception handler stuff */
-      current->tss.excount = 0;
-      return -EFAULT;
-    }
-  /* take down exception handler stuff */
-  current->tss.excount = 0;
-  return size;
-}
-
-/*
- * Return the length of the string including the NUL terminator
- * (strlen+1) or zero if an error occured.
- */
-size_t strlen_user_failure(void)
-{
-  current->tss.excount = 0;
-  return -EFAULT;
-}
-size_t strlen_user(char * s)
-{
-  size_t i;
-  /* setup exception handling stuff */
-  current->tss.excount++;
-  current->tss.expc = (unsigned long )strlen_user_failure;
-  
-  i = strlen(s)+1;
-  
-  if ( i == -EFAULT)
-    return -EFAULT;
-  
-  /* take down exception handler stuff */
-  current->tss.excount = 0;
-
-  return(i);
-}
-
index 319292840c046b9a03ed67ad16abaf020a05bdd0..ab5b070db7b3dface943f05a130c2a478182f293 100644 (file)
@@ -31,12 +31,16 @@ SECTIONS
   .text      :
   {
     *(.text)
-    *(.rodata)
-    *(.rodata1)
+    *(.fixup)
     *(.got1)
   }
   _etext = .;
   PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
   .dtors     : { *(.dtors)   }
@@ -45,31 +49,33 @@ SECTIONS
   .data    :
   {
     *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
     CONSTRUCTORS
   }
-  .data1   : { *(.data1) }
-  .got           : { *(.got.plt) *(.got) }
-  .dynamic       : { *(.dynamic) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
   _edata  =  .;
+/*
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+*/
+  __bss_start = .;             /* BSS */
   PROVIDE (edata = .);
   __bss_start = .;
-  .sbss      : { *(.sbss) *(.scommon) }
   .bss       :
   {
+   *(.sbss) *(.scommon)
    *(.dynbss)
    *(.bss)
    *(COMMON)
   }
   _end = . ;
   PROVIDE (end = .);
-  /* These are needed for ELF backends which have not yet been
-     converted to the new style linker.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  /* These must appear regardless of  .  */
 }
 
index baace08625d5bb53c9ad2115aee89fae732947b6..68b33f047a745652ce4b0b0fbb94a5153d3e4f35 100644 (file)
@@ -1,12 +1,38 @@
-#
-# Makefile for i386-specific library files..
-#
+.c.s:
+       $(CC) $(CFLAGS) -S $<
+.s.o:
+       $(AS) $(ASFLAGS) -o $*.o $<
+.c.o:
+       $(CC) $(CFLAGS) -c $<
+.S.s:
+       $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+.S.o:
+       $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+       $(AS) $(ASFLAGS) -o $*.o $*.s
+       rm $*.s
+
+HOST_CC = gcc
 
 L_TARGET = lib.o
-L_OBJS  = checksum.o cksum_support.o
-CC = gcc -I$(TOPDIR)/include
+L_OBJS  = checksum.o cksum_support.o string.o
 
 ${L_TARGET}: $(L_OBJS)
        $(LD) -r -o ${L_TARGET} $(L_OBJS)
 
+
 fastdep:
+       $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+       $(CPP) -M *.S *.c > .depend
+
+modules: 
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S
new file mode 100644 (file)
index 0000000..9ff7a05
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "../kernel/ppc_asm.tmpl"
+#include <asm/errno.h>
+
+       .globl  strcpy
+strcpy:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r5)
+       bne     1b
+       blr
+
+       .globl  strncpy
+strncpy:
+       cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r6,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r6)
+       bdnzf   2,1b            /* dec ctr, branch if ctr != 0 && !cr0.eq */
+       blr
+
+       .globl  strcat
+strcat:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r0,1(r5)
+       cmpwi   0,r0,0
+       bne     1b
+       addi    r5,r5,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r5)
+       bne     1b
+       blr
+
+       .globl  strcmp
+strcmp:
+       addi    r5,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r3,1(r5)
+       cmpwi   1,r3,0
+       lbzu    r0,1(r4)
+       subf.   r3,r0,r3
+       beqlr   1
+       beq     1b
+       blr
+
+       .globl  strlen
+strlen:
+       addi    r4,r3,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       bne     1b
+       subf    r3,r3,r4
+       blr
+
+       .globl  memset
+memset:
+       rlwimi  r4,r4,8,16,23
+       rlwimi  r4,r4,16,0,15
+       addi    r6,r3,-4
+       cmplwi  0,r5,4
+       blt     7f
+       stwu    r4,4(r6)
+       beqlr
+       andi.   r0,r6,3
+       add     r5,r0,r5
+       subf    r6,r0,r6
+       rlwinm  r0,r5,32-2,2,31
+       mtctr   r0
+       bdz     6f
+1:     stwu    r4,4(r6)
+       bdnz    1b
+6:     andi.   r5,r5,3
+7:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r6,r6,3
+8:     stbu    r4,1(r6)
+       bdnz    8b
+       blr
+       .globl  bcopy
+bcopy:
+       mr      r6,r3
+       mr      r3,r4
+       mr      r4,r6
+       b       memcpy
+
+       .globl  memmove
+memmove:
+       cmplw   0,r3,r4
+       bgt     backwards_memcpy
+       /* fall through */
+
+       .globl  memcpy
+memcpy:
+       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
+       addi    r6,r3,-4
+       addi    r4,r4,-4
+       beq     2f                      /* if less than 8 bytes to do */
+       andi.   r0,r6,3                 /* get dest word aligned */
+       mtctr   r7
+       bne     5f
+1:     lwz     r7,4(r4)
+       lwzu    r8,8(r4)
+       stw     r7,4(r6)
+       stwu    r8,8(r6)
+       bdnz    1b
+       andi.   r5,r5,7
+2:     cmplwi  0,r5,4
+       blt     3f
+       lwzu    r0,4(r4)
+       addi    r5,r5,-4
+       stwu    r0,4(r6)
+3:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r4,r4,3
+       addi    r6,r6,3
+4:     lbzu    r0,1(r4)
+       stbu    r0,1(r6)
+       bdnz    4b
+       blr
+5:     subfic  r0,r0,4
+       mtctr   r0
+6:     lbz     r7,4(r4)
+       addi    r4,r4,1
+       stb     r7,4(r6)
+       addi    r6,r6,1
+       bdnz    6b
+       subf    r5,r0,r5
+       rlwinm. r7,r5,32-3,3,31
+       beq     2b
+       mtctr   r7
+       b       1b
+
+       .globl  backwards_memcpy
+backwards_memcpy:
+       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
+       add     r6,r3,r5
+       add     r4,r4,r5
+       beq     2f
+       andi.   r0,r6,3
+       mtctr   r7
+       bne     5f
+1:     lwz     r7,-4(r4)
+       lwzu    r8,-8(r4)
+       stw     r7,-4(r6)
+       stwu    r8,-8(r6)
+       bdnz    1b
+       andi.   r5,r5,7
+2:     cmplwi  0,r5,4
+       blt     3f
+       lwzu    r0,-4(r4)
+       subi    r5,r5,4
+       stwu    r0,-4(r6)
+3:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+4:     lbzu    r0,-1(r4)
+       stbu    r0,-1(r6)
+       bdnz    4b
+       blr
+5:     mtctr   r0
+6:     lbzu    r7,-1(r4)
+       stbu    r7,-1(r6)
+       bdnz    6b
+       subf    r5,r0,r5
+       rlwinm. r7,r5,32-3,3,31
+       beq     2b
+       mtctr   r7
+       b       1b
+       
+       .globl  memcmp
+memcmp:
+       cmpwi   0,r5,0
+       blelr
+       mtctr   r5
+       addi    r6,r3,-1
+       addi    r4,r4,-1
+1:     lbzu    r3,1(r6)
+       lbzu    r0,1(r4)
+       subf.   r3,r0,r3
+       bdnzt   2,1b
+       blr
+       .globl  __copy_tofrom_user
+__copy_tofrom_user:
+       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
+       addi    r6,r3,-4
+       addi    r4,r4,-4
+       li      r3,0                    /* success return value */
+       beq     2f                      /* if less than 8 bytes to do */
+       andi.   r0,r6,3                 /* get dest word aligned */
+       mtctr   r7
+       bne     5f
+1:     lwz     r7,4(r4)
+11:    lwzu    r8,8(r4)
+12:    stw     r7,4(r6)
+13:    stwu    r8,8(r6)
+       bdnz    1b
+       andi.   r5,r5,7
+2:     cmplwi  0,r5,4
+       blt     3f
+14:    lwzu    r0,4(r4)
+       addi    r5,r5,-4
+15:    stwu    r0,4(r6)
+3:     cmpwi   0,r5,0
+       beqlr
+       mtctr   r5
+       addi    r4,r4,3
+       addi    r6,r6,3
+4:     lbzu    r0,1(r4)
+16:    stbu    r0,1(r6)
+       bdnz    4b
+       blr
+5:     subfic  r0,r0,4
+       mtctr   r0
+6:     lbz     r7,4(r4)
+       addi    r4,r4,1
+17:    stb     r7,4(r6)
+       addi    r6,r6,1
+       bdnz    6b
+       subf    r5,r0,r5
+       rlwinm. r7,r5,32-3,3,31
+       beq     2b
+       mtctr   r7
+       b       1b
+99:    li      r3,-EFAULT
+       blr
+.section __ex_table,"a"
+       .align  2
+       .long   1b,99b
+       .long   11b,99b
+       .long   12b,99b
+       .long   13b,99b
+       .long   14b,99b
+       .long   15b,99b
+       .long   4b,99b
+       .long   16b,99b
+       .long   6b,99b
+       .long   17b,99b
+.text
+
+       .globl  __clear_user
+__clear_user:
+       addi    r6,r3,-4
+       li      r3,0
+       li      r5,0
+       cmplwi  0,r4,4
+       blt     7f
+11:    stwu    r5,4(r6)
+       beqlr
+       andi.   r0,r6,3
+       add     r4,r0,r4
+       subf    r6,r0,r6
+       rlwinm  r0,r4,32-2,2,31
+       mtctr   r0
+       bdz     6f
+1:     stwu    r5,4(r6)
+       bdnz    1b
+6:     andi.   r4,r4,3
+7:     cmpwi   0,r4,0
+       beqlr
+       mtctr   r4
+       addi    r6,r6,3
+8:     stbu    r5,1(r6)
+       bdnz    8b
+       blr
+99:    li      r3,-EFAULT
+       blr
+.section __ex_table,"a"
+       .align  2
+       .long   11b,99b
+       .long   1b,99b
+       .long   8b,99b
+.text
+
+       .globl  __strncpy_from_user
+__strncpy_from_user:
+       addi    r6,r3,-1
+       addi    r4,r4,-1
+       cmpwi   0,r5,0
+       beq     2f
+       mtctr   r5
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       stbu    r0,1(r6)
+       bdnzf   2,1b            /* dec ctr, branch if ctr != 0 && !cr0.eq */
+       beq     3f
+2:     addi    r6,r6,1
+3:     subf    r3,r3,r6
+       blr
+99:    li      r3,-EFAULT
+       blr
+.section __ex_table,"a"
+       .align  2
+       .long   1b,99b
+.text
+
+       .globl  strlen_user
+strlen_user:
+       addi    r4,r3,-1
+1:     lbzu    r0,1(r4)
+       cmpwi   0,r0,0
+       bne     1b
+       subf    r3,r3,r4
+       addi    r3,r3,1
+       blr
+99:    li      r3,0
+       blr
+.section __ex_table,"a"
+       .align  2
+       .long   1b,99b
diff --git a/arch/ppc/mkdiff b/arch/ppc/mkdiff
new file mode 100644 (file)
index 0000000..304eb94
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+N=`basename $PWD`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+echo Diff of: $N against $N.ORIG '->' $N-$date-ppc.patch 
+diff -uNr -X $N/arch/ppc/ignore $N.ORIG $N > dist/$N-$date-ppc.patch
diff --git a/arch/ppc/mkdist b/arch/ppc/mkdist
new file mode 100644 (file)
index 0000000..f915719
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+N=`basename $PWD`
+V=`echo $N | sed 's/linux-//'`
+date=`date +'%y%m%d'`
+mkdir -p ../dist
+mv zImage ../dist/zImage-$V-$date
+mv System.map ../dist/System.map-$V-$date
+
diff --git a/arch/ppc/mktar b/arch/ppc/mktar
new file mode 100644 (file)
index 0000000..965eefb
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+N=`basename $PWD`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+tar -zcf dist/ppc$N-$date.tar.gz -X $N/arch/ppc/ignore $N
index ac6ef02137233cd101e491450dc428e1eb1add8c..13aeab6cabe6ceda3ed5be95bc1b803e2a709634 100644 (file)
@@ -14,7 +14,7 @@
 .c.s:
        $(CC) $(CFLAGS) -S $<
 
-OBJS   = fault.o init.o
+OBJS   = fault.o init.o extable.o
 
 mm.o: $(OBJS)
        $(LD) -r -o mm.o $(OBJS)
@@ -22,9 +22,9 @@ mm.o: $(OBJS)
 modules:
 
 dep:
-       $(CPP) -M *.c > .depend
-       
+
 fastdep:
+       $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
 
 #
 # include a dependency file if one exists
diff --git a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c
new file mode 100644 (file)
index 0000000..696a9f1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * linux/arch/ppc/mm/extable.c
+ *
+ * from linux/arch/i386/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+                const struct exception_table_entry *last,
+                unsigned long value)
+{
+        while (first <= last) {
+               const struct exception_table_entry *mid;
+               long diff;
+
+               mid = (last - first) / 2 + first;
+               diff = mid->insn - value;
+                if (diff == 0)
+                        return mid->fixup;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+        return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+       unsigned long ret;
+
+#if 1 /*ndef CONFIG_MODULES*/
+       /* There is only the kernel to search.  */
+       ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+       if (ret) return ret;
+#else
+       /* The kernel is the last "module" -- no need to treat it special.  */
+       struct module *mp;
+       for (mp = module_list; mp != NULL; mp = mp->next) {
+               if (mp->ex_table_start == NULL)
+                       continue;
+               ret = search_one_table(mp->ex_table_start,
+                                      mp->ex_table_end - 1, addr);
+               if (ret) return ret;
+       }
+#endif
+
+       return 0;
+}
index 7104d6bbbb394075e8fdb86c2d3ed920b381fe8a..fea722780310f22fc623861f3a418ed889570b93 100644 (file)
@@ -1,9 +1,14 @@
 /*
- *  ARCH/ppc/mm/fault.c
+ *  arch/ppc/mm/fault.c
  *
  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  *  Ported to PPC by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *  Modified by Cort Dougan and Paul Mackerras.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
  */
 
 #include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/interrupt.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/mmu_context.h>
 
-extern void die_if_kernel(char *, struct pt_regs *, long);
-extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void new_page_fault(unsigned long address, unsigned long code, unsigned long text,
-                   struct pt_regs *regs);
-
+#ifdef CONFIG_PMAC
+extern void (*xmon_fault_handler)(void);
+#endif
 
-#undef SHOW_FAULTS
-#undef NOISY_INSTRFAULT
-#undef NOISY_DATAFAULT
+/* the linux norm for the function name is show_regs() so
+   make it call dump_regs() on the mac -- Cort */
+#ifdef CONFIG_PMAC 
+#define show_regs dump_regs
+#endif
 
-unsigned int probingmem = 0;
-#define NEWMM 1
+extern void die_if_kernel(char *, struct pt_regs *, long);
+void bad_page_fault(struct pt_regs *, unsigned long);
+void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
+void print_pte(struct _PTE);
 
-void new_page_fault(unsigned long address, unsigned long ppc_code,
-                   unsigned long text, struct pt_regs *regs)
+void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)     
 {
-  struct vm_area_struct * vma;
-  struct mm_struct *mm = current->mm;
-
-  int intel_code = 0;
-  pgd_t *dir;
-  pmd_t *pmd;
-  pte_t *pte;
-  
-  /*
-   *   bit 0 == 0 means no page found, 1 means protection fault
-   *   bit 1 == 0 means read, 1 means write
-   *   bit 2 == 0 means kernel, 1 means user-mode
-   */
-  if (user_mode(regs)) intel_code |= 0x04;
-  if (!text && (ppc_code & 0x02000000)) intel_code |= 0x02;  /* Load/store */
-  if (!text && (ppc_code & 0x08000000))
-  {
-    intel_code |= 0x01;  /* prot viol */
-    goto do_page;
-  }
-  
-  dir = pgd_offset(mm, address & PAGE_MASK);
-  if (dir)
-  {
-    pmd = pmd_offset(dir, address & PAGE_MASK);
-    if (pmd && pmd_present(*pmd))
-    {
-      pte = pte_offset(pmd, address & PAGE_MASK);
-      if (pte && pte_present(*pte))
-      {
-       MMU_hash_page(&current->tss, address & PAGE_MASK, pte);
-       return;
-      }
-    }
-  }
-
+       struct task_struct *tsk = current;
+       extern unsigned _end[];
+       struct vm_area_struct * vma;
+       struct mm_struct *mm = current->mm;
+       pgd_t *dir;
+       pmd_t *pmd;
+       pte_t *pte;
+       
+       /*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
+              current->comm,current->pid,address,regs->nip,regs,error_code);*/
+#ifdef CONFIG_PMAC
+       if (xmon_fault_handler && regs->trap == 0x300) {
+               xmon_fault_handler();
+               return;
+       }
+#endif
+       if (in_interrupt()) {
+               static int complained;
+               if (complained < 20) {
+                       ++complained;
+                       printk("page fault in interrupt handler, addr=%lx\n",
+                              address);
+                       show_regs(regs);
+               }
+       }
+       if (current == NULL)
+               goto bad_area;
+       
 do_page:
-  down(&mm->mmap_sem);
-  vma = find_vma(current->mm, address);
-  if (!vma)
-    goto bad_area;
-  if (vma->vm_start <= address)
-    goto good_area;
-  if (!(vma->vm_flags & VM_GROWSDOWN))
-    goto bad_area;
-  if (expand_stack(vma, address))
-    goto bad_area;
+       down(&mm->mmap_sem);
+       vma = find_vma(tsk->mm, address);
+       if (!vma)
+               goto bad_area;
+       if (vma->vm_start <= address)
+               goto good_area;
+       if (!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+       if (expand_stack(vma, address))
+               goto bad_area;
   
 good_area:
-  /* a write */
-  if (intel_code & 2) {
-    if (!(vma->vm_flags & VM_WRITE))
-    {
-      goto bad_area;
-    }
-  /* a read */
-  } else {
-    /* protection fault */
-    if (intel_code & 1)
-    {
-      printk("prot fault\n");
-      goto bad_area;
-    }
-    if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-    {
-      printk("no read or exec\n");      
-      goto bad_area; 
-    }
-  }
-  handle_mm_fault(vma, address, intel_code & 2);
-  up(&mm->mmap_sem);  flush_page(address);  /* Flush & Invalidate cache - note: address is OK now */  
-  return;
+       if (error_code & 0xb5700000)
+               /* an error such as lwarx to I/O controller space,
+                  address matching DABR, eciwx, etc. */
+               goto bad_area;
+       
+       /* a write */
+       if (error_code & 0x02000000) {
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       /* a read */
+       } else {
+               /* protection fault */
+               if ( error_code & 0x08000000 )
+                       goto bad_area;
+               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto bad_area;
+       }
+       handle_mm_fault(current, vma, address, error_code & 0x02000000);
+        up(&mm->mmap_sem);
+       /*printk("do_page_fault() return %s/%d addr %x msr %x\n",
+             current->comm,current->pid,address,regs->msr);*/
+       /* not needed since flush_page_to_ram() works */
+#if 0
+       flush_page(address);
+#endif
+       return;
   
 bad_area:
-  up(&mm->mmap_sem);
+       up(&current->mm->mmap_sem);
+       bad_page_fault(regs, address);
+}
+
+
+void
+bad_page_fault(struct pt_regs *regs, unsigned long address)
+{
+       extern unsigned int probingmem;
+       struct task_struct *tsk = current;
+       unsigned long fixup;
+       
+       
+       /* Are we prepared to handle this fault?  */
+       if ((fixup = search_exception_table(regs->nip)) != 0) {
+               if ( user_mode(regs) )
+                       printk("Exception from user mode\n");
+#if 0    
+               printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
+#endif    
+               regs->nip = fixup;
+               return;
+       }
 
-  /* Did we have an exception handler installed? */
-  if(current->tss.excount != 0) {
-    if(user_mode(regs)) {
-      printk("Exception signalled from user mode!\n");
-    } else {
-#if 0      
-      printk("Exception from kernel mode. pc %x expc %x count %d\n",
-            regs->nip,current->tss.expc,current->tss.excount);
-#endif      
-      current->tss.excount = 0;
-      regs->gpr[3] = -EFAULT;
-      regs->nip = current->tss.expc;
-      return;
-    }
-  }
+       if ( user_mode(regs) )
+       {
+               force_sig(SIGSEGV, tsk);
+               return;
+       }
   
-  if (user_mode(regs))
-  {
-    force_sig(SIGSEGV, current);
-    return;
-  }
-  panic("KERNEL access of bad area PC %x address %x vm_flags %x\n",
-       regs->nip,address,vma->vm_flags);
+bad_kernel_access:
+       /* make sure it's not a bootup probe test */
+       if ( probingmem )
+       {
+               probingmem = 0;
+               return;
+       }
+       /* kernel has accessed a bad area */
+       show_regs(regs);
+       print_backtrace( regs->gpr[1] );
+#ifdef CONFIG_PMAC
+       xmon(regs);
+#endif
+       panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
+             regs->nip,address,tsk->comm,tsk->pid);
 }
 
-va_to_phys(unsigned long address)
+unsigned long va_to_phys(unsigned long address)
 {
        pgd_t *dir;
        pmd_t *pmd;
        pte_t *pte;
+       
        dir = pgd_offset(current->mm, address & PAGE_MASK);
        if (dir)
        {
@@ -165,8 +189,28 @@ va_to_phys(unsigned long address)
        return (0);
 }
 
-inline void
-update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t _pte)
+void print_pte(struct _PTE p)
 {
-   MMU_hash_page(&current->tss, address & PAGE_MASK, (pte *)&_pte);
+       printk(
+"%08x %08x vsid: %06x h: %01x api: %02x rpn: %05x rcwimg: %d%d%d%d%d%d pp: %02x\n",
+               *((unsigned long *)(&p)), *((long *)&p+1),
+               p.vsid, p.h, p.api, p.rpn,
+               p.r,p.c,p.w,p.i,p.m,p.g,p.pp);
+}
+
+/*
+ * Search the hw hash table for a mapping to the given physical
+ * address. -- Cort
+ */
+unsigned long htab_phys_to_va(unsigned long address)
+{
+       extern PTE *Hash, *Hash_end;
+       PTE *ptr;
+
+       for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
+       {
+               if ( ptr->rpn == (address>>12) )
+                       printk("phys %08X -> va ???\n",
+                              address);
+       }
 }
index ee2381dbac338efb59f1c9476812801c0900c8db..d469759963373e181432a47828411852c1cba8c6 100644 (file)
@@ -1,9 +1,21 @@
 /*
  *  arch/ppc/mm/init.c
  *
- *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *  Ported to PPC by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
  */
 
 #include <linux/config.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/stddef.h>
+#ifdef CONFIG_PMAC
+#include <asm/prom.h>
+#endif
+#include <asm/io.h>
+#include <asm/mmu_context.h>
 #include <asm/pgtable.h>
+#include <asm/mmu.h>
+#ifdef CONFIG_PREP
 #include <asm/residual.h>
+#endif
 
-extern pgd_t swapper_pg_dir[1024];
-extern unsigned long empty_zero_page[1024];
+int next_mmu_context;
+extern pgd_t swapper_pg_dir[];
+extern char _start[], _end[];
+extern char etext[], _stext[];
+/* References to section boundaries */
+extern char __init_begin, __init_end;
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
-void flush_hash_table(void);
+extern unsigned long *find_end_of_memory(void);
 
-#undef HASHSTATS
+#undef MAP_RAM_WITH_SEGREGS 1
 
-unsigned long _SDR1;           /* Hardware SDR1 image */
-PTE *Hash;
-int Hash_size, Hash_mask;
+#ifdef CONFIG_PMAC
+void *find_mem_piece(unsigned, unsigned);
+static void mapin_ram(void);
+static void inherit_prom_translations(void);
+#endif
+#ifdef CONFIG_PREP
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
+int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);     
+#endif
+
+static void hash_init(void);
+static void *MMU_get_page(void);
+void map_page(struct thread_struct *, unsigned long va,
+                    unsigned long pa, int flags);
+
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
 unsigned long *end_of_DRAM;
-int cache_is_copyback = 1;
-int kernel_pages_are_copyback = 1;
-/* Note: these need to be in 'data' so they live over the boot */
-unsigned char *BeBox_IO_page = 0;
-unsigned long isBeBox[2] = {0, 0};
+int mem_init_done;
 
+#ifdef CONFIG_PREP
 #ifdef HASHSTATS
-extern unsigned long *hashhits;
-#endif
-
+extern unsigned long evicts;
+#endif /* HASHSTATS */
+/*
+ * these are used to setup the initial page tables
+ * They can waste up to an entire page since the
+ * I'll fix this shortly -- Cort
+ */
+#define MAX_MMU_PAGES  16
+unsigned int probingmem = 0;
+unsigned int mmu_pages_count = 0;
+char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
+unsigned long _TotalMemory;
+#endif /* CONFIG_PREP */
 
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+unsigned long empty_bad_page_table;
 
 pte_t * __bad_pagetable(void)
 {
-       panic("__bad_pagetable");
+       memset((void *)empty_bad_page_table, 0, PAGE_SIZE);
+       return (pte_t *) empty_bad_page_table;
 }
 
+unsigned long empty_bad_page;
+
 pte_t __bad_page(void)
 {
-       panic("__bad_page");
+       memset((void *)empty_bad_page, 0, PAGE_SIZE);
+       return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
+}
+
+#ifdef CONFIG_PMAC
+#define MAX_MEM_REGIONS        32
+phandle memory_pkg;
+
+struct mem_pieces {
+       int n_regions;
+       struct reg_property regions[MAX_MEM_REGIONS];
+};
+
+struct mem_pieces phys_mem;
+struct mem_pieces phys_avail;
+struct mem_pieces prom_mem;
+
+static void get_mem_prop(char *, struct mem_pieces *);
+static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
+static void print_mem_pieces(struct mem_pieces *);
+
+unsigned long avail_start;
+int prom_trashed;
+
+/*
+ * Read in a property describing some pieces of memory.
+ */
+static void
+get_mem_prop(char *name, struct mem_pieces *mp)
+{
+       int s, i;
+
+       s = (int) call_prom("getprop", 4, 1, memory_pkg, name,
+                           mp->regions, sizeof(mp->regions));
+       if (s < sizeof(mp->regions[0])) {
+               printk("getprop /memory %s returned %d\n", name, s);
+               abort();
+       }
+       mp->n_regions = s / sizeof(mp->regions[0]);
+
+       /*
+        * Make sure the pieces are sorted.
+        */
+       for (i = 1; i < mp->n_regions; ++i) {
+               unsigned long a, s;
+               int j;
+
+               a = mp->regions[i].address;
+               s = mp->regions[i].size;
+               for (j = i - 1; j >= 0; --j) {
+                       if (a >= mp->regions[j].address)
+                               break;
+                       mp->regions[j+1] = mp->regions[j];
+               }
+               mp->regions[j+1].address = a;
+               mp->regions[j+1].size = s;
+       }
+}
+
+/*
+ * Remove some memory from an array of pieces
+ */
+static void
+remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size,
+                int must_exist)
+{
+       int i, j;
+       unsigned end, rs, re;
+       struct reg_property *rp;
+
+       end = start + size;
+       for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) {
+               if (end > rp->address && start < rp->address + rp->size)
+                       break;
+       }
+       if (i >= mp->n_regions) {
+               if (must_exist)
+                       printk("remove_mem_piece: [%x,%x) not in any region\n",
+                              start, end);
+               return;
+       }
+       for (; i < mp->n_regions && end > rp->address; ++i, ++rp) {
+               rs = rp->address;
+               re = rs + rp->size;
+               if (must_exist && (start < rs || end > re)) {
+                       printk("remove_mem_piece: bad overlap [%x,%x) with",
+                              start, end);
+                       print_mem_pieces(mp);
+                       must_exist = 0;
+               }
+               if (start > rs) {
+                       rp->size = start - rs;
+                       if (end < re) {
+                               /* need to split this entry */
+                               if (mp->n_regions >= MAX_MEM_REGIONS)
+                                       panic("eek... mem_pieces overflow");
+                               for (j = mp->n_regions; j > i + 1; --j)
+                                       mp->regions[j] = mp->regions[j-1];
+                               ++mp->n_regions;
+                               rp[1].address = end;
+                               rp[1].size = re - end;
+                       }
+               } else {
+                       if (end < re) {
+                               rp->address = end;
+                               rp->size = re - end;
+                       } else {
+                               /* need to delete this entry */
+                               for (j = i; j < mp->n_regions - 1; ++j)
+                                       mp->regions[j] = mp->regions[j+1];
+                               --mp->n_regions;
+                               --i;
+                               --rp;
+                       }
+               }
+       }
+}
+
+static void
+print_mem_pieces(struct mem_pieces *mp)
+{
+       int i;
+
+       for (i = 0; i < mp->n_regions; ++i)
+               printk(" [%x, %x)", mp->regions[i].address,
+                      mp->regions[i].address + mp->regions[i].size);
+       printk("\n");
+}
+
+void *
+find_mem_piece(unsigned size, unsigned align)
+{
+       int i;
+       unsigned a, e;
+       struct mem_pieces *mp = &phys_avail;
+
+       for (i = 0; i < mp->n_regions; ++i) {
+               a = mp->regions[i].address;
+               e = a + mp->regions[i].size;
+               a = (a + align - 1) & -align;
+               if (a + size <= e) {
+                       remove_mem_piece(mp, a, size, 1);
+                       return __va(a);
+               }
+       }
+       printk("Couldn't find %u bytes at %u alignment\n", size, align);
+       abort();
+       return NULL;
+}
+
+/*
+ * Collect information about RAM and which pieces are already in use.
+ * At this point, we have the first 8MB mapped with a BAT.
+ * Our text, data, bss use something over 1MB, starting at 0.
+ * Open Firmware may be using 1MB at the 4MB point.
+ */
+unsigned long *find_end_of_memory(void)
+{
+       unsigned long a, total;
+       unsigned long h, kstart, ksize;
+       extern char _stext[], _end[];
+       int i;
+
+       memory_pkg = call_prom("finddevice", 1, 1, "/memory");
+       if (memory_pkg == (void *) -1)
+               panic("can't find memory package");
+
+       /*
+        * Find out where physical memory is, and check that it
+        * starts at 0 and is contiguous.  It seems that RAM is
+        * always physically contiguous on Power Macintoshes,
+        * because MacOS can't cope if it isn't.
+        */
+       get_mem_prop("reg", &phys_mem);
+       if (phys_mem.n_regions == 0)
+               panic("No RAM??");
+       a = phys_mem.regions[0].address;
+       if (a != 0)
+               panic("RAM doesn't start at physical address 0");
+       total = phys_mem.regions[0].size;
+       for (i = 1; i < phys_mem.n_regions; ++i) {
+               a = phys_mem.regions[i].address;
+               if (a != total) {
+                       printk("RAM starting at 0x%lx is not contiguous\n", a);
+                       printk("Using RAM from 0 to 0x%lx\n", total-1);
+                       phys_mem.n_regions = i;
+                       break;
+               }
+               total += phys_mem.regions[i].size;
+       }
+
+       /* record which bits the prom is using */
+       get_mem_prop("available", &phys_avail);
+       prom_mem = phys_mem;
+       for (i = 0; i < phys_avail.n_regions; ++i)
+               remove_mem_piece(&prom_mem, phys_avail.regions[i].address,
+                                phys_avail.regions[i].size, 1);
+
+       /*
+        * phys_avail records memory we can use now.
+        * prom_mem records memory allocated by the prom that we
+        * don't want to use now, but we'll reclaim later.
+        * Make sure the kernel text/data/bss is in neither.
+        */
+       kstart = __pa(_stext);  /* should be 0 */
+       ksize = PAGE_ALIGN(_end - _stext);
+       remove_mem_piece(&phys_avail, kstart, ksize, 0);
+       remove_mem_piece(&prom_mem, kstart, ksize, 0);
+
+       /*
+        * Allow 64k of hash table for every 16MB of memory,
+        * up to a maximum of 2MB.
+        */
+       for (h = 64<<10; h < total / 256 && h < 2<<20; h *= 2)
+               ;
+       Hash_size = h;
+       Hash_mask = (h >> 6) - 1;
+
+       /* Find some memory for the hash table. */
+       Hash = find_mem_piece(Hash_size, Hash_size);
+       printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+              total >> 20, Hash_size >> 10, Hash);
+
+       return __va(total);
+}
+
+/*
+ * Find some memory for setup_arch to return.
+ * We use the last chunk of available memory as the area
+ * that setup_arch returns, making sure that there are at
+ * least 32 pages unused before this for MMU_get_page to use.
+ */
+unsigned long find_available_memory(void)
+{
+       int i;
+       unsigned long a, free;
+       unsigned long start, end;
+
+       free = 0;
+       for (i = 0; i < phys_avail.n_regions - 1; ++i) {
+               start = phys_avail.regions[i].address;
+               end = start + phys_avail.regions[i].size;
+               free += (end & PAGE_MASK) - PAGE_ALIGN(start);
+       }
+       a = PAGE_ALIGN(phys_avail.regions[i].address);
+       if (free < 32 * PAGE_SIZE)
+               a += 32 * PAGE_SIZE - free;
+       avail_start = (unsigned long) __va(a);
+       return avail_start;
 }
+#endif /* CONFIG_PMAC */
 
 void show_mem(void)
 {
+       int i,free = 0,total = 0,reserved = 0;
+       int shared = 0;
        struct task_struct *p;
-       unsigned long i,free = 0,total = 0,reserved = 0;
-       unsigned long shared = 0;
-       PTE *ptr;
-       unsigned long full = 0, overflow = 0;
-       unsigned int ti;
 
        printk("Mem-info:\n");
        show_free_areas();
        printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-       i = MAP_NR(high_memory);
+       i = max_mapnr;
        while (i-- > 0) {
                total++;
                if (PageReserved(mem_map+i))
@@ -78,105 +387,185 @@ void show_mem(void)
                else
                        shared += atomic_read(&mem_map[i].count) - 1;
        }
-       printk("%lu pages of RAM\n",total);
-       printk("%lu free pages\n",free);
-       printk("%lu reserved pages\n",reserved);
-       printk("%lu pages shared\n",shared);
+       printk("%d pages of RAM\n",total);
+       printk("%d free pages\n",free);
+       printk("%d reserved pages\n",reserved);
+       printk("%d pages shared\n",shared);
        show_buffers();
 #ifdef CONFIG_NET
        show_net_buffers();
 #endif
-#ifdef HASHSTATS
-       printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
-       for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) {
-               if ( hashhits[i] >= 20 )
-                       printk("[%lu] \t %lu\n", i,hashhits[i]);
-       }
-#endif
-  
-       for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) {
-               if (ptr->v) {
-                       full++;
-                       if (ptr->h == 1)
-                               overflow++;
-               }
-       }
-       printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
-              Hash_size>>10,   (Hash_size/(sizeof(PTE)*8)) >> 10,
-              full,Hash_size/sizeof(PTE),
-              (full*100)/(Hash_size/sizeof(PTE)),
-              overflow);
-       printk(" Task  context    vsid0\n");
-       read_lock(&tasklist_lock);
-       for_each_task(p) {
-               printk("%5d %8x %8x\n",
-                      p->pid,p->mm->context,
-                      ((SEGREG *)p->tss.segs)[0].vsid);
+       printk("%-8s %3s %3s %8s %8s %8s %9s %8s\n", "Process", "Pid", "Cnt",
+              "Ctx", "Ctx<<4", "Last Sys", "pc", "task");
+       for_each_task(p)
+       {       
+               printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+                      p->comm,p->pid,
+                      p->mm->count,p->mm->context,
+                      p->mm->context<<4, p->tss.last_syscall,
+                      user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
+                      p);
+               if ( p == current )
+                       printk(" current");
+               printk("\n");
        }
-       read_unlock(&tasklist_lock);
 }
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
 
+/*
+ * paging_init() sets up the page tables - in fact we've already done this.
+ */
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 {
-       return free_area_init(start_mem, end_mem);
+       /*
+        * Grab some memory for bad_page and bad_pagetable to use.
+        */
+       empty_bad_page = start_mem;
+       empty_bad_page_table = start_mem + PAGE_SIZE;
+       start_mem += 2 * PAGE_SIZE;
+
+       /* note: free_area_init uses its second argument
+          to size the mem_map array. */
+       start_mem = free_area_init(start_mem, end_mem);
+       return start_mem;
 }
 
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
-  int codepages = 0;
-  int datapages = 0;
-  unsigned long tmp;
-  extern int etext;
+       unsigned long addr;
+#ifdef CONFIG_PMAC
+       int i;
+       unsigned long lim;
+#endif
+       int codepages = 0;
+       int datapages = 0;
+       int initpages = 0;
+
+       end_mem &= PAGE_MASK;
+       high_memory = (void *) end_mem;
+       num_physpages = max_mapnr = MAP_NR(high_memory);
        
-  end_mem &= PAGE_MASK;
-  high_memory = (void *)end_mem;
-  max_mapnr = MAP_NR(end_mem);
-  /* clear the zero-page */
-  memset(empty_zero_page, 0, PAGE_SIZE);
+       /* clear the zero-page */
+       memset(empty_zero_page, 0, PAGE_SIZE);
        
        /* mark usable pages in the mem_map[] */
-  start_mem = PAGE_ALIGN(start_mem);
+       start_mem = PAGE_ALIGN(start_mem);
+       
+#ifdef CONFIG_PMAC
+       remove_mem_piece(&phys_avail, __pa(avail_start),
+                        start_mem - avail_start, 1);
+
+       for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
+               set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+
+       for (i = 0; i < phys_avail.n_regions; ++i) {
+               a = (unsigned long) __va(phys_avail.regions[i].address);
+               lim = a + phys_avail.regions[i].size;
+               a = PAGE_ALIGN(a);
+               for (; a < lim; a += PAGE_SIZE) {
+                       clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+                       mem_map[MAP_NR(a)].count = 1;
+                       free_page(a);
+               }
+       }
+       phys_avail.n_regions = 0;
 
-  for (tmp = KERNELBASE ; tmp < (long)high_memory ; tmp += PAGE_SIZE)
-    {
-      if (tmp < start_mem)
+       /* free the prom's memory */
+       for (i = 0; i < prom_mem.n_regions; ++i) {
+               a = (unsigned long) __va(prom_mem.regions[i].address);
+               lim = a + prom_mem.regions[i].size;
+               a = PAGE_ALIGN(a);
+               for (; a < lim; a += PAGE_SIZE) {
+                       clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+                       mem_map[MAP_NR(a)].count = 1;
+                       free_page(a);
+               }
+       }
+       prom_trashed = 1;
+#endif /* CONFIG_PMAC */
+
+#ifdef CONFIG_PREP
+       /* mark mem used by kernel as reserved, mark other unreserved */
+       for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
        {
-         set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
-         if (tmp < (unsigned long) &etext)
-           {
-             codepages++;
-           } else
-             {
-               datapages++;
-             }
-         continue;
-       }
-      clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
-      atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
-      free_page(tmp);
-    }
-  tmp = nr_free_pages << PAGE_SHIFT;
-  printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
-        tmp >> 10,
-        ((int)high_memory - (int)KERNELBASE) >> 10,
-        codepages << (PAGE_SHIFT-10),
-        datapages << (PAGE_SHIFT-10));
-  /*   invalidate();*/
-  return;
+               /* skip hash table gap */
+               if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+                       continue;
+               if ( addr < (ulong) /*Hash_end*/ start_mem )
+                       set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+               else
+                       clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+       }
+
+       for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
+               if(PageReserved(mem_map + MAP_NR(addr))) {
+                       if (addr < (ulong) etext)
+                               codepages++;
+                       /*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+                                initpages++;*/
+                        else if (addr < (ulong) start_mem)
+                               datapages++;
+                       continue;
+               }
+               atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+#ifdef CONFIG_BLK_DEV_INITRD
+               if (!initrd_start ||
+                   (addr < initrd_start || addr >= initrd_end))
+#endif /* CONFIG_BLK_DEV_INITRD */
+                       free_page(addr);
+       }
+       
+#endif /* CONFIG_PREP */
+        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+              (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+              codepages << (PAGE_SHIFT-10),
+              datapages << (PAGE_SHIFT-10), 
+              initpages << (PAGE_SHIFT-10),
+              PAGE_OFFSET, end_mem);
+       mem_init_done = 1;
 }
 
+/*
+ * this should reclaim gap between _end[] and hash table
+ * as well as unused mmu_pages[] on prep systems.
+ * When I get around to it, I'll put initialization functions
+ * (called only at boot) in their own .section and free that -- Cort
+ */
 void free_initmem(void)
 {
-       /* To be written */
+       unsigned long addr;
+       unsigned long a;
+       unsigned long num_freed_pages = 0;
+
+       /* free unused mmu_pages[] */
+       a = PAGE_ALIGN( (unsigned long) mmu_pages) + (mmu_pages_count*PAGE_SIZE);
+       for ( ; a < PAGE_ALIGN((unsigned long)mmu_pages)+(MAX_MMU_PAGES*PAGE_SIZE); a += PAGE_SIZE )
+       {
+               clear_bit( PG_reserved, &mem_map[MAP_NR(a)].flags );
+               atomic_set(&mem_map[MAP_NR(a)].count, 1);
+               free_page(a);
+               num_freed_pages++;
+       }
+
+#if 0
+       addr = (unsigned long)(&__init_begin);
+       for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+               num_freed_pages++;
+               mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+               mem_map[MAP_NR(addr)].count = 1;
+               free_page(addr);
+       }
+#endif 
+       printk ("Freeing unused kernel memory: %dk freed\n",
+               (num_freed_pages * PAGE_SIZE) >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
 {
        int i;
 
-       i = ((int)high_memory & 0x00FFFFFF) >> PAGE_SHIFT;
+       i = max_mapnr;
        val->totalram = 0;
        val->sharedram = 0;
        val->freeram = nr_free_pages << PAGE_SHIFT;
@@ -187,526 +576,637 @@ void si_meminfo(struct sysinfo *val)
                val->totalram++;
                if (!atomic_read(&mem_map[i].count))
                        continue;
-               val->sharedram += atomic_read(&mem_map[i].count) - 1;
+               val->sharedram += atomic_read(&mem_map[i].count)-1;
        }
        val->totalram <<= PAGE_SHIFT;
        val->sharedram <<= PAGE_SHIFT;
        return;
 }
 
+/* Kernel MMU setup & lowest level hardware support */
+
+unsigned long _SDR1;           /* Hardware SDR1 image */
+
+#ifdef CONFIG_PREP
+
 BAT BAT0 =
-   {
-       {
-               0x80000000>>17,         /* bepi */
-               BL_256M,                /* bl */
-               1,                      /* vs -- supervisor mode valid */
-               1,                      /* vp -- user mode valid */
-       },
-       {
-               0x80000000>>17,         /* brpn */
-               1,                      /* write-through */
-               1,                      /* cache-inhibited */
-               0,                      /* memory coherence */
-               1,                      /* guarded */
-               BPP_RW                  /* protection */
-       }
-   };
+{
+  {
+    0x80000000>>17,    /* bepi */
+    BL_256M,           /* bl */
+    1,                 /* vs -- supervisor mode valid */
+    1,                 /* vp -- user mode valid */
+  },
+  {
+    0x80000000>>17,            /* brpn */
+    1,                 /* write-through */
+    1,                 /* cache-inhibited */
+    0,                 /* memory coherence */
+    1,                 /* guarded */
+    BPP_RW             /* protection */
+  }
+};
 BAT BAT1 =
-   {
-       {
-               0xC0000000>>17,         /* bepi */
-               BL_256M,                /* bl */
-               1,                      /* vs */
-               1,                      /* vp */
-       },
-       {
-               0xC0000000>>17,         /* brpn */
-               1,                      /* w */
-               1,                      /* i (cache disabled) */
-               0,                      /* m */
-               1,                      /* g */
-               BPP_RW                  /* pp */
-       }
-   };
+{
+  {
+    0xC0000000>>17,    /* bepi */
+    BL_256M,           /* bl */
+    1,                 /* vs */
+    1,                 /* vp */
+  },
+  {
+    0xC0000000>>17,            /* brpn */
+    1,                 /* w */
+    1,                 /* i (cache disabled) */
+    0,                 /* m */
+    1,                 /* g */
+    BPP_RW                     /* pp */
+  }
+};
 BAT BAT2 =
-   {
-       {
-               0x90000000>>17,         /* bepi */
-               BL_256M, /* this gets set to amount of phys ram */
-               1,                      /* vs */
-               0,                      /* vp */
-       },
-       {
-               0x00000000>>17,         /* brpn */
-               0,                      /* w */
-               0,                      /* i */
-               0,                      /* m */
-               0,                      /* g */
-               BPP_RW                  /* pp */
-       }
-   };
+{
+  {
+    0x90000000>>17,    /* bepi */
+    BL_256M, /* this gets set to amount of phys ram */
+    1,                 /* vs */
+    0,                 /* vp */
+  },
+  {
+    0x00000000>>17,            /* brpn */
+    0,                 /* w */
+    0,                 /* i */
+    1,                 /* m */
+    0,                 /* g */
+    BPP_RW                     /* pp */
+  }
+};
 BAT BAT3 =
-   {
-       {
-               0x00000000>>17,         /* bepi */
-               BL_256M,                /* bl */
-               0,                      /* vs */
-               0,                      /* vp */
-       },
-       {
-               0x00000000>>17,         /* brpn */
-               1,                      /* w */
-               1,                      /* i (cache disabled) */
-               0,                      /* m */
-               0,                      /* g */
-               BPP_RW                  /* pp */
-       }
-   };
-BAT TMP_BAT2 =
-   { /* 0x9XXXXXXX -> 0x0XXXXXXX */
-       {
-               0x90000000>>17,         /* bepi */
-               BL_256M,                /* bl */
-               1,                      /* vs */
-               1,                      /* vp */
-       },
-       {
-               0x00000000>>17,         /* brpn */
-               1,                      /* w */
-               0,                      /* i (cache enabled) */
-               0,                      /* m */
-               0,                      /* g */
-               BPP_RW                  /* pp */
-       }
-   };
-
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/*
- * This code is called to create a minimal mapped environment.
- * It is called with the MMU on, but with only a BAT register
- * set up to cover the code/data.  After this routine runs,
- * the BAT mapping is withdrawn and all mappings must be complete.
- */
+{
+  {
+    0x00000000>>17,    /* bepi */
+    BL_256M,           /* bl */
+    0,                 /* vs */
+    0,                 /* vp */
+  },
+  {
+    0x00000000>>17,            /* brpn */
+    0,                 /* w */
+    0,                 /* i (cache disabled) */
+    1,                 /* m */
+    0,                 /* g */
+    BPP_RW                     /* pp */
+  }
+};
 
+P601_BAT BAT0_601 =
+{
+  {
+    0x80000000>>17,    /* bepi */
+    1,1,0, /* wim */
+    1, 0, /* vs, vp */
+    BPP_RW, /* pp */
+  },
+  {
+    0x80000000>>17,            /* brpn */
+    1, /* v */
+    BL_8M, /* bl */
+  }
+};
 
+P601_BAT BAT1_601 =
+{
+  {
+    0xC0000000>>17,    /* bepi */
+    1,1,0, /* wim */
+    1, 0, /* vs, vp */
+    BPP_RW, /* pp */
+  },
+  {
+    0xC0000000>>17,            /* brpn */
+    1, /* v */
+    BL_8M, /* bl */
+  }
+};
 
+P601_BAT BAT2_601 =
+{
+  {
+    0x90000000>>17,    /* bepi */
+    0,0,0, /* wim */
+    1, 0, /* vs, vp */
+    BPP_RW, /* pp */
+  },
+  {
+    0x00000000>>17,            /* brpn */
+    1, /* v */
+    BL_8M, /* bl */
+  }
+};
 
-extern char _start[], _end[];
-void MMU_init(void)
+P601_BAT BAT3_601 =
 {
-  extern RESIDUAL res;
-  extern unsigned long resptr;
-  int i, p;
-  SEGREG *segs;
-  
-  /* copy residual data */
-  if ( resptr )
-    memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
-  else
-    bzero( &res, sizeof(RESIDUAL) ); /* clearing bss probably clears this but... */
-  
-  end_of_DRAM = (unsigned long *)find_end_of_memory();
-  _SDR1 = ((unsigned long)Hash - KERNELBASE) | Hash_mask;
-#if 0  
-  printk("Hash      %08x\n",(unsigned long)Hash);
-  printk("Hash_mask %08x\n",Hash_mask);
-  printk("Hash_size %08x\n",Hash_size);        
-  printk("SDR1      %08x\n",_SDR1);
-#endif
-  /* Segment registers */
-  segs = (SEGREG *)init_task.tss.segs;
-  for (i = 0;  i < 16;  i++)
   {
-    segs[i].ks = 0;
-    segs[i].kp = 1;
-#if 1
-    if ( i < 8 )
-      segs[i].vsid = i+10000;
-    else
-#else
-    if ( i < 8 )
-      segs[i].vsid = i<<5;
-#endif           
-      segs[i].vsid = i;
+    0x90800000>>17,    /* bepi */
+    0,0,0, /* wim */
+    1, 0, /* vs, vp */
+    BPP_RW, /* pp */
+  },
+  {
+    0x00800000>>17,            /* brpn */
+    1, /* v */
+    BL_8M, /* bl */
   }
-  
-  
-       
-  /* Hard map in any special local resources */
-  if (isBeBox[0])
-    {
-      /* Map in one page for the BeBox motherboard I/O */
-      end_of_DRAM = (unsigned long *)((unsigned long)end_of_DRAM - PAGE_SIZE);
-#if 0          
-      BeBox_IO_page = (unsigned char *)0x7FFFF000;
-#endif
-               BeBox_IO_page = (unsigned char *)end_of_DRAM;
-               MMU_disable_cache_for_page(&init_task.tss, BeBox_IO_page);
-    }
-}
+};
 
 /*
- * Insert(create) a hardware page table entry
+ * This finds the amount of physical ram and does necessary
+ * setup for prep.  This is pretty architecture specific so
+ * this will likely stay seperate from the pmac.
+ * -- Cort
  */
-int inline MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg)
-{
-  int hash, page_index, segment, i, h, _h, api, vsid, perms;
-  PTE *_pte, *empty, *slot;
-  PTE *slot0, *slot1;
-  extern char _etext;
-  page_index = ((int)va & 0x0FFFF000) >> 12;
-  segment = (unsigned int)va >> 28;
-  api = page_index >> 10;
-  vsid = ((SEGREG *)tss->segs)[segment].vsid;
-  empty = slot = (PTE *)NULL;
-  
-  if ( (va <= _etext) && (va >= KERNELBASE))
-  {
-    printk("MMU_hash_page: called on kernel page mapped with bats va %x\n",
-          va);
-  }
+unsigned long *find_end_of_memory(void)
+{
+       extern RESIDUAL res;
+       extern unsigned long resptr;
+       int i, p;
+       unsigned long h;
 
-  /* check first hash bucket */
-  h = 0;
-  hash = page_index ^ vsid;
-  hash &= 0x3FF | (Hash_mask << 10);
-  hash *= 8;                   /* 8 entries in each bucket */
-  _pte = &Hash[hash];
-  slot0 = _pte;
-  for (i = 0;  i < 8;  i++, _pte++)
-    {
-      if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
-       {
-         slot = _pte;
-         goto found_it;
-       }
-      if ((empty == NULL) && (!_pte->v))
+       /* copy residual data */
+       if ( resptr )
+               memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
+       else
+               /* clearing bss probably clears this but... */
+               memset( &res, sizeof(RESIDUAL), 0 );
+       _TotalMemory = res.TotalMemory;
+       
+       /* this really has nothing to do with the mmu_init() but is
+          necessary for early setup -- Cort */
+       if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
        {
-         empty = _pte;
-         _h = h;
+               _machine = _MACH_IBM;
        }
-    }
-
-  /* check second hash bucket */
-  h = 1;
-  hash = page_index ^ vsid;
-  hash = ~hash;
-  hash &= 0x3FF | (Hash_mask << 10);
-  hash *= 8;                   /* 8 entries in each bucket */
-  _pte = &Hash[hash];
-  slot1 = _pte;
-  for (i = 0;  i < 8;  i++, _pte++)
-    {
-      if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
+       else
+               _machine = _MACH_Motorola;
+  
+       /* setup the hash table */
+       if (_TotalMemory == 0 )
        {
-         slot = _pte;
-         goto found_it;
+               /*
+                * I need a way to probe the amount of memory if the residual
+                * data doesn't contain it. -- Cort
+                */
+               printk("Ramsize from residual data was 0 -- Probing for value\n");
+               _TotalMemory = 0x03000000;
+               printk("Ramsize default to be %dM\n", _TotalMemory>>20);
        }
-      if ((empty == NULL) && (!_pte->v))
+       
+#if 0
+       /* linux has trouble with > 64M ram -- Cort */
+       if ( _TotalMemory > 0x04000000 /* 64M */ )
        {
-         empty = _pte;
-         _h = h;
+               printk("Only using first 64M of ram.\n");
+               _TotalMemory = 0x04000000;
        }
-    }
+#endif 
+       
+       /* setup the bat2 mapping to cover physical ram */
+       BAT2.batu.bl = 0x1; /* 256k mapping */
+       for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
+             h *= 2 )
+               BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
+       /*
+        * Allow 64k of hash table for every 16MB of memory,
+        * up to a maximum of 2MB.
+        */
+       for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
+               ;
+       Hash_size = h;
+       Hash_mask = (h >> 6) - 1;
+       
+       /* align htab on a Hash_size boundry above _end[] */
+       Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
+       memset(Hash, Hash_size, 0 );
 
-  if (empty == (PTE *)NULL)
-  { 
-#if 1
-    printk("Both hash buckets full! va %x vsid %x current %s (%d)\n",
-          va,vsid,current->comm,current->pid);
-#endif
-    slot = slot1;
-    h = 1;
-  }
-  else
-  {
-    slot = empty;
-    h = _h;
-  }
-found_it:
-#ifdef HASHSTATS
-  hashhits[hash]++;
-#endif
-  _tlbie(va); /* Clear TLB */
-    /* Fill in table */
-      slot->v = 1;
-      slot->vsid = vsid;
-      slot->h = h;
-      slot->api = api;
-      if (((pg->page_num << 12) & 0xF0000000) == KERNELBASE)
+       /*
+        * if this is a 601, we can only map sizes of 8M with the BAT's
+        * so we have to map what we can't map with the bats with the segregs
+        * head.S will copy in the appropriate BAT's according to the processor
+        * since the 601_BAT{2,3} structures are already setup to map
+        * the first 16M correctly
+        * -- Cort
+        */
+#ifndef MAP_RAM_WITH_SEGREGS     /* don't need to do it twice */
+       if ( _get_PVR() == 1 )
        {
-         slot->rpn = pg->page_num - (KERNELBASE>>12);
-       } else
-         {
-           slot->rpn = pg->page_num;
-         }
-      slot->r = 0;
-      slot->c = 0;
-      slot->i = 0;
-      slot->g = 0;
-      if (cache_is_copyback)
-       {
-         if (kernel_pages_are_copyback || (pg->flags & _PAGE_USER) || (va < (unsigned long)&_etext))
-           { /* All User & Kernel TEXT pages are copy-back */
-             slot->w = 0;
-             slot->m = 1;
-           } else
-             { /* Kernel DATA pages are write-thru */
-               slot->w = 1;
-               slot->m = 0;
-             }
-       } else
-         {
-           slot->w = 1;
-           slot->m = 0;
-         }
-      if (pg->flags & _PAGE_USER)
+               /* map in rest of ram with seg regs */
+               if ( _TotalMemory > 0x01000000 /* 16M */)
+               {
+                       for (i = KERNELBASE+0x01000000;
+                            i < KERNELBASE+_TotalMemory;  i += PAGE_SIZE)
+                               map_page(&init_task.tss, i, __pa(i),
+                                        _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
+               }
+       }
+#endif /* MAP_RAM_WITH_SEGREGS */
+  
+#ifdef MAP_RAM_WITH_SEGREGS
+       /* turn off bat mapping kernel since being done with segregs */
+       memset(&BAT2, sizeof(BAT2), 0);
+       memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
+       memset(&BAT3_601, sizeof(BAT2), 0);
+       /* map all of ram for kernel with segregs */
+       for (i = KERNELBASE;  i < KERNELBASE+_TotalMemory;  i += PAGE_SIZE)
        {
-         if (pg->flags & _PAGE_RW)
-           { /* Read/write page */
-             perms = PP_RWRW;
-           } else
-             { /* Read only page */
-               perms = PP_RWRX;
-               perms = PP_RXRX;
-             }
-       } else
-         { /* Kernel pages */
-           perms = PP_RWRW;
-           perms = PP_RWXX;
-         }
-      slot->pp = perms;
-      return (0);
+               if ( i < (unsigned long)etext )
+                       map_page(&init_task.tss, i, __pa(i),
+                                _PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
+               else
+                       map_page(&init_task.tss, i, __pa(i),
+                                _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
+       }
+#endif /* MAP_RAM_WITH_SEGREGS */
+       
+       printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+              _TotalMemory >> 20, Hash_size >> 10, Hash);
+       return ((unsigned long *)_TotalMemory);
 }
+#endif /* CONFIG_PREP */
+
 
+#ifdef CONFIG_PMAC
 /*
- * Disable cache for a particular page
+ * Map in all of physical memory starting at KERNELBASE.
  */
-MMU_disable_cache_for_page(struct thread_struct *tss, unsigned long va)
+extern int n_mem_regions;
+extern struct reg_property mem_regions[];
+
+#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+
+static void mapin_ram()
 {
-       int hash, page_index, segment, i, h, _h, api, vsid, perms;
-       PTE *_pte, *empty, *slot;
-       PTE *slot0, *slot1;
-       extern char _etext;
-       page_index = ((int)va & 0x0FFFF000) >> 12;
-       segment = (unsigned int)va >> 28;
-       api = page_index >> 10;
-       vsid = ((SEGREG *)tss->segs)[segment].vsid;
-       empty = slot = (PTE *)NULL;
-       for (_h = 0;  _h < 2;  _h++)
-       {
-               hash = page_index ^ vsid;               
-               if (_h)
-               {
-                       hash = ~hash;  /* Secondary hash uses ones-complement */
-               }
-               hash &= 0x3FF | (Hash_mask << 10);
-               hash *= 8;  /* Eight entries / hash bucket */
-               _pte = &Hash[hash];
-               /* Save slot addresses in case we have to purge */
-               if (_h)
-               {
-                       slot1 = _pte;
-               } else
-               {
-                       slot0 = _pte;
-               }
-               for (i = 0;  i < 8;  i++, _pte++)
-               {
-                       if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
-                       { /* Found it! */
-                               h = _h;
-                               slot = _pte;
-                               goto found_it;
-                       }
-                       if ((empty == (PTE *)NULL) && !_pte->v)
-                       {
-                               h = _h;
-                               empty = _pte;
-                       }
-               }
+    int i;
+    unsigned long v, p, s, f;
+
+    v = KERNELBASE;
+    for (i = 0; i < phys_mem.n_regions; ++i) {
+       p = phys_mem.regions[i].address;
+       for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+           f = _PAGE_PRESENT | _PAGE_ACCESSED;
+           if ((char *) v < _stext || (char *) v >= etext)
+               f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+           map_page(&init_task.tss, v, p, f);
+           v += PAGE_SIZE;
+           p += PAGE_SIZE;
        }
-found_it:      
-       _tlbie(va); /* Clear TLB */
-       slot->i = 1;
-       slot->m = 0;
+    }
 }
 
+#define MAX_PROM_TRANSLATIONS  64
 
-/*
- * invalidate a hardware hash table pte
- */
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
+static struct translation_property prom_translations[MAX_PROM_TRANSLATIONS];
+int n_translations;
+phandle mmu_pkg;
+extern ihandle prom_chosen;
+
+static void inherit_prom_translations()
 {
-       int hash, page_index, segment, i, h, _h, api, vsid, perms;
-       PTE *_pte, *slot;
-       int flags = 0;
-       page_index = ((int)va & 0x0FFFF000) >> 12;
-       segment = (unsigned int)va >> 28;
-       api = page_index >> 10;
-       vsid = mm->context | segment;
-       for (_h = 0;  _h < 2;  _h++)
-       {
-               hash = page_index ^ vsid;               
-               if (_h)
-               {
-                       hash = ~hash;  /* Secondary hash uses ones-complement */
-               }
-               hash &= 0x3FF | (Hash_mask << 10);
-               hash *= 8;  /* Eight entries / hash bucket */
-               _pte = &Hash[hash];
-               for (i = 0;  i < 8;  i++, _pte++)
-               {
-                       if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
-                       { /* Found it! */
-                               _tlbie(va); /* Clear TLB */
-                               if (_pte->r) flags |= _PAGE_ACCESSED;
-                               if (_pte->c) flags |= _PAGE_DIRTY;
-                               _pte->v = 0;
-                               return (flags);
-                       }
+       int s, i, f;
+       unsigned long v, p, n;
+       struct translation_property *tp;
+       ihandle mmu_inst;
+
+       if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
+                           &mmu_inst, sizeof(mmu_inst)) != sizeof(mmu_inst))
+               panic("couldn't get /chosen mmu property");
+       mmu_pkg = call_prom("instance-to-package", 1, 1, mmu_inst);
+       if (mmu_pkg == (phandle) -1)
+               panic("couldn't get mmu package");
+       s = (int) call_prom("getprop", 4, 1, mmu_pkg, "translations",
+                           &prom_translations, sizeof(prom_translations));
+       if (s < sizeof(prom_translations[0]))
+               panic("couldn't get mmu translations property");
+       n_translations = s / sizeof(prom_translations[0]);
+
+       for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
+               /* ignore stuff mapped down low */
+               if (tp->virt < 0x10000000)
+                       continue;
+               /* map PPC mmu flags to linux mm flags */
+               f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
+                                 | _PAGE_COHERENT | _PAGE_GUARDED))
+                       | pgprot_val(PAGE_KERNEL);
+               /* add these pages to the mappings */
+               v = tp->virt;
+               p = tp->phys;
+               n = tp->size;
+               for (; n != 0; n -= PAGE_SIZE) {
+                       map_page(&init_task.tss, v, p, f);
+                       v += PAGE_SIZE;
+                       p += PAGE_SIZE;
                }
        }
-       _tlbie(va);
-       return (flags);
 }
+#endif
 
-
-inline void
-flush_cache_all(void)
+/*
+ * Initialize the hash table and patch the instructions in head.S.
+ */
+static void hash_init(void)
 {
+       int Hash_bits;
+
+       extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
+               hash_page_patch_C[];
+
+       memset(Hash, 0, Hash_size);
+       Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+
+       /*
+        * Patch up the instructions in head.S:hash_page
+        */
+       Hash_bits = ffz(~Hash_size) - 6;
+       hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
+               | (__pa(Hash) >> 16);
+       hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
+               | ((26 - Hash_bits) << 6);
+       if (Hash_bits > 16)
+               Hash_bits = 16;
+       hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
+               | ((26 - Hash_bits) << 6);
+       hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
+               | (Hash_mask >> 10);
+       hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
+               | (Hash_mask >> 10);
+
+       /*
+        * Ensure that the locations we've patched have been written
+        * out from the data cache and invalidated in the instruction
+        * cache, on those machines with split caches.
+        */
+       store_cache_range((unsigned long) hash_page_patch_A,
+                         (unsigned long) (hash_page_patch_C + 1));
 }
-inline void
-flush_cache_mm(struct mm_struct *mm)
+
+
+/*
+ * Do very early mm setup such as finding the size of memory
+ * and setting up the hash table.
+ * A lot of this is prep/pmac specific but a lot of it could
+ * still be merged.
+ * -- Cort
+ */
+void
+MMU_init(void)
 {
-} 
-inline void
-flush_cache_page(struct vm_area_struct *vma, long va)
+        end_of_DRAM = find_end_of_memory();
+        hash_init();
+        _SDR1 = __pa(Hash) | (Hash_mask >> 10);
+#ifdef CONFIG_PMAC
+        /* Force initial page tables */
+       /* this done by INIT_TSS in processor.h on prep -- Cort */
+        init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
+
+       /* Map in all of RAM starting at KERNELBASE */
+       mapin_ram();
+       /* Copy mappings from the prom */
+       inherit_prom_translations();
+#endif /* CONFIG_PMAC */
+}
+
+static void *
+MMU_get_page()
 {
-} 
-inline void
-flush_cache_range(struct mm_struct *mm, unsigned long va_start, unsigned long va_end)
+  void *p;
+  
+  if (mem_init_done) {
+    p = (void *) __get_free_page(GFP_KERNEL);
+    if (p == 0)
+      panic("couldn't get a page in MMU_get_page");
+  } else {
+#ifdef CONFIG_PREP
+    mmu_pages_count++;
+    if ( mmu_pages_count > MAX_MMU_PAGES )
+      printk("out of mmu pages!\n");
+    p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+               (mmu_pages_count+PAGE_SIZE));
+#endif
+#ifdef CONFIG_PMAC
+    p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+#endif
+  }
+  memset(p, 0, PAGE_SIZE);
+  return p;
+}
+
+#ifdef CONFIG_PMAC
+void *
+ioremap(unsigned long addr, unsigned long size)
 {
-} 
+       unsigned long p, end = addr + size;
+
+       for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
+               map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+       return (void *) addr;
+}
+#endif
 
-inline void
-cache_mode(char *str, int *ints)
+void
+map_page(struct thread_struct *tss, unsigned long va,
+        unsigned long pa, int flags)
 {
-       cache_is_copyback = ints[0];
+       pmd_t *pd;
+       pte_t *pg;
+
+       if (tss->pg_tables == NULL) {
+               /* Allocate upper level page map */
+               tss->pg_tables = (unsigned long *) MMU_get_page();
+       }
+       /* Use upper 10 bits of VA to index the first level map */
+       pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+       if (pmd_none(*pd)) {
+               /* Need to allocate second-level table */
+               pg = (pte_t *) MMU_get_page();
+               pmd_val(*pd) = (unsigned long) pg;
+       }
+       /* Use middle 10 bits of VA to index the second-level map */
+       pg = pte_offset(pd, va);
+       set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
+       /*flush_hash_page(va >> 28, va);*/
+       flush_hash_page(0, va);
 }
 
 /*
  * TLB flushing:
  *
- *  - flush_tlb() flushes the current mm struct TLBs
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
  *  - flush_tlb_range(mm, start, end) flushes a range of pages
  *
  * since the hardware hash table functions as an extension of the
- * tlb as far as the linux tables are concerned, flush them too.
+ * tlb as far as the linux tables are concerned, flush it too.
  *    -- Cort
  */
-inline void
-flush_tlb(void)
-{
-  PTE *ptep;
-  int context = current->mm->context;
-  struct vm_area_struct *v;
-  unsigned int i;
-  
-  v = current->mm->mmap;
 
-  /* for every virtual memory address in the current context -- flush
-     the hash table */
-  while ( v != NULL )
-  {
-    for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
-    {
-      MMU_invalidate_page(v->vm_mm,i);
-    }
-    v = v->vm_next;
-  }
-
-  _tlbia();
-}
-
-/* flush all tlb/hash table entries except for kernels
-
-   although the kernel is mapped with the bats, it's dynamic areas
-   obtained via kmalloc are mapped by the seg regs
-                      -- Cort
-   */
-inline void
+/*
+ * Flush all tlb/hash table entries except for the kernel's.
+ * We use the fact that only kernel mappings use VSIDs 0 - 15.
+ */
+void
 flush_tlb_all(void)
 {
-  PTE *ptep;
-
-  /* flush hash table */
-  for ( ptep = Hash ; ptep < (PTE *)((unsigned long)Hash+Hash_size) ; ptep++ )
-  {
-    /* if not kernel vsids 0-7 (vsid greater than that for process 0)*/
-    if ( (ptep->vsid > 7 ) && (ptep->v))
-    {
-      ptep->v = 0;
-    }
-  }
+       struct task_struct *tsk;
 
-  _tlbia();
+       read_lock(&tasklist_lock);
+       for_each_task(tsk) {
+               if (tsk->mm)
+                       tsk->mm->context = NO_CONTEXT;
+       }
+       read_unlock(&tasklist_lock);
+       get_mmu_context(current);
+       set_context(current->mm->context);
 }
 
-inline void
+
+/*
+ * Flush all the (user) entries for the address space described
+ * by mm.  We can't rely on mm->mmap describing all the entries
+ * that might be in the hash table.
+ */
+void
 flush_tlb_mm(struct mm_struct *mm)
 {
-  PTE *ptep;
-  int context = mm->context;
-  struct vm_area_struct *v;
-  unsigned int i;
-
-  v = mm->mmap;
-  while ( v != NULL )
-  {
-    for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
-    {
-      MMU_invalidate_page(v->vm_mm,i);
-    }
-    v = v->vm_next;
-  }
-
-  _tlbia();
+       mm->context = NO_CONTEXT;
+       if (mm == current->mm) {
+               get_mmu_context(current);
+               /* done by get_mmu_context() now -- Cort */
+               /*set_context(current->mm->context);*/
+       }
 }
 
 
-inline void
-flush_tlb_page(struct vm_area_struct *vma, long vmaddr)
+void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 {
-  MMU_invalidate_page(vma->vm_mm,vmaddr);
+       unsigned vsid;
+       
+       if ( vmaddr < TASK_SIZE) {
+               /*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
+               flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
+               /* this is needed on prep at the moment -- don't know why
+                  -- Cort*/
+               MMU_invalidate_page(vma->vm_mm,vmaddr);
+       }
+       else
+       {
+               /*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
+       }
 }
 
 
-/* for each page addr in the range, call mmu_invalidat_page()
+/* for each page addr in the range, call MMU_invalidate_page()
    if the range is very large and the hash table is small it might be faster to
    do a search of the hash table and just invalidate pages that are in the range
    but that's for study later.
         -- Cort
    */
-inline void
-flush_tlb_range(struct mm_struct *mm, long start, long end)
+void
+flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-  long i;
-  for ( i = PAGE_ALIGN(start-PAGE_SIZE) ; i < PAGE_ALIGN(end) ; i += PAGE_SIZE)
-  {
-    MMU_invalidate_page(mm,i);
-  }
+        start &= PAGE_MASK;
+       for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
+       {
+               /*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
+                               start );*/
+               flush_hash_page(mm->context, start);
+               /* this is needed on prep at the moment -- don't know why
+                  -- Cort*/
+               MMU_invalidate_page(mm,start);
+       }
 }
 
-inline void
-flush_page_to_ram(unsigned long page)
+/*
+ * The context counter has overflowed.
+ * We set mm->context to NO_CONTEXT for all mm's in the system.
+ * We assume we can get to all mm's by looking as tsk->mm for
+ * all tasks in the system.
+ */
+void
+mmu_context_overflow(void)
+{
+       struct task_struct *tsk;
+       int nr;
+
+       printk(KERN_INFO "mmu_context_overflow\n");
+       for (nr = 0; nr < NR_TASKS; ++nr) {
+               tsk = task[nr];
+               if (tsk && tsk->mm)
+                       tsk->mm->context = NO_CONTEXT;
+       }
+       flush_hash_segments(0x10, 0xffffff);
+       _tlbia();
+       next_mmu_context = 0;
+}
+
+#ifdef CONFIG_PREP
+/*
+ * it's not a simple matter to get rid of these and switch to the
+ * ones paul is using. it will take some time and thought  -- Cort
+ */
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
 {
+       int hash, page_index, segment, i, h, _h, api, vsid, perms;
+       PTE *_pte, *slot;
+       int flags = 0;
+       page_index = ((int)va & 0x0FFFF000) >> 12;
+       segment = (unsigned int)va >> 28;
+       api = page_index >> 10;
+       vsid = VSID_FROM_CONTEXT(segment,mm->context);
+       for (_h = 0;  _h < 2;  _h++)
+       {
+               hash = page_index ^ vsid;               
+               if (_h)
+               {
+                       hash = ~hash;  /* Secondary hash uses ones-complement */
+               }
+               hash &= 0x3FF | (Hash_mask /*<< 10*/);
+               hash *= 8;  /* Eight entries / hash bucket */
+               _pte = &Hash[hash];
+               for (i = 0;  i < 8;  i++, _pte++)
+               {
+                       if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
+                       { /* Found it! */
+                               _tlbie(va); /* Clear TLB */
+                               if (_pte->r) flags |= _PAGE_ACCESSED;
+                               if (_pte->c) flags |= _PAGE_DIRTY;
+                               _pte->v = 0;
+                               return /*(flags)*/;
+                       }
+               }
+       }
+       _tlbie(va);
+       return /*(flags)*/;
+}
+#endif
+
+#include <asm/mmu.h>
+void print_mm_info(void)
+{
+       struct _SEGREG s;
+       long a;
+       struct _BATU bu;
+       struct _BATL bl;
+       unsigned long i;
+
+       for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
+       {
+               a = get_SR(i);
+               memcpy(&s,&a,4);
+               printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x  %x\n",
+                      i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
+       }
+
+       asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
+       printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
+                      bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
 }
diff --git a/arch/ppc/prep_defconfig b/arch/ppc/prep_defconfig
new file mode 100644 (file)
index 0000000..bd955c7
--- /dev/null
@@ -0,0 +1,239 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+# CONFIG_HEARTBEAT is not set
+# CONFIG_POWERSAVING is not set
+CONFIG_MCOMMON=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_NCR53C7xx=y
+# CONFIG_SCSI_NCR53C7xx_sync is not set
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_SCSI_QLOGIC_PMAC is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_BEXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_RNFS_BOOTP is not set
+# CONFIG_RNFS_RARP is not set
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_HFS_FS=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
index 9d64ee85ddcb75e9be5cc8d4b03a638988048256..80e1145854f38b7801fc76dcb24f48515fd7e470 100644 (file)
@@ -42,7 +42,7 @@ SUN_FB_CGFOURTEEN=y
 SUN_FB_BWTWO=y
 SUN_FB_LEO=y
 TADPOLE_FB_WEITEK=y
-#SUN_FB_CREATOR is not set
+SUN_FB_CREATOR=y
 
 #
 # Misc Linux/SPARC drivers
@@ -180,15 +180,12 @@ CONFIG_MYRI_SBUS=m
 # Filesystems
 #
 CONFIG_QUOTA=y
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
-CONFIG_UMSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
index 5d0ea0840052fb3ac05e7b8f74c70efe300f8260..f60ecbe9ca3f8d5598b1abd192d65b19b23ee624 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $
+/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -842,8 +842,9 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
        linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
        linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
 
-       if (getname (sunos_mount->hostname, &the_name))
-               return -EFAULT;
+       the_name = getname(sunos_mount->hostname);
+       if(IS_ERR(the_name))
+               return PTR_ERR(the_name);
 
        strncpy (linux_nfs_mount.hostname, the_name, 254);
        linux_nfs_mount.hostname [255] = 0;
index 3b997055116a7b33215b97c2995736641b8ffca4..ad9aa8953d248cf9019765d4cdbdbc93b5d98581 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.148 1997/06/24 15:48:02 jj Exp $
+/* $Id: srmmu.c,v 1.149 1997/07/20 05:59:34 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -2214,7 +2214,8 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
 {
        if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
                struct vm_area_struct *vmaring;
-               struct inode *inode;
+               struct dentry *dentry;
+               struct inode *inode = NULL;
                unsigned long flags, offset, vaddr, start;
                int alias_found = 0;
                pgd_t *pgdp;
@@ -2223,7 +2224,9 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
 
                save_and_cli(flags);
 
-               inode = vma->vm_inode;
+               dentry = vma->vm_dentry;
+               if(dentry)
+                       inode = dentry->d_inode;
                if (!inode)
                        goto done;
                offset = (address & PAGE_MASK) - vma->vm_start;
index a0ffc10ed4a3c7c11c4e7a5933b8d4d84f89c4eb..7ffca1033551065bd0f7debefe2389b7e0056cd3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.148 1997/05/18 21:11:19 davem Exp $
+/* $Id: sun4c.c,v 1.149 1997/07/20 05:59:38 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2435,11 +2435,14 @@ static pgd_t *sun4c_pgd_alloc(void)
  */
 static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
-       struct inode *inode;
+       struct dentry *dentry;
+       struct inode *inode = NULL;
        pgd_t *pgdp;
        pte_t *ptep;
 
-       inode = vma->vm_inode;
+       dentry = vma->vm_dentry;
+       if(dentry)
+               inode = dentry->d_inode;
        if(inode) {
                unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
                struct vm_area_struct *vmaring = inode->i_mmap; 
index 92a0038535ca71adc151e986732d3ad60edf89b2..c9c92b9877b8589534ca6022ac97f6ed4e4b3d75 100644 (file)
@@ -160,14 +160,11 @@ CONFIG_MYRI_SBUS=m
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
index 9e9013735c6ac957d32ac61a752b28a9b2217e97..aecb9fd471b3c4cc06f4d79e85f4df2ce3d7e2f5 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.28 1997/07/05 09:52:20 davem Exp $
+# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -7,12 +7,24 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+ifdef SMP
+
+.S.s:
+       $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
 .S.s:
        $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
 
 .S.o:
        $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
+endif
+
 all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
@@ -22,6 +34,10 @@ O_OBJS   := process.o setup.o cpu.o idprom.o \
            unaligned.o sys_sunos32.o sunos_ioctl32.o
 OX_OBJS  := sparc64_ksyms.o
 
+ifdef SMP
+O_OBJS += smp.o trampoline.o
+endif
+
 ifdef CONFIG_SPARC32_COMPAT
   O_OBJS += sys32.o sys_sparc32.o signal32.o ioctl32.o
 endif
@@ -36,7 +52,7 @@ endif
 
 head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
        winfixup.S entry.S
-       $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
 
 #
 # This is just to get the dependencies...
index 6c3ff91741b0bb4e1897bc4191d8cbc51153cdd5..00e5f272295f95a3508dacf653ecc3f03723c51a 100644 (file)
@@ -4,6 +4,9 @@
  */
 
 #include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/init.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
index d6cdf9162f241b7db248d9d47a354c7d39ca1b58..2c96a83e94d08a876aa6c78eebd3f6227db2c5e7 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
 #include <asm/asi.h>
 #include <asm/system.h>
 #include <asm/fpumacro.h>
@@ -56,12 +58,7 @@ __initfunc(void cpu_probe(void))
        long ver, fpu_vers;
        long fprs;
        
-#ifndef __SMP__
-       cpuid = 0;
-#else
-#error SMP not supported on sparc64 yet
-       /* cpuid = get_cpuid(); */
-#endif
+       cpuid = smp_processor_id();
 
        fprs = fprs_read ();
        fprs_write (FPRS_FEF);
index 5e6705896048e4ab3f24ba2ec25408820e1bc678..9327058a80b9695ec5959b051e9d6076e3bfd550 100644 (file)
@@ -13,7 +13,7 @@
 #include <asm/system.h>
 #include <asm/smp.h>
 
-struct prom_cpuinfo linux_cpus[NCPUS];
+struct prom_cpuinfo linux_cpus[NR_CPUS];
 int linux_num_cpus = 0;
 
 extern void cpu_probe(void);
index a410cfe80896eee03042482db6966f366f7244ae..425c2d873c85914a3945da2982a3607a201b059e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.50 1997/07/15 16:53:00 davem Exp $
+/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -206,7 +206,7 @@ fpdis_exit:
         * flushing very quickly.
         */
        .align  32
-       .globl  do_ivec
+       .globl  do_ivec, do_ivec_return
 do_ivec:
        ldxa            [%g0] ASI_INTR_RECEIVE, %g1
        andcc           %g1, 0x20, %g0
index b7a0f312da8a0832379cdb357d6f8a82423e943b..81eb45e4258943453f8be8a809e1d23a45e1c684 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
+/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -30,6 +30,7 @@
 #include <asm/kbio.h>
 #include <asm/vuid_event.h>
 #include <asm/rtc.h>
+#include <asm/openpromio.h>
 
 /* As gcc will warn about casting u32 to some ptr, we have to cast it to
  * unsigned long first, and that's what is A() for.
@@ -697,6 +698,22 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        case RTCGET:
        case RTCSET:
 
+       /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
+        * embedded pointers in the arg which we'd need to clean up...
+        */
+       case OPROMGETOPT:
+       case OPROMSETOPT:
+       case OPROMNXTOPT:
+       case OPROMSETOPT2:
+       case OPROMNEXT:
+       case OPROMCHILD:
+       case OPROMGETPROP:
+       case OPROMNXTPROP:
+       case OPROMU2P:
+       case OPROMGETCONS:
+       case OPROMGETFBNAME:
+       case OPROMGETBOOTARGS:
+
        /* Socket level stuff */
        case FIOSETOWN:
        case SIOCSPGRP:
index 390c33517b12a073dc2d2d8cb2e92561d7a03779..7d1580b397a2be95e50fad21c317c10bbff03fd4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.10 1997/06/30 09:24:02 jj Exp $
+/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -83,7 +83,7 @@ void sparc_free_io (void *virtual, int len)
        unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
        unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
        
-       if (virtual >= PAGE_OFFSET + 0x10000000000UL)
+       if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL)
                return;
 
        release_region(vaddr, plen);
index c4e7f0e745403f6c31cc57f7d9114a3ff655b07f..f76c27c57ac6fbe850a08fbaba1c68e90ce41098 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $
+/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -23,6 +23,7 @@
 #include <asm/iommu.h>
 #include <asm/upa.h>
 #include <asm/oplib.h>
+#include <asm/timer.h>
 #include <asm/smp.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
@@ -76,7 +77,7 @@ int get_irq_list(char *buf)
 }
 
 /* INO number to Sparc PIL level. */
-static unsigned char ino_to_pil[] = {
+unsigned char ino_to_pil[] = {
        0, 1, 2, 3, 5, 7, 8, 9,         /* SBUS slot 0 */
        0, 1, 2, 3, 5, 7, 8, 9,         /* SBUS slot 1 */
        0, 1, 2, 3, 5, 7, 8, 9,         /* SBUS slot 2 */
@@ -391,7 +392,116 @@ int __sparc64_bh_counter = 0;
 #define irq_exit(cpu, irq)     (local_irq_count[cpu]--)
 
 #else
-#error SMP not supported on sparc64 just yet
+
+atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+
+/* Who has global_irq_lock. */
+unsigned char global_irq_holder = NO_PROC_ID;
+
+/* This protects IRQ's. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+static inline void wait_on_irq(int cpu)
+{
+       int local_count = local_irq_count[cpu];
+
+       while(local_count != atomic_read(&global_irq_count)) {
+               atomic_sub(local_count, &global_irq_count);
+               spin_unlock(&global_irq_lock);
+               for(;;) {
+                       if (atomic_read(&global_irq_count))
+                               continue;
+                       if (*((unsigned char *)&global_irq_lock))
+                               continue;
+                       if (spin_trylock(&global_irq_lock))
+                               break;
+               }
+               atomic_add(local_count, &global_irq_count);
+       }
+}
+
+static inline void get_irqlock(int cpu)
+{
+       if (!spin_trylock(&global_irq_lock)) {
+               if ((unsigned char) cpu == global_irq_holder)
+                       return;
+               do {
+                       barrier();
+               } while (!spin_trylock(&global_irq_lock));
+       }
+       wait_on_irq(cpu);
+       global_irq_holder = cpu;
+}
+
+void __global_cli(void)
+{
+       int cpu = smp_processor_id();
+
+       __cli();
+       get_irqlock(cpu);
+}
+
+void __global_sti(void)
+{
+       release_irqlock(smp_processor_id());
+       __sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+       return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+       if (flags & 1) {
+               __global_cli();
+       } else {
+               if (global_irq_holder == (unsigned char) smp_processor_id()) {
+                       global_irq_holder = NO_PROC_ID;
+                       spin_unlock(&global_irq_lock);
+               }
+               if (!(flags & 2))
+                       __sti();
+       }
+}
+
+void irq_enter(int cpu, int irq)
+{
+       hardirq_enter(cpu);
+       barrier();
+       while (*((unsigned char *)&global_irq_lock)) {
+               if ((unsigned char) cpu == global_irq_holder)
+                       printk("irq_enter: Frosted Lucky Charms, "
+                              "they're magically delicious!\n");
+               barrier();
+       }
+}
+
+void irq_exit(int cpu, int irq)
+{
+       hardirq_exit(cpu);
+       release_irqlock(cpu);
+}
+
+void synchronize_irq(void)
+{
+       int cpu = smp_processor_id();
+       int local_count = local_irq_count[cpu];
+       unsigned long flags;
+
+       if (local_count != atomic_read(&global_irq_count)) {
+               save_and_cli(flags);
+               restore_flags(flags);
+       }
+}
+
 #endif /* __SMP__ */
 
 void report_spurious_ivec(struct pt_regs *regs)
@@ -432,9 +542,7 @@ void handler_irq(int irq, struct pt_regs *regs)
        struct irqaction *action;
        int cpu = smp_processor_id();
 
-       /* XXX */
-       if(irq != 14)
-               clear_softint(1 << irq);
+       clear_softint(1 << irq);
 
        irq_enter(cpu, irq);
        action = *(irq + irq_action);
@@ -575,53 +683,46 @@ int probe_irq_off(unsigned long mask)
   return 0;
 }
 
-/* XXX This is a hack, make it per-cpu so that SMP port will work correctly
- * XXX with mixed MHZ Ultras in the machine. -DaveM
- */
-static unsigned long cpu_cfreq;
-static unsigned long tick_offset;
+struct sun5_timer *linux_timers = NULL;
 
-/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
-static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
+/* This is called from sbus_init() to get the jiffies timer going.
+ * We need to call this after there exists a valid SBus_chain so
+ * that the IMAP/ICLR registers can be accessed.
+ *
+ * XXX That is because the whole startup sequence is broken.  I will
+ * XXX fix it all up very soon.  -DaveM
+ */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
 {
-       if (!(get_softint () & 1)) {
-               /* Just to be sure... */
-               clear_softint(1 << 14);
-               printk("Spurious level14 at %016lx\n", regs->tpc);
-               return;
-       } else {
-               unsigned long compare, tick;
-
-               do {
-                       extern void timer_interrupt(int, void *, struct pt_regs *);
-
-                       timer_interrupt(irq, dev_id, regs);
-
-                       /* Acknowledge INT_TIMER */
-                       clear_softint(1 << 0);
+       struct linux_prom64_registers pregs[3];
+       u32 pirqs[2];
+       int node, err;
 
-                       /* Set up for next timer tick. */
-                       __asm__ __volatile__("rd        %%tick_cmpr, %0\n\t"
-                                            "add       %0, %2, %0\n\t"
-                                            "wr        %0, 0x0, %%tick_cmpr\n\t"
-                                            "rd        %%tick, %1"
-                                            : "=&r" (compare), "=r" (tick)
-                                            : "r" (tick_offset));
-               } while(tick >= compare);
+       node = prom_finddevice("/counter-timer");
+       if(node == 0) {
+               prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
+               prom_halt();
        }
-}
+       err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+       if(err == -1) {
+               prom_printf("init_timers: Cannot obtain 'reg' for counter-timer.\n");
+               prom_halt();
+       }
+       err = prom_getproperty(node, "interrupts", (char *)&pirqs[0], sizeof(pirqs));
+       if(err == -1) {
+               prom_printf("init_timers: Cannot obtain 'interrupts' "
+                           "for counter-timer.\n");
+               prom_halt();
+       }
+       linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
 
-/* This is called from time_init() to get the jiffies timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
-{
-       int node, err;
+       /* Shut it up first. */
+       linux_timers->limit0 = 0;
+
+       /* Register IRQ handler. */
+       err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
+                         cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
 
-       /* XXX FIX this for SMP -JJ */
-       node = linux_cpus [0].prom_node;
-       cpu_cfreq = prom_getint(node, "clock-frequency");
-       tick_offset = cpu_cfreq / HZ;
-       err = request_irq(14, timer_handler, (SA_INTERRUPT|SA_STATIC_ALLOC),
-                         "timer", NULL);
        if(err) {
                prom_printf("Serious problem, cannot register timer interrupt\n");
                prom_halt();
@@ -630,27 +731,33 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
 
                save_and_cli(flags);
 
-               __asm__ __volatile__("wr        %0, 0x0, %%tick_cmpr\n\t"
-                                    "wrpr      %%g0, 0x0, %%tick"
-                                    : /* No outputs */
-                                    : "r" (tick_offset));
-                                    
-               clear_softint (get_softint ());
+               /* Set things up so user can access tick register for profiling
+                * purposes.
+                */
+               __asm__ __volatile__("
+       sethi   %%hi(0x80000000), %%g1
+       sllx    %%g1, 32, %%g1
+       rd      %%tick, %%g2
+       add     %%g2, 6, %%g2
+       andn    %%g2, %%g1, %%g2
+       wrpr    %%g2, 0, %%tick
+"              : /* no outputs */
+               : /* no inputs */
+               : "g1", "g2");
+
+               linux_timers->limit0 =
+                       (SUN5_LIMIT_ENABLE | SUN5_LIMIT_ZRESTART | SUN5_LIMIT_TOZERO |
+                        (SUN5_HZ_TO_LIMIT(HZ) & SUN5_LIMIT_CMASK));
 
                restore_flags(flags);
        }
+
        sti();
 }
 
-/* We use this nowhere else, so only define it's layout here. */
-struct sun5_timer {
-       volatile u32 count0, _unused0;
-       volatile u32 limit0, _unused1;
-       volatile u32 count1, _unused2;
-       volatile u32 limit1, _unused3;
-} *prom_timers;
+struct sun5_timer *prom_timers;
 
-static u32 prom_limit0, prom_limit1;
+static u64 prom_limit0, prom_limit1;
 
 static void map_prom_timers(void)
 {
index 89f63f78f8a8c4a440fdd2ba760f6d128640269a..afd5af8d0330babce1ece9b6672b0d750b6806e4 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
+/*  $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -50,9 +50,12 @@ asmlinkage int sys_idle(void)
                return -EPERM;
 
        /* endless idle loop with no priority at all */
+       current->priority = -100;
        current->counter = -100;
-       for (;;)
+       for (;;) {
+               run_task_queue(&tq_scheduler);
                schedule();
+       }
        return 0;
 }
 
@@ -61,42 +64,27 @@ asmlinkage int sys_idle(void)
 /*
  * the idle loop on a UltraMultiPenguin...
  */
-asmlinkage int sys_idle(void)
+asmlinkage int cpu_idle(void)
 {
-       if (current->pid != 0)
-               return -EPERM;
-
-       /* endless idle loop with no priority at all */
-       current->counter = -100;
-       schedule();
-       return 0;
+       current->priority = -100;
+       while(1) {
+               if(tq_scheduler) {
+                       lock_kernel();
+                       run_task_queue(&tq_scheduler);
+                       unlock_kernel();
+               }
+               current->counter = -100;
+               schedule();
+       }
 }
 
-/* This is being executed in task 0 'user space'. */
-int cpu_idle(void *unused)
+asmlinkage int sys_idle(void)
 {
-       volatile int *spap = &smp_process_available;
-       volatile int cval;
+       if(current->pid != 0)
+               return -EPERM;
 
-       while(1) {
-               if(0==*spap)
-                       continue;
-               cli();
-               /* Acquire exclusive access. */
-               while((cval = smp_swap(spap, -1)) == -1)
-                       while(*spap == -1)
-                               ;
-                if (0==cval) {
-                       /* ho hum, release it. */
-                       *spap = 0;
-                       sti();
-                        continue;
-                }
-               /* Something interesting happened, whee... */
-               *spap = (cval - 1);
-               sti();
-               idle();
-       }
+       cpu_idle();
+       return 0;
 }
 
 #endif
@@ -467,7 +455,11 @@ void fault_in_user_windows(struct pt_regs *regs)
  *       allocate the task_struct and kernel stack in
  *       do_fork().
  */
+#ifdef __SMP__
+extern void ret_from_smpfork(void);
+#else
 extern void ret_from_syscall(void);
+#endif
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                struct task_struct *p, struct pt_regs *regs)
@@ -485,7 +477,11 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
        child_trap_frame = ((char *)p) + stack_offset;
        memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size);
        p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
+#ifdef __SMP__
+       p->tss.kpc = ((unsigned long) ret_from_smpfork) - 0x8;
+#else
        p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
+#endif
        p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
        p->tss.cwp = regs->u_regs[UREG_G0];
        if(regs->tstate & TSTATE_PRIV) {
@@ -495,6 +491,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                p->tss.ctx = 0;
                p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
        } else {
+               if(current->tss.flags & SPARC_FLAG_32BIT) {
+                       sp &= 0x00000000ffffffff;
+                       regs->u_regs[UREG_FP] &= 0x00000000ffffffff;
+               }
                p->tss.kregs->u_regs[UREG_FP] = sp;
                p->tss.flags &= ~SPARC_FLAG_KTHREAD;
                p->tss.current_ds = USER_DS;
index 680baf7de709ca0f0164bb60c81853e4484d13a4..7eb47e97644bd5e950a19c278ff60aea762566e3 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.10 1997/07/08 11:07:47 jj Exp $
+/*  $Id: setup.c,v 1.11 1997/07/24 12:15:05 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -405,11 +405,7 @@ extern char *mmu_info(void);
 
 int get_cpuinfo(char *buffer)
 {
-#ifndef __SMP__
-       int cpuid=0;
-#else
-#error SMP not supported on sparc64 yet
-#endif
+       int cpuid=smp_processor_id();
 
        return sprintf(buffer, "cpu\t\t: %s\n"
             "fpu\t\t: %s\n"
index 88d7a8ecfd7fa2c44d3f8dd1af293d2a8e3b9bcf..77ccf40a0ad55f9b0c2fb2e6de7df0919b5f5025 100644 (file)
@@ -3,6 +3,26 @@
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tasks.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 
@@ -13,8 +33,9 @@ volatile int smp_processors_ready = 0;
 unsigned long cpu_present_map = 0;
 int smp_num_cpus = 1;
 int smp_threads_ready = 0;
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
 
-struct cpuinfo_sparc64 cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS];
 static unsigned char boot_cpu_id = 0;
 static int smp_activated = 0;
 
@@ -52,11 +73,11 @@ void smp_store_cpu_info(int id)
 
 void smp_commence(void)
 {
-       local_flush_cache_all();
-       local_flush_tlb_all();
+       flush_cache_all();
+       flush_tlb_all();
        smp_commenced = 1;
-       local_flush_cache_all();
-       local_flush_tlb_all();
+       flush_cache_all();
+       flush_tlb_all();
 }
 
 static void smp_setup_percpu_timer(void);
@@ -67,8 +88,8 @@ void smp_callin(void)
 {
        int cpuid = hard_smp_processor_id();
 
-       local_flush_cache_all();
-       local_flush_tlb_all();
+       flush_cache_all();
+       flush_tlb_all();
 
        smp_setup_percpu_timer();
 
@@ -76,7 +97,7 @@ void smp_callin(void)
        smp_store_cpu_info(cpuid);
        callin_flag = 1;
        __asm__ __volatile__("membar #Sync\n\t"
-                            "flush  %g6" : : : "memory");
+                            "flush  %%g6" : : : "memory");
 
        while(!task[cpuid])
                barrier();
@@ -103,11 +124,18 @@ int start_secondary(void *unused)
        return cpu_idle(NULL);
 }
 
+void cpu_panic(void)
+{
+       printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
+       panic("SMP bolixed\n");
+}
+
 extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+extern unsigned long sparc64_cpu_startup;
 
 void smp_boot_cpus(void)
 {
-       int cpucount = 0, i, first, prev;
+       int cpucount = 0, i;
 
        printk("Entering UltraSMPenguin Mode...\n");
        __sti();
@@ -133,15 +161,15 @@ void smp_boot_cpus(void)
                        continue;
 
                if(cpu_present_map & (1 << i)) {
-                       extern unsigned long sparc64_cpu_startup;
-                       unsigned long entry = (unsigned long)&sparc_cpu_startup;
                        struct task_struct *p;
                        int timeout;
 
                        kernel_thread(start_secondary, NULL, CLONE_PID);
                        p = task[++cpucount];
                        p->processor = i;
-                       prom_startcpu(linux_cpus[i].prom_node, entry, i);
+                       prom_startcpu(linux_cpus[i].prom_node,
+                                     ((unsigned long)&sparc64_cpu_startup),
+                                     ((unsigned long)p));
                        for(timeout = 0; timeout < 5000000; timeout++) {
                                if(cpu_callin_map[i])
                                        break;
@@ -190,49 +218,46 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
                barrier();
 }
 
-/* XXX Make it fast later. */
+static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
+{
+       u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
+
+       __asm__ __volatile__("
+       wrpr    %0, %1, %%pstate
+       wr      %%g0, %2, %%asi
+       stxa    %3, [0x40] %%asi
+       stxa    %4, [0x50] %%asi
+       stxa    %5, [0x60] %%asi
+       stxa    %%g0, [%6] %%asi
+       membar  #Sync"
+       : /* No outputs */
+       : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
+         "r" (data0), "r" (data1), "r" (data2), "r" (target));
+
+       /* NOTE: PSTATE_IE is still clear. */
+       do {
+               __asm__ __volatile__("ldxa [%%g0] %1, %0"
+                       : "=r" (result)
+                       : "i" (ASI_INTR_DISPATCH_STAT));
+       } while(result & 0x1);
+       __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+                            : : "r" (pstate));
+       if(result & 0x2)
+               panic("Penguin NACK's master!");
+}
+
 void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
 {
        if(smp_processors_ready) {
-               unsigned long mask;
-               u64 data0 = (((unsigned long)ctx)<<32 |
-                            (((unsigned long)func) & 0xffffffff));
-               u64 pstate;
+               unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+               u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
                int i, ncpus = smp_num_cpus;
 
                __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
-               mask = (cpu_present_map & ~(1 << smp_processor_id()));
                for(i = 0; i < ncpus; i++) {
-                       if(mask & (1 << i)) {
-                               u64 target = mid<<14 | 0x70;
-                               u64 result;
-
-                               __asm__ __volatile__("
-                               wrpr    %0, %1, %%pstate
-                               wrpr    %%g0, %2, %%asi
-                               stxa    %3, [0x40] %%asi
-                               stxa    %4, [0x50] %%asi
-                               stxa    %5, [0x60] %%asi
-                               stxa    %%g0, [%6] %7
-                               membar  #Sync"
-                               : /* No outputs */
-                               : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
-                                 "r" (data0), "r" (data1), "r" (data2),
-                                 "r" (target), "i" (ASI_UDB_INTR_W));
-
-                               /* NOTE: PSTATE_IE is still clear. */
-                               do {
-                                       __asm__ __volatile__("ldxa [%%g0] %1, %0",
-                                               : "=r" (result)
-                                               : "i" (ASI_INTR_DISPATCH_STAT));
-                               } while(result & 0x1);
-                               __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
-                                                    : : "r" (pstate));
-                               if(result & 0x2)
-                                       panic("Penguin NACK's master!");
-                       }
+                       if(mask & (1 << i))
+                               xcall_deliver(data0, data1, data2, pstate, i);
                }
-
                /* NOTE: Caller runs local copy on master. */
        }
 }
@@ -246,17 +271,19 @@ extern unsigned long xcall_flush_cache_all;
 void smp_flush_cache_all(void)
 {
        smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
+       __flush_cache_all();
 }
 
 void smp_flush_tlb_all(void)
 {
        smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+       __flush_tlb_all();
 }
 
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
        u32 ctx = mm->context & 0x1fff;
-       if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+       if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
                smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
        __flush_tlb_mm(ctx);
 }
@@ -265,7 +292,7 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
                         unsigned long end)
 {
        u32 ctx = mm->context & 0x1fff;
-       if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+       if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
                smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
        __flush_tlb_range(ctx, start, end);
 }
@@ -275,7 +302,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
        struct mm_struct *mm = vma->vm_mm;
        u32 ctx = mm->context & 0x1fff;
 
-       if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+       if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
                smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
        __flush_tlb_page(ctx, page);
 }
@@ -308,12 +335,12 @@ extern void update_one_process(struct task_struct *p, unsigned long ticks,
 void smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
        int cpu = smp_processor_id();
+       int user = user_mode(regs);
 
-       clear_profile_irq(cpu);
-       if(!user_mode(regs))
-               sparc_do_profile(regs->pc);
+       /* XXX clear_profile_irq(cpu); */
+       if(!user)
+               sparc64_do_profile(regs->tpc);
        if(!--prof_counter[cpu]) {
-               int user = user_mode(regs);
                if(current->pid) {
                        update_one_process(current, 1, user, !user);
                        if(--current->counter < 0) {
@@ -344,4 +371,5 @@ static void smp_setup_percpu_timer(void)
 int setup_profiling_timer(unsigned int multiplier)
 {
        /* XXX implement me */
+       return 0;
 }
index ad40a5fb5317e87bc2a7334cf36dd9d77261ce5e..df6a1c05e93456e9f837fa05c122b18f2e5e698c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.3 1997/06/17 13:25:29 jj Exp $
+/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
 
 #include <asm/oplib.h>
 #include <asm/mostek.h>
+#include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -35,11 +36,17 @@ static int set_rtc_mmss(unsigned long);
  * NOTE: On SUN5 systems the ticker interrupt comes in using 2
  *       interrupts, one at level14 and one with softint bit 0.
  */
-void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+extern struct sun5_timer *linux_timers;
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        /* last time the cmos clock got updated */
        static long last_rtc_update=0;
 
+       __asm__ __volatile__("ldx       [%0], %%g0"
+                            : /* no outputs */
+                            : "r" (&((linux_timers)->limit0)));
+
        do_timer(regs);
 
        /* Determine when to update the Mostek clock. */
@@ -239,14 +246,12 @@ __initfunc(static void clock_probe(void))
 
 __initfunc(void time_init(void))
 {
-       extern void init_timers(void (*func)(int, void *, struct pt_regs *));
        unsigned int year, mon, day, hour, min, sec;
        struct mostek48t02 *mregs;
 
        do_get_fast_time = do_gettimeofday;
 
        clock_probe();
-       init_timers(timer_interrupt);
 
        mregs = mstk48t02_regs;
        if(!mregs) {
@@ -266,6 +271,13 @@ __initfunc(void time_init(void))
        mregs->creg &= ~MSTK_CREG_READ;
 }
 
+extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+
+__initfunc(void sun4u_start_timers(void))
+{
+       init_timers(timer_interrupt);
+}
+
 static __inline__ unsigned long do_gettimeoffset(void)
 {
        unsigned long offset = 0;
@@ -286,16 +298,39 @@ static __inline__ unsigned long do_gettimeoffset(void)
 
 void do_gettimeofday(struct timeval *tv)
 {
-       unsigned long flags;
-
-       save_and_cli(flags);
-       *tv = xtime;
-       tv->tv_usec += do_gettimeoffset();
-       if(tv->tv_usec >= 1000000) {
-               tv->tv_usec -= 1000000;
-               tv->tv_sec++;
-       }
-       restore_flags(flags);
+       /* Load doubles must be used on xtime so that what we get
+        * is guarenteed to be atomic, this is why we can run this
+        * with interrupts on full blast.  Don't touch this... -DaveM
+        */
+       __asm__ __volatile__("
+       sethi   %hi(linux_timers), %o1
+       sethi   %hi(xtime), %g2
+       ldx     [%o1 + %lo(linux_timers)], %g3
+1:     ldd     [%g2 + %lo(xtime)], %o4
+       ldx     [%g3], %o1
+       ldd     [%g2 + %lo(xtime)], %o2
+       xor     %o4, %o2, %o2
+       xor     %o5, %o3, %o3
+       orcc    %o2, %o3, %g0
+       bne,pn  %icc, 1b
+        cmp    %o1, 0
+       bge,pt  %icc, 1f
+        sethi  %hi(tick), %o3
+       ld      [%o3 + %lo(tick)], %o3
+       sethi   %hi(0x1fffff), %o2
+       or      %o2, %lo(0x1fffff), %o2
+       add     %o5, %o3, %o5
+       and     %o1, %o2, %o1
+1:     add     %o5, %o1, %o5
+       sethi   %hi(1000000), %o2
+       or      %o2, %lo(1000000), %o2
+       cmp     %o5, %o2
+       bl,a,pn %icc, 1f
+        st     %o4, [%o0 + 0x0]
+       add     %o4, 0x1, %o4
+       sub     %o5, %o2, %o5
+       st      %o4, [%o0 + 0x0]
+1:     st      %o5, [%o0 + 0x4]");
 }
 
 void do_settimeofday(struct timeval *tv)
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
new file mode 100644 (file)
index 0000000..fe0df32
--- /dev/null
@@ -0,0 +1,197 @@
+/* $Id: trampoline.S,v 1.1 1997/07/24 14:47:53 davem Exp $
+ * trampoline.S: Jump start slave processors on sparc64.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/lsu.h>
+#include <asm/pstate.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/spitfire.h>
+#include <asm/asm_offsets.h>
+
+       .text
+       .globl          sparc64_cpu_startup
+sparc64_cpu_startup:
+       flushw
+       mov     (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
+       stxa    %g1, [%g0] ASI_LSU_CONTROL
+       wrpr    %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+       wrpr    %g0, 15, %pil
+
+       mov     %o0, %g6
+
+       sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+       sllx    %g5, 32, %g5
+       or      %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
+
+       sethi   %uhi(_PAGE_PADDR), %g3
+       or      %g3, %ulo(_PAGE_PADDR), %g3
+       sllx    %g3, 32, %g3
+       sethi   %hi(_PAGE_PADDR), %g7
+       or      %g7, %lo(_PAGE_PADDR), %g7
+       or      %g3, %g7, %g7
+
+       /* Find TLB entry we are executing out of. */
+       clr     %l0
+       set     0x1fff, %l2
+       rd      %pc, %l3
+       andn    %l3, %l2, %g2
+1:     ldxa    [%l0] ASI_ITLB_TAG_READ, %g1
+       nop
+       nop
+       nop
+       andn    %g1, %l2, %g1
+       cmp     %g1, %g2
+       be,a,pn %xcc, 2f
+        ldxa   [%l0] ASI_ITLB_DATA_ACCESS, %g1
+       cmp     %l0, (63 << 3)
+       blu,pt  %xcc, 1b
+        add    %l0, (1 << 3), %l0
+
+2:     nop
+       nop
+       nop
+       and     %g1, %g3, %g1
+       sub     %g1, %g2, %g1
+       or      %g5, %g1, %g5
+       clr     %l0
+       sethi   %hi(KERNBASE), %g3
+       sethi   %hi(KERNBASE<<1), %g7
+       mov     TLB_TAG_ACCESS, %l7
+1:     ldxa    [%l0] ASI_ITLB_TAG_READ, %g1
+       nop
+       nop
+       nop
+       andn    %g1, %l2, %g1
+       cmp     %g1, %g3
+       blu,pn  %xcc, 2f
+       cmp     %g1, %g7
+       bgeu,pn %xcc, 2f
+        nop
+       stxa    %g0, [%l7] ASI_IMMU
+       stxa    %g0, [%l0] ASI_ITLB_DATA_ACCESS
+2:     cmp     %l0, (63 << 3)
+       blu,pt  %xcc, 1b
+        add    %l0, (1 << 3), %l0
+
+       nop
+       nop
+       nop
+       clr     %l0
+1:     ldxa    [%l0] ASI_DTLB_TAG_READ, %g1
+       nop
+       nop
+       nop
+       andn    %g1, %l2, %g1
+       cmp     %g1, %g3
+       blu,pn  %xcc, 2f
+        cmp    %g1, %g7
+       bgeu,pn %xcc, 2f
+        nop
+       stxa    %g0, [%l7] ASI_DMMU
+       stxa    %g0, [%l0] ASI_DTLB_DATA_ACCESS
+2:     cmp     %l0, (63 << 3)
+       blu,pt  %xcc, 1b
+        add    %l0, (1 << 3), %l0
+
+       nop
+       nop
+       nop
+       sethi   %hi(KERNBASE), %g3
+       mov     (63 << 3), %g7
+       stxa    %g3, [%l7] ASI_DMMU
+       stxa    %g5, [%g7] ASI_DTLB_DATA_ACCESS
+       membar  #Sync
+       stxa    %g3, [%l7] ASI_IMMU
+       stxa    %g5, [%g7] ASI_ITLB_DATA_ACCESS
+       membar  #Sync
+       flush   %g6
+       membar  #Sync
+       b,pt    %xcc, 1f
+        nop
+1:     set     bounce, %g2
+       jmpl    %g2 + %g0, %g0
+        nop
+
+bounce:
+       mov     PRIMARY_CONTEXT, %g7
+       stxa    %g0, [%g7] ASI_DMMU
+       membar  #Sync
+       mov     SECONDARY_CONTEXT, %g7
+       stxa    %g0, [%g7] ASI_DMMU
+       membar  #Sync
+
+       sethi   %uhi(PAGE_OFFSET), %g4
+       sllx    %g4, 32, %g4
+
+       mov     TLB_TAG_ACCESS, %g2
+       stxa    %g3, [%g2] ASI_IMMU
+       stxa    %g3, [%g2] ASI_DMMU
+
+       mov     (63 << 3), %g7
+       ldxa    [%g7] ASI_ITLB_DATA_ACCESS, %g1
+       andn    %g1, (_PAGE_G), %g1
+       stxa    %g1, [%g7] ASI_ITLB_DATA_ACCESS
+       membar  #Sync
+
+       ldxa    [%g7] ASI_DTLB_DATA_ACCESS, %g1
+       andn    %g1, (_PAGE_G), %g1
+       stxa    %g1, [%g7] ASI_DTLB_DATA_ACCESS
+       membar  #Sync
+
+       flush   %g6
+       membar  #Sync
+
+       mov     1, %g5
+       sllx    %g5, (PAGE_SHIFT + 1), %g5
+       sub     %g5, (REGWIN_SZ + STACK_BIAS), %g5
+       add     %g6, %g5, %sp
+       mov     0, %fp
+
+       wrpr    %g0, 0, %wstate
+       wrpr    %g0, 0, %tl
+
+       /* Setup the trap globals, then we can resurface. */
+       rdpr    %pstate, %o1
+       mov     %g6, %o2
+       wrpr    %o1, (PSTATE_AG | PSTATE_IE), %pstate
+       sethi   %hi(sparc64_ttable_tl0), %g5
+       wrpr    %g5, %tba
+       mov     %o2, %g6
+
+       wrpr    %o1, (PSTATE_MG | PSTATE_IE), %pstate
+       sethi   %hi(0x1ff8), %g2
+       or      %g2, %lo(0x1ff8), %g2
+       ldx     [%o2 + AOFF_task_mm], %g6
+       ldx     [%g6 + AOFF_mm_pgd], %g6
+       clr     %g7
+
+       wrpr    %o1, (PSTATE_IG | PSTATE_IE), %pstate
+       sethi   %hi(ivector_to_mask), %g5
+       or      %g5, %lo(ivector_to_mask), %g1
+       mov     0x40, %g2
+
+       wrpr    %g0, 0, %wstate
+       wrpr    %o1, PSTATE_IE, %pstate
+
+       mov     TSB_REG, %o4
+       mov     1, %o5
+       stxa    %o5, [%o4] ASI_DMMU
+       stxa    %o5, [%o4] ASI_IMMU
+       membar  #Sync
+
+       wrpr    %g0, 0, %pil
+       or      %o1, PSTATE_IE, %o1
+       wrpr    %o1, 0, %pstate
+
+       call    smp_callin
+        nop
+       call    cpu_idle
+        mov    0, %o0
+       call    cpu_panic
+        nop
+1:     b,a,pt  %xcc, 1b
index a1154cb6d1a7e4dd56e3d09714c4181ac37be824..74054f63a920fe52aa8508c8e800a559fb024f1e 100644 (file)
@@ -1,77 +1,77 @@
-/* $Id: locks.S,v 1.2 1997/03/10 12:28:02 jj Exp $
+/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
  * locks.S: SMP low-level lock primitives on Sparc64.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <asm/asm_offsets.h>
 #include <asm/ptrace.h>
+#include <asm/smp.h>
 
        .text
-       .align  4
-
-       .globl  __spinlock_waitfor
-__spinlock_waitfor:
-1:     orcc    %g2, 0x0, %g0
-       bne     1b
-        ldub   [%g1], %g2
-       ldstub  [%g1], %g2
-       jmpl    %o7 - 12, %g0
-        mov    %g5, %o7
-
-       .globl  ___become_idt
-___become_idt:
-#if 0 /* Don't know how to do this on the Ultra yet... */
-#endif
-       jmpl    %o7 + 8, %g0
-        mov    %g5, %o7
+       .align          32
 
 ___lk_busy_spin:
-       orcc    %g2, 0, %g0
-       bne     ___lk_busy_spin
-        ldub   [%g1 + 0], %g2
-       b       1f
-        ldstub [%g1 + 0], %g2
+       orcc            %g2, 0, %g0
+       bne,pt          %icc, ___lk_busy_spin
+        ldub           [%g1 + 0], %g2
+       b,pt            %xcc, 1f
+        ldstub         [%g1 + 0], %g2
 
-       .globl  ___lock_kernel
+       .globl          ___lock_kernel
 ___lock_kernel:
-       addcc   %g2, -1, %g2
-       rdpr    %pil, %g3
-       bcs,a   9f
-        st     %g2, [%g6 + AOFF_task_lock_depth]
-       wrpr    15, %pil
-       ldstub  [%g1 + 0], %g2
-1:     orcc    %g2, 0, %g0
-       bne,a   ___lk_busy_spin
-        ldub   [%g1 + 0], %g2
-       ldub    [%g1 + 2], %g2
-       cmp     %g2, %g5
-       be      2f
-        stb    %g5, [%g1 + 1]
-       stb     %g5, [%g1 + 2]
-#ifdef __SMP__
-       /* XXX Figure out how to become interrupt receiver in SMP system. */
-#endif
-2:     mov     -1, %g2
-       st      %g2, [%g6 + AOFF_task_lock_depth]
-       wrpr    %g3, %pil
-9:     jmpl    %o7 + 0x8, %g0
-        mov    %g5, %o7
+       addcc           %g2, -1, %g2
+       rdpr            %pil, %g3
+       bcs,a,pn        %icc, 9f
+        st             %g2, [%g6 + AOFF_task_lock_depth]
+       wrpr            %g0, 15, %pil
+       ldstub          [%g1 + 0], %g2
+1:     brnz,a,pn       %g2, ___lk_busy_spin
+        ldub           [%g1 + 0], %g2
+       lduw            [%g6 + AOFF_task_processor], %g2
+       membar          #LoadLoad | #LoadStore
+       stb             %g2, [%g1 + 1]
+2:     mov             -1, %g2
+       st              %g2, [%g6 + AOFF_task_lock_depth]
+       wrpr            %g3, 0, %pil
+9:     jmpl            %o7 + 0x8, %g0
+        mov            %g5, %o7
+
+       .globl          ___lock_reacquire_kernel
+___lock_reacquire_kernel:
+       rdpr            %pil, %g3
+       wrpr            %g0, 15, %pil
+       st              %g2, [%g6 + AOFF_task_lock_depth]
+       ldstub          [%g1 + 0], %g2
+1:     brz,pt          %g2, 3f
+        ldub           [%g1 + 0], %g2
+2:     brnz,a,pt       %g2, 2b
+        ldub           [%g1 + 0], %g2
+       b,pt            %xcc, 1b
+        ldstub         [%g1 + 0], %g2
+3:     lduw            [%g6 + AOFF_task_processor], %g2
+       membar          #LoadLoad | #LoadStore
+       stb             %g2, [%g1 + 1]
+       wrpr            %g3, 0, %pil
+       jmpl            %o7 + 0x8, %g0
+        mov            %g5, %o7
 
 #undef NO_PROC_ID
 #define NO_PROC_ID     0xff
 
-       .globl  ___unlock_kernel
+       .globl          ___unlock_kernel
 ___unlock_kernel:
-       addcc   %g2, 1, %g2
-       rdpr    %pil, %g3
-       bne,a   1f
-        st     %g2, [%g6 + AOFF_task_lock_depth]
-       wrpr    15, %pil
-       mov     NO_PROC_ID, %g2
-       stb     %g2, [%g1 + 1]
-       stb     %g0, [%g1 + 0]
-       st      %g0, [%g6 + AOFF_task_lock_depth]
-       wrpr    %g3, %pil
-1:     jmpl    %o7 + 0x8, %g0
-        mov    %g5, %o7
+       addcc           %g2, 1, %g2
+       rdpr            %pil, %g3
+       bne,a,pn        %icc, 1f
+        stw            %g2, [%g6 + AOFF_task_lock_depth]
+       wrpr            15, %pil
+       mov             NO_PROC_ID, %g2
+       stb             %g2, [%g1 + 1]
+       membar          #StoreStore | #LoadStore
+       stb             %g0, [%g1 + 0]
+       stw             %g0, [%g6 + AOFF_task_lock_depth]
+       wrpr            %g3, 0, %pil
+1:     jmpl            %o7 + 0x8, %g0
+        mov            %g5, %o7
        
index dddf3153bb2561e98cf0e4fa1c0d579593564698..72f4fa07937b7409418487a1c81f8767eb8230d6 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.3 1997/06/27 14:53:38 jj Exp $
+# $Id: Makefile,v 1.4 1997/07/24 12:15:08 davem Exp $
 # Makefile for the linux Sparc64-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -7,12 +7,24 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
+ifdef SMP
+
+.S.s:
+       $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
 .S.s:
        $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
 
 .S.o:
        $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
+endif
+
 O_TARGET := mm.o
 O_OBJS   := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o
 
index a8d903b256558eff11f0a5ff7d9c0204620d3086..386c8540f79e083369dffb5722653bf017560448 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.39 1997/07/07 02:50:57 davem Exp $
+/*  $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -431,8 +431,17 @@ void prom_reload_locked(void)
        membar("#Sync");
 }
 
+void __flush_cache_all(void)
+{
+       unsigned long va;
+
+       flushw_all();
+       for(va =  0; va < (PAGE_SIZE << 1); va += 32)
+               spitfire_put_icache_tag(va, 0x0);
+}
+
 /* If not locked, zap it. */
-void flush_tlb_all(void)
+void __flush_tlb_all(void)
 {
        unsigned long flags;
        int i;
index e40b4635f0f959db888893f89566fff933a5fcd7..18f9a363d5577a80f53b29ef2b76ae922bb24c56 100644 (file)
@@ -1,10 +1,11 @@
-/* $Id: ultra.S,v 1.8 1997/07/15 05:35:50 davem Exp $
+/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <asm/asi.h>
+#include <asm/pgtable.h>
 #include <asm/spitfire.h>
 
        /* All callers check mm->context != NO_CONTEXT for us. */
index a4aea63b84504faa72ccaeeec79582158f02a8b4..40b33da4bf54441c1b0dafd5fd786717f89d5ae8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.6 1997/03/18 17:59:59 jj Exp $
+/* $Id: console.c,v 1.7 1997/07/19 08:28:29 ecd Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -88,6 +88,7 @@ prom_query_input_device()
        if(strncmp(propb, "serial", sizeof("serial")))
                return PROMDEV_I_UNK;
        /* FIXME: Is there any better way how to find out? */   
+       memset(propb, 0, sizeof(propb));
        st_p = prom_finddevice ("/options");
        prom_getproperty(st_p, "input-device", propb, sizeof(propb));
        if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
@@ -116,6 +117,7 @@ prom_query_output_device()
        if(strncmp("serial", propb, sizeof("serial")))
                return PROMDEV_O_UNK;
        /* FIXME: Is there any better way how to find out? */   
+       memset(propb, 0, sizeof(propb));
        st_p = prom_finddevice ("/options");
        prom_getproperty(st_p, "output-device", propb, sizeof(propb));
        if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
index 8b738fd41a88893be363f80258809ed6e058849d..9720f1a706677cbdebe2961349a814cfcb22e06e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.8 1997/07/14 23:45:28 davem Exp $
+/* $Id: misc.c,v 1.9 1997/07/24 12:15:11 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -135,7 +135,7 @@ void prom_set_trap_table(unsigned long tba)
 }
 
 #ifdef __SMP__
-void prom_start_cpu(int cpunode, unsigned long pc, unsigned long o0)
+void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
 {
        p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
 }
index 18de40debe77916978ff898fdde3e1492e4a3b5e..0703b5cd7d92243890647152e53e1b4fe3a870bb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.10 1997/06/27 04:18:30 davem Exp $
+/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -6,6 +6,8 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/string.h>
 
 #include <asm/openprom.h>
index 740a3780a66bcb0ee412b6934718eb28ea67d7eb..e14cf09c780215e329c43142be7086c977dd24a2 100644 (file)
@@ -370,7 +370,7 @@ static void redo_acsi_request( void );
 static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
                        cmd, unsigned long arg );
 static int acsi_open( struct inode * inode, struct file * filp );
-static void acsi_release( struct inode * inode, struct file * file );
+static int acsi_release( struct inode * inode, struct file * file );
 static void acsi_prevent_removal( int target, int flag );
 static int acsi_change_blk_size( int target, int lun);
 static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
@@ -1200,7 +1200,7 @@ static int acsi_open( struct inode * inode, struct file * filp )
  * be forgotten about...
  */
 
-static void acsi_release( struct inode * inode, struct file * file )
+static int acsi_release( struct inode * inode, struct file * file )
 {
        int device;
 
@@ -1210,6 +1210,7 @@ static void acsi_release( struct inode * inode, struct file * file )
        if (--access_count[device] == 0 && acsi_info[device].removable)
                acsi_prevent_removal(device, 0);
        MOD_DEC_USE_COUNT;
+       return( 0 );
 }
 
 /*
@@ -1821,7 +1822,7 @@ void cleanup_module(void)
 {
        del_timer( &acsi_timer );
        blk_dev[MAJOR_NR].request_fn = 0;
-       free_pages( acsi_buffer, ACSI_BUFFER_ORDER );
+       free_pages( (unsigned long)acsi_buffer, ACSI_BUFFER_ORDER );
 
        if (unregister_blkdev( MAJOR_NR, "ad" ) != 0)
                printk( KERN_ERR "acsi: cleanup_module failed\n");
index da9af49b01377cea6f97075375329532d75bcb9a..97957c0eae9532c3a82c397d9b644a577334ad46 100644 (file)
@@ -117,7 +117,9 @@ static char slmreqsense_cmd[6] = { 0x03, 0, 0, 0, 0, 0 };
 static char slmprint_cmd[6]    = { 0x0a, 0, 0, 0, 0, 0 };
 static char slminquiry_cmd[6]  = { 0x12, 0, 0, 0, 0, 0x80 };
 static char slmmsense_cmd[6]   = { 0x1a, 0, 0, 0, 255, 0 };
+#if 0
 static char slmmselect_cmd[6]  = { 0x15, 0, 0, 0, 0, 0 };
+#endif
 
 
 #define        MAX_SLM         2
@@ -262,11 +264,13 @@ static long slm_write( struct inode *node, struct file *file, const char *buf,
 static int slm_ioctl( struct inode *inode, struct file *file, unsigned int
                       cmd, unsigned long arg );
 static int slm_open( struct inode *inode, struct file *file );
-static void slm_release( struct inode *inode, struct file *file );
+static int slm_release( struct inode *inode, struct file *file );
 static int slm_req_sense( int device );
 static int slm_mode_sense( int device, char *buffer, int abs_flag );
+#if 0
 static int slm_mode_select( int device, char *buffer, int len, int
                             default_flag );
+#endif
 static int slm_get_pagesize( int device, int *w, int *h );
 
 /************************* End of Prototypes **************************/
@@ -794,7 +798,7 @@ static int slm_open( struct inode *inode, struct file *file )
 }
 
 
-static void slm_release( struct inode *inode, struct file *file )
+static int slm_release( struct inode *inode, struct file *file )
 
 {      int device;
        struct slm *sip;
@@ -806,6 +810,8 @@ static void slm_release( struct inode *inode, struct file *file )
                sip->wbusy = 0;
        if (file->f_mode & 1)
                sip->rbusy = 0;
+       
+       return( 0 );
 }
 
 
@@ -876,6 +882,8 @@ static int slm_mode_sense( int device, char *buffer, int abs_flag )
 }
 
 
+#if 0
+/* currently unused */
 static int slm_mode_select( int device, char *buffer, int len,
                                                        int default_flag )
 
@@ -911,6 +919,7 @@ static int slm_mode_select( int device, char *buffer, int len,
        stdma_release();
        return( rv );
 }
+#endif
 
 
 static int slm_get_pagesize( int device, int *w, int *h )
index 0ef43d10144d4a498d1d3c9d64bcf4278aaa1e6b..65407caf6833aeb21a2fc94ab1a63e0b2b8c5b38 100644 (file)
@@ -99,5 +99,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
   tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
 fi
 bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'PC joystick support' CONFIG_JOYSTICK
 endmenu
index bdc6ff892e221ec82fbc21a2d8548e641ee26c22..2f734132dd03d0784071510aed3a1f4bb469353f 100644 (file)
@@ -261,6 +261,16 @@ M = y
 L_OBJS += rtc.o
 endif
 
+ifeq ($(CONFIG_NVRAM),y)
+M = y
+L_OBJS += nvram.o
+else
+  ifeq ($(CONFIG_NVRAM),m)
+    MM = m
+    M_OBJS += nvram.o
+  endif
+endif
+
 ifeq ($(CONFIG_QIC02_TAPE),y)
 L_OBJS += tpqic02.o
 else
index 7db3b5dba1145f04d1d195fc80558c48742451aa..4a5bea1953313fffd5538669cddfe5fe7738eee4 100644 (file)
@@ -221,8 +221,7 @@ fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
        if (remap_page_range(vma->vm_start, vma->vm_offset,
                             vma->vm_end - vma->vm_start, vma->vm_page_prot))
                return -EAGAIN;
-       vma->vm_inode = inode;
-       atomic_inc(&inode->i_count);
+       vma->vm_dentry = dget(file->f_dentry);
        return 0;
 }
 
index 66523964a5a9b89162e22a2a2bc54629b1d3a740..4506284cff2fbb711f46c2924af938689ccf50bf 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/kbd_diacr.h>
 #include <linux/vt_kern.h>
 #include <linux/kbd_ll.h>
+#include <linux/sysrq.h>
 
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
@@ -148,8 +149,6 @@ static unsigned char handle_diacr(unsigned char);
 struct pt_regs * kbd_pt_regs;
 
 #ifdef CONFIG_MAGIC_SYSRQ
-#define SYSRQ_KEY 0x54
-extern void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
 static int sysrq_pressed;
 #endif
 
@@ -239,7 +238,7 @@ void handle_scancode(unsigned char scancode)
                return;
        } else if (sysrq_pressed) {
                if (!up_flag)
-                       handle_sysrq(keycode, kbd_pt_regs, kbd, tty);
+                       handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
                return;
        }
 #endif
index 0635035956dfbc2b5c62e962a5f280f2ee3e0c0e..6e9eb576605491b68b96bab83dc12b1c44720a31 100644 (file)
@@ -132,6 +132,10 @@ static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_str
         */
        if (x86 > 3 && offset >= __pa(high_memory))
                pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#endif
+#ifdef __powerpc__
+       if (offset >= __pa(high_memory))
+               pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
 #endif
        if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
                return -EAGAIN;
index 13829cd01bd87c9e8f287f82cd6e572c565bef17..dac4203540463e4c287a54bfdcb0ac0f989d2c96 100644 (file)
@@ -74,6 +74,7 @@ extern void wdt_init(void);
 extern void pcwatchdog_init(void);
 extern int rtc_init(void);
 extern int dsp56k_init(void);
+extern int nvram_init(void);
 
 #ifdef CONFIG_PROC_FS
 static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -242,6 +243,9 @@ __initfunc(int misc_init(void))
 #ifdef CONFIG_ATARI_DSP56K
        dsp56k_init();
 #endif
+#ifdef CONFIG_NVRAM
+       nvram_init();
+#endif
 #endif /* !MODULE */
        if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
                printk("unable to get major %d for misc devices\n",
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
new file mode 100644 (file)
index 0000000..287f6ff
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * CMOS/NV-RAM driver for Linux
+ *
+ * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ * idea by and with help from Richard Jelinek <rj@suse.de>
+ *
+ * This driver allows you to access the contents of the non-volatile memory in
+ * the mc146818rtc.h real-time clock. This chip is built into all PCs and into
+ * many Atari machines. In the former it's called "CMOS-RAM", in the latter
+ * "NVRAM" (NV stands for non-volatile).
+ *
+ * The data are supplied as a (seekable) character device, /dev/nvram. The
+ * size of this file is 50, the number of freely available bytes in the memory
+ * (i.e., not used by the RTC itself).
+ * 
+ * Checksums over the NVRAM contents are managed by this driver. In case of a
+ * bad checksum, reads and writes return -EIO. The checksum can be initialized
+ * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or
+ * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
+ * again; use with care!)
+ *
+ * This file also provides some functions for other parts of the kernel that
+ * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}.
+ * Obviously this can be used only if this driver is always configured into
+ * the kernel and is not a module. Since the functions are used by some Atari
+ * drivers, this is the case on the Atari.
+ *
+ */
+
+#define NVRAM_VERSION          "1.0"
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#define PC             1
+#define ATARI  2
+
+/* select machine configuration */
+#if defined(CONFIG_ATARI)
+#define MACH ATARI
+#elif defined(__i386__) /* and others?? */
+#define MACH PC
+#else
+#error Cannot build nvram driver for this machine configuration.
+#endif
+
+#if MACH == PC
+
+/* RTC in a PC */
+#define CHECK_DRIVER_INIT() 1
+
+/* On PCs, the checksum is built only over bytes 2..31 */
+#define PC_CKS_RANGE_START     2
+#define PC_CKS_RANGE_END       31
+#define PC_CKS_LOC                     32
+
+#define        mach_check_checksum     pc_check_checksum
+#define        mach_set_checksum       pc_set_checksum
+#define        mach_proc_infos         pc_proc_infos
+
+#endif
+
+#if MACH == ATARI
+
+/* Special parameters for RTC in Atari machines */
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#define RTC_PORT(x)                    (TT_RTC_BAS + 2*(x))
+#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
+
+/* On Ataris, the checksum is over all bytes except the checksum bytes
+ * themselves; these are at the very end */
+#define ATARI_CKS_RANGE_START  0
+#define ATARI_CKS_RANGE_END            47
+#define ATARI_CKS_LOC                  48
+
+#define        mach_check_checksum     atari_check_checksum
+#define        mach_set_checksum       atari_set_checksum
+#define        mach_proc_infos         atari_proc_infos
+
+#endif
+
+/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
+ * interrupts disabled. Due to the index-port/data-port design of the RTC, we
+ * don't want two different things trying to get to it at once. (e.g. the
+ * periodic 11 min sync from time.c vs. this driver.)
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/mc146818rtc.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+
+static int nvram_open_cnt = 0; /* #times opened */
+static int nvram_open_mode;            /* special open modes */
+#define        NVRAM_WRITE             1               /* opened for writing (exclusive) */
+#define        NVRAM_EXCL              2               /* opened with O_EXCL */
+
+#define        RTC_FIRST_BYTE          14      /* RTC register number of first NVRAM byte */
+#define        NVRAM_BYTES                     50      /* number of NVRAM bytes */
+
+
+static int mach_check_checksum( void );
+static void mach_set_checksum( void );
+#ifdef CONFIG_PROC_FS
+static int mach_proc_infos( unsigned char *contents, char *buffer, int *len,
+                                                       off_t *begin, off_t offset, int size );
+#endif
+
+
+/*
+ * These are the internal NVRAM access functions, which do NOT disable
+ * interrupts and do not check the checksum. Both tasks are left to higher
+ * level function, so they need to be done only once per syscall.
+ */
+
+static __inline__ unsigned char nvram_read_int( int i )
+{
+       return( CMOS_READ( RTC_FIRST_BYTE+i ) );
+}
+
+static __inline__ void nvram_write_int( unsigned char c, int i )
+{
+       CMOS_WRITE( c, RTC_FIRST_BYTE+i );
+}
+
+static __inline__ int nvram_check_checksum_int( void )
+{
+       return( mach_check_checksum() );
+}
+
+static __inline__ void nvram_set_checksum_int( void )
+{
+       mach_set_checksum();
+}
+
+#if MACH == ATARI
+
+/*
+ * These non-internal functions are provided to be called by other parts of
+ * the kernel. It's up to the caller to ensure correct checksum before reading
+ * or after writing (needs to be done only once).
+ *
+ * They're only built if CONFIG_ATARI is defined, because Atari drivers use
+ * them. For other configurations (PC), the rest of the kernel can't rely on
+ * them being present (this driver couldn't be configured at all, or as a
+ * module), so they access config information themselves.
+ */
+
+unsigned char nvram_read_byte( int i )
+{
+       unsigned long flags;
+       unsigned char c;
+
+       save_flags(flags);
+       cli();
+       c = nvram_read_int( i );
+       restore_flags(flags);
+       return( c );
+}
+
+void nvram_write_byte( unsigned char c, int i )
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       nvram_write_int( c, i );
+       restore_flags(flags);
+}
+
+int nvram_check_checksum( void )
+{
+       unsigned long flags;
+       int rv;
+
+       save_flags(flags);
+       cli();
+       rv = nvram_check_checksum_int();
+       restore_flags(flags);
+       return( rv );
+}
+
+void nvram_set_checksum( void )
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       nvram_set_checksum_int();
+       restore_flags(flags);
+}
+
+#endif /* MACH == ATARI */
+
+
+/*
+ * The are the file operation function for user access to /dev/nvram
+ */
+
+static long long nvram_llseek( struct inode *inode, struct file *file,
+                                                          loff_t offset, int origin )
+{
+       switch( origin ) {
+         case 0:
+               /* nothing to do */
+               break;
+         case 1:
+               offset += file->f_pos;
+               break;
+         case 2:
+               offset += NVRAM_BYTES;
+               break;
+       }
+       return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
+}
+
+static long nvram_read( struct inode * inode, struct file * file,
+                                               char * buf, unsigned long count )
+{
+       unsigned long flags;
+       unsigned i = file->f_pos;
+       char *tmp = buf;
+
+       save_flags(flags);
+       cli();
+       
+       if (!nvram_check_checksum_int()) {
+               restore_flags(flags);
+               return( -EIO );
+       }
+
+       for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp )
+               put_user( nvram_read_int(i), tmp );
+       file->f_pos = i;
+
+       restore_flags(flags);
+       return( tmp - buf );
+}
+
+static long nvram_write( struct inode * inode, struct file * file,
+                                                const char * buf, unsigned long count )
+{
+       unsigned long flags;
+       unsigned i = file->f_pos;
+       const char *tmp = buf;
+       char c;
+
+       save_flags(flags);
+       cli();
+       
+       if (!nvram_check_checksum_int()) {
+               restore_flags(flags);
+               return( -EIO );
+       }
+
+       for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp ) {
+               get_user( c, tmp );
+               nvram_write_int( c, i );
+       }
+       nvram_set_checksum_int();
+       file->f_pos = i;
+
+       restore_flags(flags);
+       return( tmp - buf );
+}
+
+static int nvram_ioctl( struct inode *inode, struct file *file,
+                                               unsigned int cmd, unsigned long arg )
+{
+       unsigned long flags;
+       int i;
+       
+       switch( cmd ) {
+
+         case NVRAM_INIT:                      /* initialize NVRAM contents and checksum */
+               if (!suser())
+                       return( -EACCES );
+
+               save_flags(flags);
+               cli();
+
+               for( i = 0; i < NVRAM_BYTES; ++i )
+                       nvram_write_int( 0, i );
+               nvram_set_checksum_int();
+               
+               restore_flags(flags);
+               return( 0 );
+         
+         case NVRAM_SETCKS:            /* just set checksum, contents unchanged
+                                                                * (maybe useful after checksum garbaged
+                                                                * somehow...) */
+               if (!suser())
+                       return( -EACCES );
+
+               save_flags(flags);
+               cli();
+               nvram_set_checksum_int();
+               restore_flags(flags);
+               return( 0 );
+
+         default:
+               return( -EINVAL );
+       }
+}
+
+static int nvram_open( struct inode *inode, struct file *file )
+{
+       if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
+               (nvram_open_mode & NVRAM_EXCL) ||
+               ((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE)))
+               return( -EBUSY );
+
+       if (file->f_flags & O_EXCL)
+               nvram_open_mode |= NVRAM_EXCL;
+       if (file->f_mode & 2)
+               nvram_open_mode |= NVRAM_WRITE;
+       nvram_open_cnt++;
+       MOD_INC_USE_COUNT;
+       return( 0 );
+}
+
+static int nvram_release( struct inode *inode, struct file *file )
+{
+       nvram_open_cnt--;
+       if (file->f_flags & O_EXCL)
+               nvram_open_mode &= ~NVRAM_EXCL;
+       if (file->f_mode & 2)
+               nvram_open_mode &= ~NVRAM_WRITE;
+
+       MOD_DEC_USE_COUNT;
+       return( 0 );
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+struct proc_dir_entry *proc_nvram;
+
+static int nvram_read_proc( char *buffer, char **start, off_t offset,
+                                                       int size, int *eof, void *data )
+{
+       unsigned long flags;
+       unsigned char contents[NVRAM_BYTES];
+    int i, len = 0;
+    off_t begin = 0;
+       
+       save_flags(flags);
+       cli();
+       for( i = 0; i < NVRAM_BYTES; ++i )
+               contents[i] = nvram_read_int( i );
+       restore_flags(flags);
+       
+       *eof = mach_proc_infos( contents, buffer, &len, &begin, offset, size );
+
+    if (offset >= begin + len)
+               return( 0 );
+    *start = buffer + (begin - offset);
+    return( size < begin + len - offset ? size : begin + len - offset );
+       
+}
+
+/* This macro frees the machine specific function from bounds checking and
+ * this like that... */
+#define        PRINT_PROC(fmt,args...)                                                 \
+       do {                                                                                            \
+               *len += sprintf( buffer+*len, fmt, ##args );    \
+               if (*begin + *len > offset + size)                              \
+                       return( 0 );                                                            \
+               if (*begin + *len < offset) {                                   \
+                       *begin += *len;                                                         \
+                       *len = 0;                                                                       \
+               }                                                                                               \
+       } while(0)
+
+#endif
+
+static struct file_operations nvram_fops = {
+       nvram_llseek,
+       nvram_read,
+       nvram_write,
+       NULL,                   /* No readdir */
+       NULL,                   /* No poll */
+       nvram_ioctl,
+       NULL,                   /* No mmap */
+       nvram_open,
+       nvram_release
+};
+
+static struct miscdevice nvram_dev = {
+       NVRAM_MINOR,
+       "nvram",
+       &nvram_fops
+};
+
+
+__initfunc(int nvram_init(void))
+{
+       /* First test whether the driver should init at all */
+       if (!CHECK_DRIVER_INIT())
+           return( -ENXIO );
+
+       printk( "Non-volatile memory driver v%s\n", NVRAM_VERSION );
+       misc_register( &nvram_dev );
+#ifdef CONFIG_PROC_FS
+       if ((proc_nvram = create_proc_entry( "nvram", 0, 0 )))
+               proc_nvram->read_proc = nvram_read_proc;
+#endif
+       
+       return( 0 );
+}
+
+#ifdef MODULE
+int init_module (void)
+{
+       return( nvram_init() );
+}
+
+void cleanup_module (void)
+{
+#ifdef CONFIG_PROC_FS
+       if (proc_nvram)
+               remove_proc_entry( "nvram", 0 );
+#endif
+       misc_deregister( &nvram_dev );
+}
+#endif
+
+
+/*
+ * Machine specific functions
+ */
+
+
+#if MACH == PC
+
+static int pc_check_checksum( void )
+{
+       int i;
+       unsigned short sum = 0;
+       
+       for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
+               sum += nvram_read_int( i );
+       return( (sum & 0xffff) ==
+                       ((nvram_read_int(PC_CKS_LOC) << 8) |
+                        nvram_read_int(PC_CKS_LOC+1)) );
+}
+
+static void pc_set_checksum( void )
+{
+       int i;
+       unsigned short sum = 0;
+       
+       for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
+               sum += nvram_read_int( i );
+       nvram_write_int( sum >> 8, PC_CKS_LOC );
+       nvram_write_int( sum & 0xff, PC_CKS_LOC+1 );
+}
+
+#ifdef CONFIG_PROC_FS
+
+static char *floppy_types[] = {
+       "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M"
+};
+
+static char *gfx_types[] = {
+       "EGA, VGA, ... (with BIOS)",
+       "CGA (40 cols)",
+       "CGA (80 cols)",
+       "monochrome",
+};
+
+static int pc_proc_infos( unsigned char *nvram, char *buffer, int *len,
+                                                 off_t *begin, off_t offset, int size )
+{
+       unsigned long flags;
+       int checksum;
+       int type;
+
+       save_flags(flags);
+       cli();
+       checksum = nvram_check_checksum_int();
+       restore_flags(flags);
+       
+       PRINT_PROC( "Checksum status: %svalid\n", checksum ? "" : "not " );
+
+       PRINT_PROC( "# floppies     : %d\n",
+                               (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0 );
+       PRINT_PROC( "Floppy 0 type  : " );
+       type = nvram[2] >> 4;
+       if (type < sizeof(floppy_types)/sizeof(*floppy_types))
+               PRINT_PROC( "%s\n", floppy_types[type] );
+       else
+               PRINT_PROC( "%d (unknown)\n", type );
+       PRINT_PROC( "Floppy 1 type  : " );
+       type = nvram[2] & 0x0f;
+       if (type < sizeof(floppy_types)/sizeof(*floppy_types))
+               PRINT_PROC( "%s\n", floppy_types[type] );
+       else
+               PRINT_PROC( "%d (unknown)\n", type );
+
+       PRINT_PROC( "HD 0 type      : " );
+       type = nvram[4] >> 4;
+       if (type)
+               PRINT_PROC( " %02x\n", type == 0x0f ? nvram[11] : type );
+       else
+               PRINT_PROC( "none\n" );
+
+       PRINT_PROC( "HD 1 type      : " );
+       type = nvram[4] & 0x0f;
+       if (type)
+               PRINT_PROC( " %02x\n", type == 0x0f ? nvram[12] : type );
+       else
+               PRINT_PROC( "none\n" );
+
+       PRINT_PROC( "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+                               nvram[18] | (nvram[19] << 8),
+                               nvram[20], nvram[25],
+                               nvram[21] | (nvram[22] << 8),
+                               nvram[23] | (nvram[24] << 8) );
+       PRINT_PROC( "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+                               nvram[39] | (nvram[40] << 8),
+                               nvram[41], nvram[46],
+                               nvram[42] | (nvram[43] << 8),
+                               nvram[44] | (nvram[45] << 8) );
+
+       PRINT_PROC( "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8) );
+       PRINT_PROC( "Extended memory: %d kB (configured), %d kB (tested)\n",
+                               nvram[9] | (nvram[10] << 8),
+                               nvram[34] | (nvram[35] << 8) );
+
+       PRINT_PROC( "Gfx adapter    : %s\n", gfx_types[ (nvram[6] >> 4)&3 ] );
+
+       PRINT_PROC( "FPU            : %sinstalled\n",
+                               (nvram[6] & 2) ? "" : "not " );
+       
+       return( 1 );
+}
+#endif
+
+#endif /* MACH == PC */
+
+#if MACH == ATARI
+
+static int atari_check_checksum( void )
+{
+       int i;
+       unsigned char sum = 0;
+       
+       for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
+               sum += nvram_read_int( i );
+       return( nvram_read_int( ATARI_CKS_LOC ) == (~sum & 0xff) &&
+                       nvram_read_int( ATARI_CKS_LOC+1 ) == (sum & 0xff) );
+}
+
+static void atari_set_checksum( void )
+{
+       int i;
+       unsigned char sum = 0;
+       
+       for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
+               sum += nvram_read_int( i );
+       nvram_write_int( ~sum, ATARI_CKS_LOC );
+       nvram_write_int( sum, ATARI_CKS_LOC+1 );
+}
+
+#ifdef CONFIG_PROC_FS
+
+static struct {
+       unsigned char val;
+       char *name;
+} boot_prefs[] = {
+       { 0x80, "TOS" },
+       { 0x40, "ASV" },
+       { 0x20, "NetBSD (?)" },
+       { 0x10, "Linux" },
+       { 0x00, "unspecified" }
+};
+
+static char *languages[] = {
+       "English (US)",
+       "German",
+       "French",
+       "English (UK)",
+       "Spanish",
+       "Italian",
+       "6 (undefined)",
+       "Swiss (French)",
+       "Swiss (German)"
+};
+
+static char *dateformat[] = {
+       "MM%cDD%cYY",
+       "DD%cMM%cYY",
+       "YY%cMM%cDD",
+       "YY%cDD%cMM",
+       "4 (undefined)",
+       "5 (undefined)",
+       "6 (undefined)",
+       "7 (undefined)"
+};
+
+static char *colors[] = {
+       "2", "4", "16", "256", "65536", "??", "??", "??"
+};
+
+#define fieldsize(a)   (sizeof(a)/sizeof(*a))
+
+static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
+                                                        off_t *begin, off_t offset, int size )
+{
+       int checksum = nvram_check_checksum();
+       int i;
+       unsigned vmode;
+       
+       PRINT_PROC( "Checksum status  : %svalid\n", checksum ? "" : "not " );
+
+       PRINT_PROC( "Boot preference  : " );
+       for( i = fieldsize(boot_prefs)-1; i >= 0; --i ) {
+               if (nvram[1] == boot_prefs[i].val) {
+                       PRINT_PROC( "%s\n", boot_prefs[i].name );
+                       break;
+               }
+       }
+       if (i < 0)
+               PRINT_PROC( "0x%02x (undefined)\n", nvram[1] );
+
+       PRINT_PROC( "SCSI arbitration : %s\n", (nvram[16] & 0x80) ? "on" : "off" );
+       PRINT_PROC( "SCSI host ID     : " );
+       if (nvram[16] & 0x80)
+               PRINT_PROC( "%d\n", nvram[16] & 7 );
+       else
+               PRINT_PROC( "n/a\n" );
+
+       /* the following entries are defined only for the Falcon */
+       if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
+               return;
+
+       PRINT_PROC( "OS language      : " );
+       if (nvram[6] < fieldsize(languages))
+               PRINT_PROC( "%s\n", languages[nvram[6]] );
+       else
+               PRINT_PROC( "%u (undefined)\n", nvram[6] );
+       PRINT_PROC( "Keyboard language: " );
+       if (nvram[7] < fieldsize(languages))
+               PRINT_PROC( "%s\n", languages[nvram[7]] );
+       else
+               PRINT_PROC( "%u (undefined)\n", nvram[7] );
+       PRINT_PROC( "Date format      : " );
+       PRINT_PROC( dateformat[nvram[8]&7],
+                               nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/' );
+       PRINT_PROC( ", %dh clock\n", nvram[8] & 16 ? 24 : 12 );
+       PRINT_PROC( "Boot delay       : " );
+       if (nvram[10] == 0)
+               PRINT_PROC( "default" );
+       else
+               PRINT_PROC( "%ds%s\n", nvram[10],
+                                       nvram[10] < 8 ? ", no memory test" : "" );
+
+       vmode = (nvram[14] << 8) || nvram[15];
+       PRINT_PROC( "Video mode       : %s colors, %d columns, %s %s monitor\n",
+                               colors[vmode & 7],
+                               vmode & 8 ? 80 : 40,
+                               vmode & 16 ? "VGA" : "TV",
+                               vmode & 32 ? "PAL" : "NTSC" );
+       PRINT_PROC( "                   %soverscan, compat. mode %s%s\n",
+                               vmode & 64 ? "" : "no ",
+                               vmode & 128 ? "on" : "off",
+                               vmode & 256 ?
+                                 (vmode & 16 ? ", line doubling" : ", half screen") : "" );
+               
+       return( 1 );
+}
+#endif
+
+#endif /* MACH == ATARI */
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
index 7a6b8cde067ce29d26d0a2b9de4eea283fbdf9c9..d9c5ac453bc579bc0c28c088b792bd2e1b22e674 100644 (file)
@@ -492,7 +492,7 @@ static int close_pad(struct inode * inode, struct file * file)
 {
        fasync_pad(inode, file, 0);
        if (--active)
-               return;
+               return 0;
        outb(0x30, current_params.io+2);        /* switch off digitiser */
        MOD_DEC_USE_COUNT;
        return 0;
@@ -640,7 +640,7 @@ static struct miscdevice pc110_pad = {
 };
 
 
-static int pc110pad_init(void)
+int pc110pad_init(void)
 {
        current_params = default_params;
 
index 56d8d82e05f4d4ea1cbb0e4c4bded1f13236646c..d0ea0b0d3321c02dd3df72b6c603237b4fa24027 100644 (file)
@@ -26,6 +26,6 @@ struct pc110pad_params {
 #define PC110PAD_IOCTL_TYPE            0x9a
 
 #define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
-#define PC110PADIOCSETP _IOR(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
+#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
  
 #endif /* _PC110PAD_H */
index ecec83ce9c8f7a3ca53745fc2137abf87ae0b90a..39c35fb4904450b022089021c80b59bb56bf9e7d 100644 (file)
 
 #include "pc_keyb.h"
 
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char pckbd_sysrq_xlate[128] =
+       "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
+       "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
+       "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
+       "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
+       "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
+       "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+       "\r\000/";                                      /* 0x60 - 0x6f */
+#endif
+
 /*
  * In case we run on a non-x86 hardware we need to initialize both the keyboard
  * controller and the keyboard. On a x86, the BIOS will already have initialized
  * them.
  */
 
+#ifndef __i386__
+#define INIT_KBD
+#endif
+
 #ifdef INIT_KBD
 
 __initfunc(static int kbd_wait_for_input(void))
 {
-        int     n;
-        int     status, data;
+       int     n;
+       int     status, data;
+       unsigned long start = jiffies;
 
-        n = KBD_TIMEOUT;
-        do {
+       do {
                 status = inb(KBD_STATUS_REG);
                 /*
                  * Wait for input data to become available.  This bit will
@@ -62,7 +79,7 @@ __initfunc(static int kbd_wait_for_input(void))
                        continue;
                 }
                return (data & 0xff);
-        } while (--n);
+        } while (jiffies - start < KBD_INIT_TIMEOUT);
         return -1;     /* timed-out if fell through to here... */
 }
 
@@ -155,12 +172,11 @@ __initfunc(static char *initialize_kbd2(void))
 
 __initfunc(static void initialize_kbd(void))
 {
-       unsigned long flags;
        char *msg;
 
-       save_flags(flags); cli();
+       disable_irq(KEYBOARD_IRQ);
        msg = initialize_kbd2();
-       restore_flags(flags);
+       enable_irq(KEYBOARD_IRQ);
 
        if (msg)
                printk(KERN_WARNING "initialize_kbd: %s\n", msg);
@@ -181,12 +197,15 @@ static volatile unsigned char resend = 0;
 
 static inline void kb_wait(void)
 {
-       int i;
+       unsigned long start = jiffies;
 
-       for (i=0; i<KBD_TIMEOUT; i++)
+       do {
                if (! (inb_p(KBD_STATUS_REG) & KBD_STAT_IBF))
                        return;
+       } while (jiffies - start < KBC_TIMEOUT);
+#ifdef KBD_REPORT_TIMEOUTS
        printk(KERN_WARNING "Keyboard timed out\n");
+#endif
 }
 
 /*
@@ -364,7 +383,7 @@ static int do_acknowledge(unsigned char scancode)
        }
        if (scancode == 0) {
 #ifdef KBD_REPORT_ERR
-               printk(KERN_INFO "keyboard buffer overflow\n");
+               printk(KERN_INFO "Keyboard buffer overflow\n");
 #endif
                prev_scancode = 0;
                return 0;
@@ -380,7 +399,7 @@ int pckbd_pretranslate(unsigned char scancode, char raw_mode)
 #ifndef KBD_IS_FOCUS_9000
 #ifdef KBD_REPORT_ERR
                if (!raw_mode)
-                 printk(KERN_DEBUG "keyboard error\n");
+                 printk(KERN_DEBUG "Keyboard error\n");
 #endif
 #endif
                prev_scancode = 0;
@@ -503,7 +522,7 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        handle_scancode(scancode);
 
                status = inb(KBD_STATUS_REG);
-       } while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
+       } while (status & KBD_STAT_OBF);
 
        mark_bh(KEYBOARD_BH);
        enable_keyboard();
@@ -517,7 +536,7 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static int send_data(unsigned char data)
 {
        int retries = 3;
-       int i;
+       unsigned long start;
 
        do {
                kb_wait();
@@ -525,16 +544,21 @@ static int send_data(unsigned char data)
                resend = 0;
                reply_expected = 1;
                outb_p(data, KBD_DATA_REG);
-               for(i=0; i<0x200000; i++) {
-                       inb_p(KBD_STATUS_REG); /* just as a delay */
+               start = jiffies;
+               do {
                        if (acknowledge)
                                return 1;
-                       if (resend)
-                               break;
-               }
-               if (!resend)
-                       return 0;
+                       if (jiffies - start >= KBD_TIMEOUT) {
+#ifdef KBD_REPORT_TIMEOUTS
+                               printk(KERN_WARNING "Keyboard timeout\n");
+#endif
+                               return 0;
+                       }
+               } while (!resend);
        } while (retries-- > 0);
+#ifdef KBD_REPORT_TIMEOUTS
+       printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
+#endif
        return 0;
 }
 
index f12ddab080cb222b52930a8340cac05c4f33281c..ffbfc49e257a34771acf419ec93affd7be91f6d6 100644 (file)
 
 #define KBD_REPORT_ERR                 /* Report keyboard errors */
 #define KBD_REPORT_UNKN                        /* Report unknown scan codes */
+#define KBD_REPORT_TIMEOUTS            /* Report keyboard timeouts */
 #undef KBD_IS_FOCUS_9000               /* We have the brain-damaged FOCUS-9000 keyboard */
-#define KBD_TIMEOUT 0x100000           /* Timeout for sending of commands */
+
+#define KBD_INIT_TIMEOUT HZ            /* Timeout for initializing the keyboard */
+#define KBC_TIMEOUT (HZ/4)             /* Timeout for sending to keyboard controller */
+#define KBD_TIMEOUT (HZ/4)             /* Timeout for keyboard command acknowledge */
 
 /*
  *     Internal variables of the driver
index 590ad4768b181243233c508dfbe2650542e21672..3fe0a8d8ab3797d41b932491973c51aa5eeb6ce5 100644 (file)
@@ -53,6 +53,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/semaphore.h>
 
 #include <linux/config.h>
 
@@ -141,19 +142,7 @@ static int poll_aux_status(void)
                schedule();
                retries++;
        }
-       return !(retries==MAX_RETRIES);
-}
-
-static int poll_aux_status_nosleep(void)
-{
-       int retries = 0;
-
-       while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < 1000000) {
-               if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
-                       inb_p(KBD_DATA_REG);
-               retries++;
-       }
-       return !(retries == 1000000);
+       return (retries < MAX_RETRIES);
 }
 
 /*
@@ -173,18 +162,10 @@ static void aux_write_dev(int val)
  */
 
 #ifdef INITIALIZE_DEVICE
-__initfunc(static void aux_write_dev_nosleep(int val))
-{
-       poll_aux_status_nosleep();
-       outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
-       poll_aux_status_nosleep();
-       outb_p(val, KBD_DATA_REG);
-}
-
 __initfunc(static int aux_write_ack(int val))
 {
-       aux_write_dev_nosleep(val);
-       poll_aux_status_nosleep();
+       aux_write_dev(val);
+       poll_aux_status();
 
        if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
        {
@@ -206,6 +187,31 @@ static void aux_write_cmd(int val)
        outb_p(val, KBD_DATA_REG);
 }
 
+/*
+ * AUX handler critical section start and end.
+ * 
+ * Only one process can be in the critical section and all keyboard sends are
+ * deferred as long as we're inside. This is necessary as we may sleep when
+ * waiting for the keyboard controller and other processes / BH's can
+ * preempt us. Please note that the input buffer must be flushed when
+ * aux_end_atomic() is called and the interrupt is no longer enabled as not
+ * doing so might cause the keyboard driver to ignore all incoming keystrokes.
+ */
+
+static struct semaphore aux_sema4 = MUTEX;
+
+static inline void aux_start_atomic(void)
+{
+       down(&aux_sema4);
+       disable_bh(KEYBOARD_BH);
+}
+
+static inline void aux_end_atomic(void)
+{
+       enable_bh(KEYBOARD_BH);
+       up(&aux_sema4);
+}
+
 /*
  * Interrupt from the auxiliary device: a character
  * is waiting in the keyboard/aux controller.
@@ -236,14 +242,12 @@ static int release_aux(struct inode * inode, struct file * file)
        fasync_aux(inode, file, 0);
        if (--aux_count)
                return 0;
-       /* disable kbd bh to avoid mixing of cmd bytes */
-       disable_bh(KEYBOARD_BH);
+       aux_start_atomic();
        aux_write_cmd(AUX_INTS_OFF);                        /* Disable controller ints */
        poll_aux_status();
        outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG);       /* Disable Aux device */
        poll_aux_status();
-       /* reenable kbd bh */
-       enable_bh(KEYBOARD_BH);
+       aux_end_atomic();
 #ifdef CONFIG_MCA
        free_irq(AUX_IRQ, inode);
 #else
@@ -262,10 +266,14 @@ static int open_aux(struct inode * inode, struct file * file)
 {
        if (!aux_present)
                return -ENODEV;
-       if (aux_count++)
+       aux_start_atomic();
+       if (aux_count++) {
+               aux_end_atomic();
                return 0;
-       if (!poll_aux_status()) {
+       }
+       if (!poll_aux_status()) {               /* FIXME: Race condition */
                aux_count--;
+               aux_end_atomic();
                return -EBUSY;
        }
        queue->head = queue->tail = 0;          /* Flush input queue */
@@ -275,18 +283,16 @@ static int open_aux(struct inode * inode, struct file * file)
        if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)) {
 #endif
                aux_count--;
+               aux_end_atomic();
                return -EBUSY;
        }
        MOD_INC_USE_COUNT;
-       /* disable kbd bh to avoid mixing of cmd bytes */
-       disable_bh(KEYBOARD_BH);
        poll_aux_status();
        outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG);        /* Enable Aux */
        aux_write_dev(AUX_ENABLE_DEV);                      /* Enable aux device */
        aux_write_cmd(AUX_INTS_ON);                         /* Enable controller ints */
        poll_aux_status();
-       /* reenable kbd bh */
-       enable_bh(KEYBOARD_BH);
+       aux_end_atomic();
 
        aux_ready = 0;
        return 0;
@@ -304,9 +310,7 @@ static long write_aux(struct inode * inode, struct file * file,
        if (count) {
                int written = 0;
 
-               /* disable kbd bh to avoid mixing of cmd bytes */
-               disable_bh(KEYBOARD_BH);
-
+               aux_start_atomic();
                do {
                        char c;
                        if (!poll_aux_status())
@@ -318,8 +322,7 @@ static long write_aux(struct inode * inode, struct file * file,
                        outb_p(c, KBD_DATA_REG);
                        written++;
                } while (--count);
-               /* reenable kbd bh */
-               enable_bh(KEYBOARD_BH);
+               aux_end_atomic();
                retval = -EIO;
                if (written) {
                        retval = written;
@@ -618,6 +621,7 @@ __initfunc(int psaux_init(void))
        queue->head = queue->tail = 0;
        queue->proc_list = NULL;
        if (!qp_found) {
+               aux_start_atomic();
 #ifdef INITIALIZE_DEVICE
                outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
                aux_write_ack(AUX_SET_SAMPLE);
@@ -625,13 +629,15 @@ __initfunc(int psaux_init(void))
                aux_write_ack(AUX_SET_RES);
                aux_write_ack(3);                       /* 8 counts per mm */
                aux_write_ack(AUX_SET_SCALE21);         /* 2:1 scaling */
-               poll_aux_status_nosleep();
+               poll_aux_status();
 #endif /* INITIALIZE_DEVICE */
                outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
-               poll_aux_status_nosleep();
-               outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
-               poll_aux_status_nosleep();
-               outb_p(AUX_INTS_OFF, KBD_DATA_REG);                
+               poll_aux_status();
+               outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);    /* Disable controller interrupts */
+               poll_aux_status();
+               outb_p(AUX_INTS_OFF, KBD_DATA_REG);
+               poll_aux_status();
+               aux_end_atomic();
        }
        return 0;
 }
index cd44d36aaa5cda4b4be12ab7423e52f7a141ee51..25396c3c1bd992831fe65974768d378a1bcc6cc9 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  *
- *     $Id: sysrq.c,v 1.3 1997/06/18 09:42:12 mj Exp $
+ *     $Id: sysrq.c,v 1.4 1997/07/17 11:54:15 mj Exp $
  *
  *     Linux Magic System Request Key Hacks
  *
@@ -63,72 +63,72 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
        console_loglevel = 7;
        printk(KERN_INFO "SysRq: ");
        switch (key) {
-       case 19:                                            /* R -- Reset raw mode */
-               kbd->kbdmode = VC_XLATE;
-               printk("Keyboard mode set to XLATE\n");
+       case 'r':                                           /* R -- Reset raw mode */
+               if (kbd) {
+                       kbd->kbdmode = VC_XLATE;
+                       printk("Keyboard mode set to XLATE\n");
+               }
                break;
-       case 30:                                            /* A -- SAK */
+       case 'a':                                           /* A -- SAK */
                printk("SAK\n");
-               do_SAK(tty);
+               if (tty)
+                       do_SAK(tty);
                reset_vc(fg_console);
                break;
-       case 48:                                            /* B -- boot immediately */
+       case 'b':                                           /* B -- boot immediately */
                printk("Resetting\n");
                machine_restart(NULL);
                break;
 #ifdef __sparc__
-       case 35:                                            /* H -- halt immediately */
+       case 'h':                                           /* H -- halt immediately */
                printk("Halting\n");
                halt_now();
                break;
 #endif
 #ifdef CONFIG_APM
-       case 24:                                            /* O -- power off */
+       case 'o':                                           /* O -- power off */
                printk("Power off\n");
                apm_set_power_state(APM_STATE_OFF);
                break;
 #endif
-       case 31:                                            /* S -- emergency sync */
+       case 's':                                           /* S -- emergency sync */
                printk("Emergency Sync\n");
                emergency_sync_scheduled = EMERG_SYNC;
                wakeup_bdflush(0);
                break;
-       case 22:                                            /* U -- emergency remount R/O */
+       case 'u':                                           /* U -- emergency remount R/O */
                printk("Emergency Remount R/O\n");
                emergency_sync_scheduled = EMERG_REMOUNT;
                wakeup_bdflush(0);
                break;
-       case 25:                                            /* P -- show PC */
+       case 'p':                                           /* P -- show PC */
                printk("Show Regs\n");
                if (pt_regs)
                        show_regs(pt_regs);
                break;
-       case 20:                                            /* T -- show task info */
+       case 't':                                           /* T -- show task info */
                printk("Show State\n");
                show_state();
                break;
-       case 50:                                            /* M -- show memory info */
+       case 'm':                                           /* M -- show memory info */
                printk("Show Memory\n");
                show_mem();
                break;
-       case 2 ... 11:                                      /* 0-9 -- set console logging level */
-               key--;
-               if (key == 10)
-                       key = 0;
-               orig_log_level = key;
-               printk("Log level set to %d\n", key);
+       case '0' ... '9':                                   /* 0-9 -- set console logging level */
+               orig_log_level = key - '0';
+               printk("Log level set to %d\n", orig_log_level);
                break;
-       case 18:                                            /* E -- terminate all user processes */
+       case 'e':                                           /* E -- terminate all user processes */
                printk("Terminate All Tasks\n");
                send_sig_all(SIGTERM, 0);
                orig_log_level = 8;                         /* We probably have killed syslogd */
                break;
-       case 37:                                            /* K -- kill all user processes */
+       case 'k':                                           /* K -- kill all user processes */
                printk("Kill All Tasks\n");
                send_sig_all(SIGKILL, 0);
                orig_log_level = 8;
                break;
-       case 38:                                            /* L -- kill all processes including init */
+       case 'l':                                           /* L -- kill all processes including init */
                printk("Kill ALL Tasks (even init)\n");
                send_sig_all(SIGKILL, 1);
                orig_log_level = 8;
@@ -154,7 +154,7 @@ static void all_files_read_only(void)           /* Kill write permissions of all files
        struct file *file;
 
        for (file = inuse_filps; file; file = file->f_next)
-               if (file->f_inode && file->f_count && S_ISREG(file->f_inode->i_mode))
+               if (file->f_dentry && file->f_count && S_ISREG(file->f_dentry->d_inode->i_mode))
                        file->f_mode &= ~2;
 }
 
index 2e1195ec6d143ec9f07e1813d296a77055bc2d0f..c985de968937fb721a2e4a0d44f330d217ab8310 100644 (file)
 #define dac_reg (0x3c8)
 #define dac_val (0x3c9)
 
+#ifdef __powerpc__
+#define VGA_OFFSET 0xC0000000;
+#else
+#define VGA_OFFSET 0x0
+#endif
+
 /*
  * By replacing the four outb_p with two back to back outw, we can reduce
  * the window of opportunity to see text mislocated to the RHS of the
@@ -152,20 +158,20 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
 {
        if (ORIG_VIDEO_MODE == 7)       /* Is this a monochrome display? */
        {
-               video_mem_base = 0xb0000;
+               video_mem_base = 0xb0000 + VGA_OFFSET;
                video_port_reg = 0x3b4;
                video_port_val = 0x3b5;
                if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
                {
                        video_type = VIDEO_TYPE_EGAM;
-                       video_mem_term = 0xb8000;
+                       video_mem_term = 0xb8000 + VGA_OFFSET;
                        *display_desc = "EGA+";
                        request_region(0x3b0,16,"ega");
                }
                else
                {
                        video_type = VIDEO_TYPE_MDA;
-                       video_mem_term = 0xb2000;
+                       video_mem_term = 0xb2000 + VGA_OFFSET;
                        *display_desc = "*MDA";
                        request_region(0x3b0,12,"mda");
                        request_region(0x3bf, 1,"mda");
@@ -174,14 +180,14 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
        else                            /* If not, it is color. */
        {
                can_do_color = 1;
-               video_mem_base = 0xb8000;
+               video_mem_base = 0xb8000  + VGA_OFFSET;
                video_port_reg  = 0x3d4;
                video_port_val  = 0x3d5;
                if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
                {
                        int i ;
 
-                       video_mem_term = 0xc0000;
+                       video_mem_term = 0xc0000 + VGA_OFFSET;
 
                        if (!ORIG_VIDEO_ISVGA) {
                                video_type = VIDEO_TYPE_EGAC;
@@ -199,8 +205,8 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
                                 * controllers (it seems like setting MM=01
                                 * and COE=1 isn't necessarily a good idea)
                                 */
-                               video_mem_base = 0xa0000 ;
-                               video_mem_term = 0xb0000 ;
+                               video_mem_base = 0xa0000  + VGA_OFFSET;
+                               video_mem_term = 0xb0000  + VGA_OFFSET;
                                outb_p (6, 0x3ce) ;
                                outb_p (6, 0x3cf) ;
 #endif
@@ -232,7 +238,7 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
                else
                {
                        video_type = VIDEO_TYPE_CGA;
-                       video_mem_term = 0xba000;
+                       video_mem_term = 0xba000 + VGA_OFFSET;
                        *display_desc = "*CGA";
                        request_region(0x3d4,2,"cga");
                }
index 4ae7aa069e3cd7326a571d98290ac7f9f9ef458b..4647f0feae9c6866b46f3f72420acd9ee5226a42 100644 (file)
@@ -275,7 +275,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
                mp->rx_skbs[i] = skb;
                skb->dev = dev;
                skb_put(skb, RX_ALLOC_SIZE);
-               rxd[i].myri_scatters[0].addr = (unsigned int) skb->data;
+               rxd[i].myri_scatters[0].addr = (unsigned long) skb->data;
                rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE;
                rxd[i].ctx = i;
                rxd[i].num_sg = 1;
@@ -429,7 +429,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
                        drops++;
                        DRX(("DROP "));
                        mp->enet_stats.rx_dropped++;
-                       rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+                       rxd->myri_scatters[0].addr = (unsigned long) skb->data;
                        rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
                        rxd->ctx = index;
                        rxd->num_sg = 1;
@@ -450,7 +450,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
                        mp->rx_skbs[index] = new_skb;
                        new_skb->dev = dev;
                        skb_put(new_skb, RX_ALLOC_SIZE);
-                       rxd->myri_scatters[0].addr = (unsigned int) new_skb->data;
+                       rxd->myri_scatters[0].addr = (unsigned long) new_skb->data;
                        rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
                        rxd->ctx = index;
                        rxd->num_sg = 1;
@@ -474,7 +474,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
 
                        /* Reuse original ring buffer. */
                        DRX(("reuse "));
-                       rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+                       rxd->myri_scatters[0].addr = (unsigned long) skb->data;
                        rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
                        rxd->ctx = index;
                        rxd->num_sg = 1;
@@ -618,7 +618,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct device *dev)
        txd = &sq->myri_txd[entry];
        mp->tx_skbs[entry] = skb;
 
-       txd->myri_gathers[0].addr = (unsigned int) skb->data;
+       txd->myri_gathers[0].addr = (unsigned long) skb->data;
        txd->myri_gathers[0].len = len;
        txd->num_sg = 1;
        txd->chan = KERNEL_CHANNEL;
index f06a66afcb1d65592eedb8ffda682dfaa20afd99..aaab86b24868d7a29b1155401d91a4fd855cba37 100644 (file)
@@ -204,7 +204,7 @@ struct net_local {
        struct tq_struct deferred;
        struct plip_local snd_data;
        struct plip_local rcv_data;
-       struct ppd *pardev;
+       struct pardevice *pardev;
        unsigned long  trigger;
        unsigned long  nibble;
        enum plip_connection_state connection;
@@ -228,7 +228,7 @@ __initfunc(int
 plip_init_dev(struct device *dev, struct parport *pb))
 {
        struct net_local *nl;
-       struct ppd *pardev;
+       struct pardevice *pardev;
 
        dev->irq = pb->irq;
        dev->base_addr = pb->base;
@@ -239,8 +239,8 @@ plip_init_dev(struct device *dev, struct parport *pb))
        }
        
        pardev = parport_register_device(pb, dev->name, plip_preempt,
-                                       plip_wakeup,
-                                       plip_interrupt, PARPORT_DEV_LURK, dev);
+                                        plip_wakeup, plip_interrupt, 
+                                        PARPORT_DEV_LURK, dev);
 
        printk(version);
        printk("%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
index 2a2f874aa224caa2535fa66513d6a1747653121f..fc26b57bff30e562de3c840359b89098dce6df5b 100644 (file)
@@ -339,6 +339,7 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        sti();
        if (sm->dma.ptt_cnt <= 0) {
                dma_receive(sm, curfrag);
+               hdlcdrv_arbitrate(dev, &sm->hdrv);
                if (hdlcdrv_ptt(&sm->hdrv)) {
                        /* starting to transmit */
                        disable_dma(dev->dma);
@@ -352,10 +353,8 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                sti();
                dma_init_receive(sm);
                setup_dma_dsp(dev, sm, 0);
-        } else {
+        } else
                dma_transmit(sm);
-               hdlcdrv_arbitrate(dev, &sm->hdrv);
-        }
        sm_output_status(sm);
        hdlcdrv_transmitter(dev, &sm->hdrv);
        hdlcdrv_receiver(dev, &sm->hdrv);
index 021ecc1652115f917c1ab84c091638afb4f77bfc..ef129930a85f1243bfbf15081576acb45ec16e18 100644 (file)
@@ -402,6 +402,7 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        sti();
        if (sm->dma.ptt_cnt <= 0) {
                dma_receive(sm, curfrag);
+               hdlcdrv_arbitrate(dev, &sm->hdrv);
                if (hdlcdrv_ptt(&sm->hdrv)) {
                        /* starting to transmit */
                        disable_dma(dev->dma);
@@ -415,10 +416,8 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                sti();
                dma_init_receive(sm);
                setup_dma_wss(dev, sm, 0);
-        } else {
+        } else
                dma_transmit(sm);
-               hdlcdrv_arbitrate(dev, &sm->hdrv);
-        }
        sm_output_status(sm);
        hdlcdrv_transmitter(dev, &sm->hdrv);
        hdlcdrv_receiver(dev, &sm->hdrv);
index 4ce803b34d3c63b3b0d4712e3ddf19790a4293e1..a5d2b30166f31c86895bbb368bcca8c9201a0f79 100644 (file)
@@ -32,7 +32,9 @@ ifdef TADPOLE_FB_WEITEK
  FB_OBJS +=    weitek.o
 endif
 ifdef SUN_FB_CREATOR
+ ifeq ($(ARCH),sparc64)
  FB_OBJS += creator.o
+ endif
 endif
 #ifdef SUN_FB_FAST_ONE
 # FB_OBJS +=   sun_8bit_fast1.o
index 086f9b40ee1b7dbeb6a6f3c2c8f8c05b953c16e0..3ce90092a580e88e84199cfb971546ea3f79ec0c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
+/* $Id: creator.c,v 1.8 1997/07/22 06:14:12 davem Exp $
  * creator.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -235,7 +235,6 @@ ffb_wid_get (fbinfo_t *fb, struct fb_wid_list *wl)
        struct fb_wid_item wit[30];
        char *km = NULL;
        int i, j;
-       u32 l;
        int err;
        
 #ifdef CONFIG_SPARC32_COMPAT
@@ -287,7 +286,6 @@ ffb_wid_put (fbinfo_t *fb, struct fb_wid_list *wl)
        struct fb_wid_item wit[30];
        char *km = NULL;
        int i, j;
-       u32 l;
        
 #ifdef CONFIG_SPARC32_COMPAT
        if (current->tss.flags & SPARC_FLAG_32BIT) {
@@ -464,8 +462,6 @@ ffb_loadcmap (fbinfo_t *fb, int index, int count)
 static int
 ffb_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
 {
-       int i;
-       
        switch (cmd) {
        case FBIO_WID_GET:
                return ffb_wid_get (fb, (struct fb_wid_list *)arg);
index cad4469045db1751743cf33e537145e712825155..111f65f97ae3546f1be7bb8c7e3b4a9ee773a6e7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.66 1997/07/15 09:48:47 jj Exp $
+/* $Id: suncons.c,v 1.67 1997/07/20 05:59:42 davem Exp $
  *
  * suncons.c: Sun SparcStation console support.
  *
@@ -931,7 +931,7 @@ __initfunc(static void
                leo_setup (&fbinfo [n], n, base, io);
                break;
 #endif
-#ifdef SUN_FB_CREATOR
+#if defined(SUN_FB_CREATOR) && defined(__sparc_v9__)
        case FBTYPE_CREATOR:
                creator_setup (&fbinfo [n], n, con_node, base, io);
                break;
index 20c14a687cdf2c77facd3dccc3d22457eeb31d38..9eaad5bc71ea764590a8006977174d6fb7673912 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
+/* $Id: tcx.c,v 1.18 1997/07/22 06:14:09 davem Exp $
  * tcx.c: SUNW,tcx 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -309,9 +309,9 @@ __initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, u32 tcx, struct lin
        tcxinfo->tec = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
                 sizeof (struct tcx_tec), "tcx_tec", fb->space, 0);
        if (!fb->base){
-               fb->base = (uint)
-                       sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
-                                      fb->type.fb_size, "tcx_ram", fb->space, 0);
+               fb->base = (unsigned long)
+                       sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET],
+                                      0, fb->type.fb_size, "tcx_ram", fb->space, 0);
        }
        
        if (prom_getbool (node, "hw-cursor")) {
index 7b7b1bd720fe3bfecb8477dd148fa3b783ecd0c9..7de26c2f7039df721ef3956330e76a91d63a4ba2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
+/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
  * weitek.c: Tadpole P9100/P9000 console driver
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -99,8 +99,6 @@ weitek_loadcmap (void *fbinfo, int index, int count)
 
 __initfunc(void weitek_setup(fbinfo_t *fb, int slot, u32 addr, int io))
 {
-       extern struct screen_info screen_info;
-       
        printk ("weitek%d at 0x%8.8x\n", slot, addr);
        
        /* Fill in parameters we left out */
index 4d59647cc7870fc364a4f4a0b485be9043f1c0c5..cf06585ff3f054ae8bf2fb4248f7e89a871ff2ac 100644 (file)
@@ -384,6 +384,13 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
 #ifdef CONFIG_SUN_AUXIO
        if (sparc_cpu_model == sun4u)
                auxio_probe ();
+#endif
+#ifdef __sparc_v9__
+       if (sparc_cpu_model == sun4u) {
+               extern void sun4u_start_timers(void);
+
+               sun4u_start_timers();
+       }
 #endif
        return memory_start;
 }
index 44a78b12c6a5549fdfef61adadd8ba3229adb700..3d28dae2f28b50547a9e0a55c7a884c97c9e0fea 100644 (file)
@@ -560,7 +560,7 @@ issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
      * sure what the relationship between the NCR structures
      * and host structures were going to be.
      */
-       (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) - 
+       (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (le32_to_cpu(issue[1])) - 
            (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
            offsetof(struct NCR53c7x0_cmd, dsa)) 
     /* If the IF TRUE bit is not set, it's a NOP */
@@ -795,18 +795,18 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
     for (i = 0, curr = (u32 *) hostdata->schedule; 
        i < host->can_queue; ++i, curr += 2) {
        curr[0] = hostdata->NOP_insn;
-       curr[1] = 0xdeadbeef;
+       curr[1] = le32_to_cpu(0xdeadbeef);
     }
-    curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
-    curr[1] = (u32) virt_to_bus (hostdata->script) +
-       hostdata->E_wait_reselect;
+    curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE);
+    curr[1] = (u32) le32_to_cpu(virt_to_bus (hostdata->script) +
+       hostdata->E_wait_reselect);
     hostdata->reconnect_dsa_head = 0;
     hostdata->addr_reconnect_dsa_head = (u32) 
-       virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+       le32_to_cpu(virt_to_bus((void *) &(hostdata->reconnect_dsa_head)));
     hostdata->expecting_iid = 0;
     hostdata->expecting_sto = 0;
     if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS) 
-       hostdata->initiate_sdtr = 0xffff
+       hostdata->initiate_sdtr = le32_to_cpu(0xffff)
     else
        hostdata->initiate_sdtr = 0;
     hostdata->talked_to = 0;
@@ -877,7 +877,7 @@ clock_to_ccf (int clock) {
  * Returns : 0 on success, -1 on failure.
  */
 
-static inline in
+static int 
 NCR53c7x0_init (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     int i, ccf, expected_ccf;
@@ -899,6 +899,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
      * will differ.
      */
     int expected_mapping = OPTION_IO_MAPPED;
+
     NCR53c7x0_local_setup(host);
 
     switch (hostdata->chip) {
@@ -929,10 +930,10 @@ NCR53c7x0_init (struct Scsi_Host *host) {
 
     /* Assign constants accessed by NCR */
     hostdata->NCR53c7xx_zero = 0;                      
-    hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
-    hostdata->NCR53c7xx_msg_abort = ABORT;
-    hostdata->NCR53c7xx_msg_nop = NOP;
-    hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+    hostdata->NCR53c7xx_msg_reject = le32_to_cpu(MESSAGE_REJECT);
+    hostdata->NCR53c7xx_msg_abort = le32_to_cpu(ABORT);
+    hostdata->NCR53c7xx_msg_nop = le32_to_cpu(NOP);
+    hostdata->NOP_insn = le32_to_cpu((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24);
 
     if (expected_mapping == -1 || 
        (hostdata->options & (OPTION_MEMORY_MAPPED)) != 
@@ -1131,7 +1132,14 @@ NCR53c7x0_init (struct Scsi_Host *host) {
        search->irq == host->irq && search != host); search=search->next);
 
     if (!search) {
-       if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL)) {
+#ifdef __powerpc__
+       if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL)) 
+#else
+       if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+#endif
+         {
+         
+         
            printk("scsi%d : IRQ%d not free, detaching\n"
                   "         You have either a configuration problem, or a\n"
                    "         broken BIOS.  You may wish to manually assign\n"
@@ -1453,6 +1461,21 @@ ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
        return -1;
     }
 
+#ifdef __powerpc__
+    if ( ! (command & PCI_COMMAND_MASTER)) {
+      printk("SCSI: PCI Master Bit has not been set. Setting...\n");
+      command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+      pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+      if (io_port >= 0x10000000) {
+             /* Mapping on PowerPC can't handle this! */
+             unsigned long new_io_port;
+             new_io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+             printk("SCSI: I/O moved from %08X to %08x\n", io_port, new_io_port);
+             io_port = new_io_port;
+             pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+      }
+    }
+#endif
 
     /* 
      * Bit 0 is the address space indicator and must be one for I/O
@@ -1613,6 +1636,9 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
     unsigned char tmp;
     int i, ncr_to_memory, memory_to_ncr;
     u32 base;
+#ifdef __powerpc__
+    unsigned long *script_ptr;
+#endif    
     NCR53c7x0_local_setup(host);
 
 
@@ -1801,6 +1827,14 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
        printk("scsi%d : NCR dsa_fields start is %d not %d\n",
            host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end - 
            Ent_dsa_zero);
+#ifdef __powerpc__
+/* The PowerPC is Big Endian - adjust script appropriately */
+    script_ptr = hostdata->script;
+    for (i = 0;  i < sizeof(SCRIPT);  i += sizeof(long))
+    {
+        *script_ptr++ = le32_to_cpu(*script_ptr);
+    }
+#endif             
 
     printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
        virt_to_bus(hostdata->script), hostdata->script);
@@ -1884,7 +1918,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
                    "         also verify that the board is jumpered to use PCI INTA, since\n"
                    "         most PCI motherboards lack support for INTB, INTC, and INTD.\n"
                    : "");
-       else if (hostdata->test_completed != 1) 
+      else if (hostdata->test_completed != 1) 
            printk ("scsi%d : test 1 bad interrupt value (%d)\n", 
                host->host_no, hostdata->test_completed);
        else 
@@ -1922,16 +1956,17 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
        cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
        cmd[4] = sizeof(data); 
 
-       dsa[2] = 1;
-       dsa[3] = virt_to_bus(&identify);
-       dsa[4] = 6;
-       dsa[5] = virt_to_bus(&cmd);
-       dsa[6] = sizeof(data);
-       dsa[7] = virt_to_bus(&data);
-       dsa[8] = 1;
-       dsa[9] = virt_to_bus(&status);
-       dsa[10] = 1;
-       dsa[11] = virt_to_bus(&msg);
+/* Need to adjust for endian-ness */           
+       dsa[2] = le32_to_cpu(1);
+       dsa[3] = le32_to_cpu(virt_to_bus(&identify));
+       dsa[4] = le32_to_cpu(6);
+       dsa[5] = le32_to_cpu(virt_to_bus(&cmd));
+       dsa[6] = le32_to_cpu(sizeof(data));
+       dsa[7] = le32_to_cpu(virt_to_bus(&data));
+       dsa[8] = le32_to_cpu(1);
+       dsa[9] = le32_to_cpu(virt_to_bus(&status));
+       dsa[10] = le32_to_cpu(1);
+       dsa[11] = le32_to_cpu(virt_to_bus(&msg));
 
        for (i = 0; i < 3; ++i) {
            cli();
@@ -1942,7 +1977,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
            }
 
            /*       SCNTL3         SDID        */
-           dsa[0] = (0x33 << 24) | (i << 16)  ;
+           dsa[0] = le32_to_cpu((0x33 << 24) | (i << 16))  ;
            hostdata->idle = 0;
            hostdata->test_running = 2;
            hostdata->test_completed = -1;
@@ -2004,9 +2039,22 @@ NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
        host->hostdata;
     int i;
+#ifdef __powerpc__
+    int len;
+    unsigned long *dsa_ptr;
+#endif    
 
     memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
        hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+#ifdef __powerpc__
+    /* Note: the script has already been 'endianized' */
+    dsa_ptr = cmd->dsa;
+    len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+    for (i = 0;  i < len;  i += sizeof(long))
+    {
+       *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+    }
+#endif         
 
     /* 
      * Note : within the NCR 'C' code, dsa points to the _start_
@@ -2046,6 +2094,14 @@ NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
     /*  XXX - new start stuff */
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
        dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+#ifdef __powerpc__
+    dsa_ptr = cmd->dsa;    
+    len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+    for (i = 0;  i < len;  i += sizeof(long))
+    {
+       *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+    }
+#endif         
 
 }
 
@@ -2125,7 +2181,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
        if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd) 
        {
            curr[0] = hostdata->NOP_insn;
-           curr[1] = 0xdeadbeef;
+           curr[1] = le32_to_cpu(0xdeadbeef);
            ++found;
            break;
        }
@@ -2140,13 +2196,13 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
      */
 
     for (left = host->can_queue,
-           ncr_search = hostdata->reconnect_dsa_head
+           ncr_search = le32_to_cpu(hostdata->reconnect_dsa_head)
            ncr_prev = &hostdata->reconnect_dsa_head;
        left >= 0 && ncr_search && 
            ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start) 
                != (char *) cmd->dsa;
        ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) + 
-           hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+           hostdata->dsa_next), ncr_search = le32_to_cpu(*ncr_prev), --left);
 
     if (left < 0) 
        printk("scsi%d: loop detected in ncr reconnect list\n",
@@ -2491,7 +2547,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
     dsps = NCR53c7x0_read32(DSPS_REG);
     dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
 
-    if (hostdata->options & OPTION_DEBUG_INTR) 
+    if (hostdata->options & OPTION_DEBUG_INTR)
        printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
 
     switch (dsps) {
@@ -2584,9 +2640,9 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
                    hostdata->msg_buf[4] = 0;           /* 0 offset = async */
                    asynchronous (host, c->target);
                }
-               patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+               patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, le32_to_cpu(5));
                patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32) 
-                   virt_to_bus ((void *)&hostdata->msg_buf));
+                   le32_to_cpu(virt_to_bus ((void *)&hostdata->msg_buf)));
                hostdata->dsp = hostdata->script + 
                    hostdata->E_respond_message / sizeof(u32);
                hostdata->dsp_changed = 1;
@@ -2649,14 +2705,14 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
         *      agrees with this being an untagged queue'd command.
         */
 
-       patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+       patch_dsa_32 (cmd->dsa, dsa_msgout, 0, le32_to_cpu(1));
 
        /* 
         * Modify the table indirect for COMMAND OUT phase, since 
         * Request Sense is a six byte command.
         */
 
-       patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+       patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, le32_to_cpu(6));
 
        c->cmnd[0] = REQUEST_SENSE;
        c->cmnd[1] &= 0xe0;     /* Zero all but LUN */
@@ -2672,17 +2728,17 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
         */
 
        patch_dsa_32 (cmd->dsa, dsa_dataout, 0, 
-           virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+           le32_to_cpu(virt_to_bus(hostdata->script) + hostdata->E_other_transfer));
        patch_dsa_32 (cmd->dsa, dsa_datain, 0, 
-           virt_to_bus(cmd->data_transfer_start));
-       cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | 
-           DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
-       cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
+           le32_to_cpu(virt_to_bus(cmd->data_transfer_start)));
+       cmd->data_transfer_start[0] = le32_to_cpu((((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | 
+           DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer));
+       cmd->data_transfer_start[1] = (u32) le32_to_cpu(virt_to_bus(c->sense_buffer));
 
-       cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) 
-           << 24) | DBC_TCI_TRUE;
-       cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) + 
-           hostdata->E_other_transfer;
+       cmd->data_transfer_start[2] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) 
+           << 24) | DBC_TCI_TRUE);
+       cmd->data_transfer_start[3] = (u32) le32_to_cpu(virt_to_bus(hostdata->script) + 
+           hostdata->E_other_transfer);
 
        /*
         * Currently, this command is flagged as completed, ie 
@@ -2691,7 +2747,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
         * status, etc are used.
         */
 
-       cmd->cmd->result = 0xffff;              
+       cmd->cmd->result = le32_to_cpu(0xffff);         
 
        /* 
         * Restart command as a REQUEST SENSE.
@@ -2732,7 +2788,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
                host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
            printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
                    host->host_no, cmd->saved_data_pointer,
-                   bus_to_virt(cmd->saved_data_pointer));
+                   bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)));
            print_insn (host, hostdata->script + Ent_reselected_ok / 
                    sizeof(u32), "", 1);
            printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
@@ -2765,7 +2821,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
            if (dsa) {
                printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
                    host->host_no, cmd->saved_data_pointer,
-                   bus_to_virt (cmd->saved_data_pointer));
+                   bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
 #if 0
                printk("scsi%d : template code :\n", host->host_no);
                for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero) 
@@ -2794,7 +2850,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
                printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
                       "         (temp was 0x%x (virt 0x%p))\n",
                    host->host_no, cmd->saved_data_pointer,
-                   bus_to_virt (cmd->saved_data_pointer),
+                   bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)),
                    NCR53c7x0_read32 (TEMP_REG),
                    bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
        }
@@ -2888,7 +2944,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
            OPTION_DEBUG_DISCONNECT)) {
            printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
                host->host_no, cmd->saved_data_pointer,
-               bus_to_virt (cmd->saved_data_pointer));
+               bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
            print_progress (c);
        }
        return SPECIFIC_INT_RESTART;
@@ -2901,11 +2957,11 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
                int size;
                printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
                    host->host_no, cmd->saved_data_pointer, bus_to_virt (
-                   cmd->saved_data_pointer));
+                   le32_to_cpu(cmd->saved_data_pointer)));
                size = print_insn (host, (u32 *) 
-                   bus_to_virt(cmd->saved_data_pointer), "", 1);
+                   bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)), "", 1);
                size = print_insn (host, (u32 *) 
-                   bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+                   bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)) + size, "", 1);
                print_progress (c);
            }
 #if 0
@@ -2947,8 +3003,8 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
                    (int) NCR53c7x0_read8(SCNTL3_REG_800),
                    datapath_residual (host)) ;
                print_insn (host, dsp, "", 1);
-               size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
-               print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+               size = print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])), "", 1);
+               print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])) + size, "", 1);
           } 
        return SPECIFIC_INT_RESTART;
 #endif
@@ -3543,7 +3599,6 @@ create_cmd (Scsi_Cmnd *cmd) {
     case MODE_SELECT: 
     case WRITE_6:
     case WRITE_10:
-    case START_STOP: /* also SCAN, which may do DATA OUT */
 #if 0
        printk("scsi%d : command is ", host->host_no);
        print_command(cmd->cmnd);
@@ -3562,6 +3617,7 @@ create_cmd (Scsi_Cmnd *cmd) {
      * These commands do no data transfer, we should force an
      * interrupt if a data phase is attempted on them.
      */
+    case START_STOP: /* also SCAN, which may do DATA OUT */
     case TEST_UNIT_READY:
        datain = dataout = 0;
        break;
@@ -3612,8 +3668,8 @@ create_cmd (Scsi_Cmnd *cmd) {
      * will start the data transfer over at the beginning.
      */
 
-    tmp->saved_data_pointer = virt_to_bus (hostdata->script) + 
-       hostdata->E_data_transfer;
+    tmp->saved_data_pointer = le32_to_cpu(virt_to_bus (hostdata->script) + 
+       hostdata->E_data_transfer);
 
     /*
      * Initialize Linux specific fields.
@@ -3622,9 +3678,9 @@ create_cmd (Scsi_Cmnd *cmd) {
     tmp->cmd = cmd;
     tmp->next = NULL;
     tmp->flags = 0;
-    tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next - 
-       hostdata->dsa_start;
-    tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+    tmp->dsa_next_addr = le32_to_cpu(virt_to_bus(tmp->dsa) + hostdata->dsa_next - 
+       hostdata->dsa_start);
+    tmp->dsa_addr = le32_to_cpu(virt_to_bus(tmp->dsa) - hostdata->dsa_start);
 
     /* 
      * Calculate addresses of dynamic code to fill in DSA
@@ -3650,8 +3706,8 @@ create_cmd (Scsi_Cmnd *cmd) {
     if (hostdata->dsa_fixup)
        hostdata->dsa_fixup(tmp);
 
-    patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
-    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+    patch_dsa_32(tmp->dsa, dsa_next, 0, le32_to_cpu(0));
+    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, le32_to_cpu(virt_to_bus(cmd)));
 
     if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) 
        if (hostdata->sync[cmd->target].select_indirect != 
@@ -3664,8 +3720,8 @@ create_cmd (Scsi_Cmnd *cmd) {
 
        }
 
-    patch_dsa_32(tmp->dsa, dsa_select, 0, hostdata->sync[cmd->target].
-       select_indirect);
+    patch_dsa_32(tmp->dsa, dsa_select, 0, le32_to_cpu(hostdata->sync[cmd->target].
+       select_indirect));
     /*
      * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
      * different commands; although it should be trivial to do them
@@ -3674,7 +3730,7 @@ create_cmd (Scsi_Cmnd *cmd) {
     if (hostdata->initiate_wdtr & (1 << cmd->target)) {
        memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
            sizeof(wdtr_message));
-       patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+       patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(wdtr_message)));
        save_flags(flags);
        cli();
        hostdata->initiate_wdtr &= ~(1 << cmd->target);
@@ -3682,7 +3738,7 @@ create_cmd (Scsi_Cmnd *cmd) {
     } else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
        memcpy ((void *) (tmp->select + 1), (void *) sdtr_message, 
            sizeof(sdtr_message));
-       patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+       patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(sdtr_message)));
        tmp->flags |= CMD_FLAG_SDTR;
        save_flags(flags);
        cli();
@@ -3695,40 +3751,40 @@ create_cmd (Scsi_Cmnd *cmd) {
                !(hostdata->options & OPTION_NO_ASYNC)) {
        memcpy ((void *) (tmp->select + 1), (void *) async_message, 
            sizeof(async_message));
-       patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+       patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(async_message)));
        tmp->flags |= CMD_FLAG_SDTR;
     } 
 #endif
     else 
-       patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+       patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1));
     hostdata->talked_to |= (1 << cmd->target);
     tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ? 
        IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
-    patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
-    patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
-    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
-    patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? 
+    patch_dsa_32(tmp->dsa, dsa_msgout, 1, le32_to_cpu(virt_to_bus(tmp->select)));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 0, le32_to_cpu(cmd->cmd_len));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, le32_to_cpu(virt_to_bus(cmd->cmnd)));
+    patch_dsa_32(tmp->dsa, dsa_dataout, 0, le32_to_cpu(cmd_dataout ? 
            virt_to_bus (cmd_dataout)
-       : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
-    patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ? 
+       : virt_to_bus (hostdata->script) + hostdata->E_other_transfer));
+    patch_dsa_32(tmp->dsa, dsa_datain, 0, le32_to_cpu(cmd_datain ? 
            virt_to_bus (cmd_datain) 
-       : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+       : virt_to_bus (hostdata->script) + hostdata->E_other_transfer));
     /* 
      * XXX - need to make endian aware, should use separate variables
      * for both status and message bytes.
      */
-    patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_msgin, 0, le32_to_cpu(1));
 /* 
  * FIXME : these only works for little endian.  We probably want to 
  *     provide message and status fields in the NCR53c7x0_cmd 
  *     structure, and assign them to cmd->result when we're done.
  */
-    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
-    patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, le32_to_cpu(virt_to_bus(&cmd->result) + 1));
+    patch_dsa_32(tmp->dsa, dsa_status, 0, le32_to_cpu(1));
+    patch_dsa_32(tmp->dsa, dsa_status, 1, le32_to_cpu(virt_to_bus(&cmd->result)));
+    patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, le32_to_cpu(1));
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 1, 
-       virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+       le32_to_cpu(virt_to_bus(&(hostdata->NCR53c7xx_msg_nop))));
     
     /*
      * Generate code for zero or more of the DATA IN, DATA OUT phases 
@@ -3779,15 +3835,15 @@ create_cmd (Scsi_Cmnd *cmd) {
 
        if (datain) {
            /* CALL other_in, WHEN NOT DATA_IN */  
-           cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
+           cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
                DCMD_TCI_IO) << 24) | 
-               DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
-           cmd_datain[1] = virt_to_bus (hostdata->script) + 
-               hostdata->E_other_in;
+               DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+           cmd_datain[1] = le32_to_cpu(virt_to_bus (hostdata->script) + 
+               hostdata->E_other_in);
            /* MOVE count, buf, WHEN DATA_IN */
-           cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
-               << 24) | count;
-           cmd_datain[3] = buf;
+           cmd_datain[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
+               << 24) | count);
+           cmd_datain[3] = le32_to_cpu(buf);
 #if 0
            print_insn (host, cmd_datain, "dynamic ", 1);
            print_insn (host, cmd_datain + 2, "dynamic ", 1);
@@ -3795,14 +3851,14 @@ create_cmd (Scsi_Cmnd *cmd) {
        }
        if (dataout) {
            /* CALL other_out, WHEN NOT DATA_OUT */
-           cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) | 
-               DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
-           cmd_dataout[1] = virt_to_bus(hostdata->script) + 
-               hostdata->E_other_out;
+           cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) | 
+               DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+           cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) + 
+               hostdata->E_other_out);
            /* MOVE count, buf, WHEN DATA+OUT */
-           cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24) 
-               | count;
-           cmd_dataout[3] = buf;
+           cmd_dataout[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24) 
+               | count);
+           cmd_dataout[3] = le32_to_cpu(buf);
 #if 0
            print_insn (host, cmd_dataout, "dynamic ", 1);
            print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -3817,10 +3873,10 @@ create_cmd (Scsi_Cmnd *cmd) {
   
     
     if (datain) {
-       cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
-           DBC_TCI_TRUE;
-       cmd_datain[1] = virt_to_bus(hostdata->script) + 
-           hostdata->E_other_transfer;
+       cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+           DBC_TCI_TRUE);
+       cmd_datain[1] = le32_to_cpu(virt_to_bus(hostdata->script) + 
+           hostdata->E_other_transfer);
 #if 0
        print_insn (host, cmd_datain, "dynamic jump ", 1);
 #endif
@@ -3834,10 +3890,10 @@ create_cmd (Scsi_Cmnd *cmd) {
     }
 #endif
     if (dataout) {
-       cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
-           DBC_TCI_TRUE;
-       cmd_dataout[1] = virt_to_bus(hostdata->script) + 
-           hostdata->E_other_transfer;
+       cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+           DBC_TCI_TRUE);
+       cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) + 
+           hostdata->E_other_transfer);
 #if 0
        print_insn (host, cmd_dataout, "dynamic jump ", 1);
 #endif
@@ -3894,26 +3950,25 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
        || hostdata->state == STATE_DISABLED) {
        printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
            cmd->target, cmd->lun);
-       cmd->result = (DID_BAD_TARGET << 16);
+       cmd->result = DID_BAD_TARGET << 16;
     } else if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
        (hostdata->debug_count_limit == 0)) {
        printk("scsi%d : maximum commands exceeded\n", host->host_no);
-       cmd->result = (DID_BAD_TARGET << 16);
-       cmd->result = (DID_BAD_TARGET << 16);
+       cmd->result = DID_BAD_TARGET << 16;
     } else if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
        switch (cmd->cmnd[0]) {
        case WRITE_6:
        case WRITE_10:
            printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
                host->host_no);
-           cmd->result = (DID_BAD_TARGET << 16);
+           cmd->result = DID_BAD_TARGET << 16;
        }
     } else {
        if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
            hostdata->debug_count_limit != -1) 
            --hostdata->debug_count_limit;
        restore_flags (flags);
-       cmd->result = 0xffff;   /* The NCR will overwrite message
+       cmd->result = le32_to_cpu(0xffff);      /* The NCR will overwrite message
                                       and status with valid data */
        cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
     }
@@ -3967,7 +4022,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
 
     int i;
     NCR53c7x0_local_setup(host);
-#if 0  
+#if 0
     printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no, 
        virt_to_bus(dsa), dsa);
 #endif
@@ -3982,7 +4037,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
 
     if (hostdata->state == STATE_DISABLED) {
        printk("scsi%d : driver disabled\n", host->host_no);
-       tmp->result = (DID_BAD_TARGET << 16);
+       tmp->result = DID_BAD_TARGET << 16;
        cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
        hostdata->free = cmd;
        tmp->scsi_done(tmp);
@@ -4001,18 +4056,18 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
 
        /* Restore this instruction to a NOP once the command starts */
        cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) / 
-           sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
+           sizeof(u32)] = (u32) le32_to_cpu(virt_to_bus ((void *)curr));
        /* Replace the current jump operand.  */
        curr[1] =
-           virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
-           hostdata->E_dsa_code_template;
+           le32_to_cpu(virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+           hostdata->E_dsa_code_template);
        /* Replace the NOP instruction with a JUMP */
-       curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
-           DBC_TCI_TRUE;
+       curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+           DBC_TCI_TRUE);
     }  else {
        printk ("scsi%d: no free slot\n", host->host_no);
        disable(host);
-       tmp->result = (DID_ERROR << 16);
+       tmp->result = DID_ERROR << 16;
        cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
        hostdata->free = cmd;
        tmp->scsi_done(tmp);
@@ -4101,7 +4156,7 @@ process_issue_queue (unsigned long flags) {
                if (hostdata->state == STATE_DISABLED) {
                    tmp = (Scsi_Cmnd *) hostdata->issue_queue;
                    hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
-                   tmp->result = (DID_BAD_TARGET << 16);
+                   tmp->result = DID_BAD_TARGET << 16;
                    if (tmp->host_scribble) {
                        ((struct NCR53c7x0_cmd *)tmp->host_scribble)->next = 
                            hostdata->free;
@@ -4133,6 +4188,7 @@ process_issue_queue (unsigned long flags) {
                                    (struct NCR53c7x0_cmd *)
                                    tmp->host_scribble);
                            } else {
+                               tmp->result = le32_to_cpu(tmp->result);
                                if (((tmp->result & 0xff) == 0xff) ||
                                    ((tmp->result & 0xff00) == 0xff00)) {
                                    printk ("scsi%d : danger Will Robinson!\n",
@@ -4370,7 +4426,6 @@ NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
     char buf[80];                              /* Debugging sprintf buffer */
     size_t buflen;                             /* Length of same */
 #endif
-
     do {
        done = 1;
        for (host = first_host; host; host = host->next) 
@@ -4449,10 +4504,16 @@ restart:
                        printk ("scsi%d : looking at result of 0x%x\n",
                            host->host_no, cmd->cmd->result);
 #endif
-               
+
+#ifdef __powerpc__
+                       if (tmp->result == le32_to_cpu(0xffff))
+                           continue;
+                       tmp->result = le32_to_cpu(tmp->result);
+#else                  
                        if (((tmp->result & 0xff) == 0xff) ||
                            ((tmp->result & 0xff00) == 0xff00))
                            continue;
+#endif                     
 
                        search_found = 1;
 
@@ -4537,7 +4598,6 @@ restart:
                            printk("scsi%d : no active command\n", host->host_no);
                        }
                    }
-
                    if (istat & ISTAT_SIP) {
                        if (hostdata->options & OPTION_DEBUG_INTR) 
                            printk ("scsi%d : ISTAT_SIP\n", host->host_no);
@@ -4872,12 +4932,12 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
             * from normal dynamic code.
             */
            if (dsp != cmd->residual + 2) {
-               cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+               cmd->residual[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
                        ((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) | 
-                   DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
-               cmd->residual[1] = virt_to_bus(hostdata->script)
+                   DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+               cmd->residual[1] = le32_to_cpu(virt_to_bus(hostdata->script)
                    + ((dcmd & DCMD_BMI_IO)
-                      ? hostdata->E_other_in : hostdata->E_other_out);
+                      ? hostdata->E_other_in : hostdata->E_other_out));
            }
 
            /*
@@ -4885,17 +4945,17 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
             * move instruction, reflecting the pointer and count at the 
             * time of the phase mismatch.
             */
-           cmd->residual[2] = dbc_dcmd + residual;
-           cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+           cmd->residual[2] = le32_to_cpu(dbc_dcmd + residual);
+           cmd->residual[3] = le32_to_cpu(NCR53c7x0_read32(DNAD_REG) - residual);
 
            /*
             * The third and final instruction is a jump to the instruction
             * which follows the instruction which had to be 'split'
             */
            if (dsp != cmd->residual + 2) {
-               cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) 
-                   << 24) | DBC_TCI_TRUE;
-               cmd->residual[5] = virt_to_bus(dsp_next);
+               cmd->residual[4] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) 
+                   << 24) | DBC_TCI_TRUE);
+               cmd->residual[5] = le32_to_cpu(virt_to_bus(dsp_next));
            }
 
            /*
@@ -5375,11 +5435,11 @@ print_insn (struct Scsi_Host *host, const u32 *insn,
  */
        sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)", 
            (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,  
-           insn[0], insn[1], bus_to_virt (insn[1]));
+           insn[0], insn[1], bus_to_virt (le32_to_cpu(insn[1])));
        tmp = buf + strlen(buf);
        if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)  {
            sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2], 
-               bus_to_virt(insn[2]));
+               bus_to_virt(le32_to_cpu(insn[2])));
            size = 3;
        } else {
            sprintf (tmp, "\n");
@@ -5439,6 +5499,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
     struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *) 
        host->hostdata : NULL;
     unsigned long flags;
+    unsigned long result;
     struct NCR53c7x0_cmd *curr, **prev;
     Scsi_Cmnd *me, **last;
 #if 0
@@ -5530,7 +5591,8 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
          &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
-       if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+       result = le32_to_cpu(cmd->result);
+       if ((result & 0xff) != 0xff && (result & 0xff00) != 0xff00) {
            if (prev)
                *prev = (struct NCR53c7x0_cmd *) curr->next;
            curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
@@ -5561,8 +5623,9 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
        cmd->host_scribble = NULL;
     }
 
-    if (((cmd->result & 0xff00) == 0xff00) ||
-       ((cmd->result & 0xff) == 0xff)) {
+    result = le32_to_cpu(cmd->result);
+    if (((result & 0xff00) == 0xff00) ||
+       ((result & 0xff) == 0xff)) {
        printk ("scsi%d : did this command ever run?\n", host->host_no);
        cmd->result = DID_ABORT << 16;
     } else {
@@ -5709,7 +5772,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
        (insn >= ncmd->residual &&
            insn < (ncmd->residual + 
                sizeof(ncmd->residual))))) {
-           ptr = bus_to_virt(insn[3]);
+           ptr = bus_to_virt(le32_to_cpu(insn[3]));
 
            if ((buffers = cmd->use_sg)) {
                for (offset = 0, 
@@ -5764,7 +5827,7 @@ print_progress (Scsi_Cmnd *cmd) {
            continue;
        if (!i) {
            where = "saved";
-           ptr = bus_to_virt(ncmd->saved_data_pointer);
+           ptr = bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer));
        } else {
            where = "active";
            ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
@@ -5782,9 +5845,9 @@ print_progress (Scsi_Cmnd *cmd) {
                cmd->host->host_no, where);
            if (ncmd) {
                size = print_insn (cmd->host, 
-                   bus_to_virt(ncmd->saved_data_pointer), "", 1);
+                   bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)), "", 1);
                print_insn (cmd->host, 
-                   bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+                   bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)) + size * sizeof(u32),
                    "", 1);
            }
        }
@@ -5809,9 +5872,9 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
            "        + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
            prefix ? prefix : "",
            host->host_no,  virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
-           dsa[hostdata->dsa_msgout / sizeof(u32)],
-           dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
-           bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+           le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+           le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]),
+           bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1])));
 
     /* 
      * Only print messages if they're sane in length so we don't
@@ -5819,10 +5882,10 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
      * anything.
      */
 
-    if (dsa[hostdata->dsa_msgout / sizeof(u32)] < 
+    if (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]) < 
            sizeof (hostdata->free->select)) 
-       for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
-           ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]); 
+       for (i = le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+           ptr = bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1])); 
            i > 0 && !check_address ((unsigned long) ptr, 1);
            ptr += len, i -= len) {
            printk("               ");
@@ -5833,8 +5896,8 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
        }
 
     printk("        + %d : select_indirect = 0x%x\n",
-       hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
-    cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+       hostdata->dsa_select, le32_to_cpu(dsa[hostdata->dsa_select / sizeof(u32)]));
+    cmd = (Scsi_Cmnd *) bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_cmnd / sizeof(u32)]));
     printk("        + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
           (u32) virt_to_bus(cmd));
     if (cmd) {
@@ -5844,7 +5907,7 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
     } else
        printk("\n");
     printk("        + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
-       dsa[hostdata->dsa_next / sizeof(u32)]);
+       le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
     if (cmd) { 
        printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
               "                   script : ",
@@ -5891,8 +5954,7 @@ print_queues (struct Scsi_Host *host) {
                    host->host_no, cmd->pid);
            /* print_dsa does sanity check on address, no need to check */
            else
-               print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
-                   -> dsa, "");
+               print_dsa (host, le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa), "");
        } else 
            printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
                host->host_no, cmd->pid, cmd->target, cmd->lun);
@@ -5917,7 +5979,7 @@ print_queues (struct Scsi_Host *host) {
            left > 0; curr += 2, --left)
        if (curr[0] != hostdata->NOP_insn) 
 /* FIXME : convert pointer to dsa_begin to pointer to dsa. */
-           print_dsa (host, bus_to_virt (curr[1] - 
+           print_dsa (host, bus_to_virt (le32_to_cpu(curr[1]) - 
                (hostdata->E_dsa_code_begin - 
                hostdata->E_dsa_code_template)), "");
     printk ("scsi%d : end schedule dsa array\n", host->host_no);
@@ -5925,7 +5987,7 @@ print_queues (struct Scsi_Host *host) {
     printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
            
     for (left = host->can_queue, 
-       dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+       dsa = bus_to_virt (le32_to_cpu(hostdata->reconnect_dsa_head));
        left >= 0 && dsa; 
        dsa = next_dsa) {
        save_flags (flags);
@@ -5937,7 +5999,7 @@ print_queues (struct Scsi_Host *host) {
        }
        else 
        {
-           next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+           next_dsa = bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
            print_dsa (host, dsa, "");
        }
        restore_flags(flags);
@@ -6131,7 +6193,7 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
        for (i = 0, curr = (u32 *) hostdata->schedule; 
            i < host->can_queue; ++i, curr += 2) {
            curr[0] = hostdata->NOP_insn;
-           curr[1] = 0xdeadbeef;
+           curr[1] = le32_to_cpu(0xdeadbeef);
        }
        hostdata->curr = NULL;
     }
index cfddfa6815d44740636b804bb751809b523e41ae..cb0071e9d76ff474767183246e6c4c35630def34 100644 (file)
@@ -1574,7 +1574,7 @@ struct NCR53c7x0_hostdata {
        if (hostdata->options & OPTION_DEBUG_DSA)                       \
            printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n",    \
                #dsa, #symbol, hostdata->##symbol,                      \
-               (word), (u32) (value));                                 \
+               (word), (u32) le32_to_cpu(value));                      \
        }
 
 /* Paranoid people could use panic() here. */
index e6f98e4e49301ca46c51f9f5c47d8452b1f783fa..d103dc19cf3fec9ddacbcd2e522415a687e3ccf9 100644 (file)
@@ -421,12 +421,8 @@ BusLogic.o: BusLogic.c FlashPoint.c
 aha152x.o: aha152x.c
        $(CC) $(CFLAGS) $(AHA152X) -c aha152x.c 
 
-aic7xxx_asm:   aic7xxx_asm.c
-       $(HOSTCC) -o $@ aic7xxx_asm.c
-
-aic7xxx.c: aic7xxx_seq.h
-aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq
-       ./aic7xxx_asm -o $@ aic7xxx.seq
+aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
+       $(CC) $(CFLAGS) -c -o $@ aic7xxx.c
 
 seagate.o: seagate.c
        $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY -c seagate.c 
index ccbf4a6e2ab26d2fad1760d4254c8c86c4715d51..5ec8a51d2e065d1194adb08789b2a85e36c1cf97 100644 (file)
@@ -1,5 +1,5 @@
                            AIC7xxx Driver for Linux
-                                April 15, 1996
+                                July 20, 1997
 
 Introduction
 ------------------------
@@ -31,6 +31,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     -----------------------
     AIC-777x   
     AIC-785x
+    AIC-786x
     AIC-787x
     AIC-788x
 
@@ -58,6 +59,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     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)
 
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
     author of the driver. John has since retired from the project. Thanks
@@ -82,10 +84,17 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
 
     Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
     
-  Command line options
-  ------------------------
+  Command line options ("aic7xxx=option[,option...]")
+  ---------------------------------------------------
     "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.
 
   /proc support
   ------------------------
@@ -106,10 +115,37 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
       - US Linux mirror of Teleport site
     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
 
-$Revision: 3.0 $
+(Modified by D. Eischen, 7/20/97)
+
+$Revision: 3.1a $
 
index 96e66defdd8a2a4bd7e4a48c1b5ae06db3bb98ca..005c889d7503a8e1d7f4bc49abeb4213d0067070 100644 (file)
@@ -1,5 +1,3 @@
-#define EXPERIMENTAL_FLAGS 0
-
 /*+M*************************************************************************
  * Adaptec AIC7xxx device driver for Linux.
  *
  * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
  * ANSI SCSI-2 specification (draft 10c), ...
  *
- * ----------------------------------------------------------------
- *  Modified to include support for wide and twin bus adapters,
- *  DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ * --------------------------------------------------------------------------
+ *
+ *  Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ *  Substantially modified to include support for wide and twin bus
+ *  adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
  *  SCB paging, and other rework of the code.
  *
- *  Parts of this driver are based on the FreeBSD driver by Justin
- *  T. Gibbs.
+ *  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.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
+ *---------------------------------------------------------------------------
+ *
+ *  Thanks also go to (in alphabetical order) the following:
+ *
+ *    Rory Bolt     - Sequencer bug fixes
+ *    Jay Estabrook - Initial DEC Alpha support
+ *    Doug Ledford  - Much needed abort/reset bug fixes
+ *    Kai Makisara  - DMAing of SCBs
  *
  *  A Boot time option was also added for not resetting the scsi bus.
  *
- *    Form:  aic7xxx=extended,no_reset
+ *    Form:  aic7xxx=extended
+ *           aic7xxx=no_reset
+ *           aic7xxx=ultra
+ *           aic7xxx=irq_trigger:[0,1]  # 0 edge, 1 level
+ *           aic7xxx=verbose
  *
- *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
  *
- *  $Id: aic7xxx.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
  *-M*************************************************************************/
 
 #ifdef MODULE
 #include "scsi.h"
 #include "hosts.h"
 #include "aic7xxx.h"
+
+#include "aic7xxx/sequencer.h"
+#include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
+#include "aic7xxx_seq.h"
 #include <linux/stat.h>
 #include <linux/malloc.h>      /* for kmalloc() */
 
  */
 #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
 
-static struct proc_dir_entry proc_scsi_aic7xxx = {
+struct proc_dir_entry proc_scsi_aic7xxx = {
     PROC_SCSI_AIC7XXX, 7, "aic7xxx",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
+    S_IFDIR | S_IRUGO | S_IXUGO, 2,
+    0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 4.0 $"
+#define AIC7XXX_C_VERSION  "$Revision: 4.1 $"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
-#define MIN(a,b)        ((a < b) ? a : b)
+#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_LUNS -1
 #ifndef TRUE
 #  define TRUE 1
 #endif
@@ -107,11 +165,8 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
  *     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.
- *
- *   o DMAing of SCBs - thanks to Kai Makisara, this now works.
- *     This define is now taken out and DMAing of SCBs is always
- *     performed (8/12/95 - DE).
+ *   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
@@ -140,16 +195,16 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
  *     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 get probed and recognized as three different adapters,
- *     but all three controllers can share the same external bank of
- *     255 SCBs.  If you enable AIC7XXX_SHARE_SCBS, then the driver
- *     will attempt to share the common bank of SCBs between the three
- *     controllers of the 3985.  This is experimental and hasn't
- *     been tested.  By default, we do not share the bank of SCBs,
- *     and force the controllers to use their own internal bank of
- *     16 SCBs.  Please let us know if sharing the SCB array works.
+ *   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
@@ -162,43 +217,54 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
  *  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, 06/30/96
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
  */
 
-/* Uncomment this for testing twin bus support. */
-#define AIC7XXX_TWIN_SUPPORT
-
 /* Uncomment this for tagged queueing. */
-/* #define AIC7XXX_TAGGED_QUEUEING */
+#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
+#define AIC7XXX_TAGGED_QUEUEING
+#endif
 
 /*
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-/* #define AIC7XXX_CMDS_PER_LUN 8 */
+#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
+#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#endif
 
 /* Set this to the delay in seconds after SCSI bus reset. */
+#ifdef CONFIG_AIC7XXX_RESET_DELAY
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
+#else
 #define AIC7XXX_RESET_DELAY 15
+#endif
 
 /*
- * Uncomment the following define for collection of SCSI transfer statistics
- * for the /proc filesystem.
+ * Control collection of SCSI transfer statistics for the /proc filesystem.
  *
  * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
  * NOTE: This does affect performance since it has to maintain statistics.
  */
-/* #define AIC7XXX_PROC_STATS */
+#ifdef CONFIG_AIC7XXX_PROC_STATS
+#define AIC7XXX_PROC_STATS
+#endif
 
 /*
- * Uncomment the following to enable SCB paging.
+ * Enable SCB paging.
  */
-/* #define AIC7XXX_PAGE_ENABLE */
+#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
+#define AIC7XXX_PAGE_ENABLE
+#endif
 
 /*
- * Uncomment the following to enable sharing of the external bank
- * of 255 SCBs for the 3985.
+ * 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.
  */
-#define AIC7XXX_SHARE_SCBS
+#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
+#define AIC7XXX_USE_EXT_SCBRAM
+#endif
 
 /*
  * For debugging the abort/reset code.
@@ -210,6 +276,87 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
  */
 #define AIC7XXX_DEBUG
 
+/*
+ * 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
+ * controller, the second set will be used for the second detected
+ * aic7xxx controller, and so on.  These values will *only* be used
+ * for targets that are tagged queueing capable; these values will
+ * be ignored in all other cases.  The tag_commands is an array of
+ * 16 to allow for wide and twin adapters.  Twin adapters will use
+ * indexes 0-7 for channel 0, and indexes 8-15 for channel 1.
+ *
+ * *** Determining commands per LUN ***
+ * 
+ * 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.
+ *
+ */
+/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
+
+#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+typedef struct
+{
+  char tag_commands[16];   /* Allow for wide/twin channel 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).
+ */
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+/*
+ * 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
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ * driver to use its own algorithm for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3.  It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * 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}},
+  {DEFAULT_TAG_COMMANDS},
+  {{-1, 16, 4, -1, 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
  */
@@ -232,14 +379,15 @@ typedef enum {
   AIC_7882,    /* PCI  aic7882 on 3940 Ultra */
   AIC_7883,    /* PCI  aic7883 on 3985 Ultra */
   AIC_7884     /* PCI  aic7884 on 294x Ultra Differential */
-} aha_type;
+} aha_chip_type;
 
 typedef enum {
   AIC_777x,    /* AIC-7770 based */
-  AIC_785x,    /* AIC-7850 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 */
-} aha_chip_type;
+  AIC_788x     /* AIC-7880 based (ultra) */
+} aha_chip_class_type;
 
 typedef enum {
   AIC_SINGLE,  /* Single Channel */
@@ -269,24 +417,24 @@ typedef enum {
  * Don't forget to change this when changing the types!
  */
 static const char *board_names[] = {
-  "<AIC-7xxx Unknown>",                /* AIC_NONE */
-  "AIC-7770",                  /* AIC_7770 */
-  "AHA-2740",                  /* AIC_7771 */
-  "AHA-2840",                  /* AIC_284x */
-  "AIC-7850",                  /* AIC_7850 */
-  "AIC-7855",                  /* AIC_7855 */
-  "AIC-7850 Ultra",            /* AIC_7860 */
-  "AHA-2940A Ultra",           /* AIC_7861 */
-  "AIC-7870",                  /* AIC_7870 */
-  "AHA-2940",                  /* AIC_7871 */
-  "AHA-3940",                  /* AIC_7872 */
-  "AHA-3985",                  /* AIC_7873 */
-  "AHA-2940 Differential",     /* AIC_7874 */
-  "AIC-7880 Ultra",            /* AIC_7880 */
-  "AHA-2940 Ultra",            /* AIC_7881 */
-  "AHA-3940 Ultra",            /* AIC_7882 */
-  "AHA-3985 Ultra",            /* AIC_7883 */
-  "AHA-2940 Ultra Differential"        /* AIC_7884 */
+  "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 */
 };
 
 /*
@@ -310,12 +458,17 @@ static const char *board_names[] = {
  */
 #define DID_RETRY_COMMAND DID_ERROR
 
+#define HSCSIID        0x07
+#define HWSCSIID       0x0F
+#define SCSI_RESET     0x040
+
 /*
  * EISA/VL-bus stuff
  */
 #define MINSLOT                1
 #define MAXSLOT                15
 #define SLOTBASE(x)    ((x) << 12)
+#define BASE_TO_SLOT(x) ((x) >> 12)
 
 /*
  * Standard EISA Host ID regs  (Offset from slot base)
@@ -333,14 +486,6 @@ static const char *board_names[] = {
 
 #define INTDEF         0x5C            /* Interrupt Definition Register */
 
-/*
- * Some defines for the HCNTRL register.
- */
-#define        REQ_PAUSE       IRQMS | INTEN | PAUSE
-#define        UNPAUSE_274X    IRQMS | INTEN
-#define        UNPAUSE_284X    INTEN
-#define        UNPAUSE_294X    IRQMS | INTEN
-
 /*
  * AIC-78X0 PCI registers
  */
@@ -377,7 +522,7 @@ static const char *board_names[] = {
  * each word, while the C56 and C66 (4096 bits) use 8 bits to
  * address each word.
  */
-typedef enum {c46 = 6, c56_66 = 8} seeprom_chip_type;
+typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
 
 /*
  *
@@ -417,15 +562,15 @@ struct seeprom_config {
 /*
  * Host Adapter Control Bits
  */
-/* UNUSED               0x0001 */
+#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 (non-wide 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 IC initialization */
+#define CFRESETB       0x0040          /* reset SCSI bus at boot */
 /* UNUSED              0xFF80 */
   unsigned short adapter_control;      /* word 17 */
 
@@ -448,36 +593,17 @@ struct seeprom_config {
   unsigned short checksum;             /* word 31 */
 };
 
+#define SELBUS_MASK            0x0a
+#define        SELNARROW       0x00
+#define        SELBUSB         0x08
+#define SINGLE_BUS             0x00
 
-#define SCSI_RESET 0x040
-
-/*
- * Pause the sequencer and wait for it to actually stop - this
- * is important since the sequencer can disable pausing for critical
- * sections.
- */
-#define PAUSE_SEQUENCER(p) \
-  synchronize_irq();                                   \
-  outb(p->pause, HCNTRL + p->base);                    \
-  while ((inb(HCNTRL + p->base) & PAUSE) == 0)         \
-    ;                                                  \
-
-/*
- * Unpause the sequencer. Unremarkable, yet done often enough to
- * warrant an easy way to do it.
- */
-#define UNPAUSE_SEQUENCER(p) \
-  outb(p->unpause, HCNTRL + p->base)
-
-/*
- * Restart the sequencer program from address zero
- */
-#define RESTART_SEQUENCER(p) \
-  do {                                                 \
-    outb(SEQRESET | FASTMODE, SEQCTL + p->base);       \
-  } while (inb(SEQADDR0 + p->base) != 0 &&             \
-          inb(SEQADDR1 + p->base) != 0);               \
-  UNPAUSE_SEQUENCER(p);
+#define SCB_TARGET(scb)         \
+       (((scb)->hscb->target_channel_lun & TID) >> 4)
+#define SCB_LUN(scb)            \
+       ((scb)->hscb->target_channel_lun & LID)
+#define SCB_IS_SCSIBUS_B(scb)   \
+       (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
 
 /*
  * If an error occurs during a data transfer phase, run the command
@@ -540,12 +666,6 @@ static struct Scsi_Host *aic7xxx_boards[NR_IRQS + 1];
  */
 static int aic7xxx_spurious_count;
 
-/*
- * The driver keeps up to four scb structures per card in memory. Only the
- * first 25 bytes of the structure are valid for the hardware, the rest used
- * for driver level bookkeeping.
- */
-
 /*
  * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
  * in the scatter-gather lists.  We need to convert the virtual
@@ -559,20 +679,28 @@ struct hw_scatterlist {
 /*
  * Maximum number of SG segments these cards can support.
  */
-#define        MAX_SG 256
+#define        AIC7XXX_MAX_SG 27
 
-struct aic7xxx_scb {
+/*
+ * 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
+
+
+struct aic7xxx_hwscb {
 /* ------------    Begin hardware supported fields    ---------------- */
 /* 0*/  unsigned char control;
 /* 1*/  unsigned char target_channel_lun;       /* 4/1/3 bits */
 /* 2*/  unsigned char target_status;
 /* 3*/  unsigned char SG_segment_count;
-/* 4*/  unsigned char SG_list_pointer[4] __attribute__ ((packed));
+/* 4*/  unsigned int  SG_list_pointer;
 /* 8*/  unsigned char residual_SG_segment_count;
-/* 9*/  unsigned char residual_data_count[3] __attribute__ ((packed));
-/*12*/  unsigned char data_pointer[4] __attribute__ ((packed));
-/*16*/  unsigned int  data_count __attribute__ ((packed)); /* must be 32 bits */
-/*20*/  unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
+/* 9*/  unsigned char residual_data_count[3];
+/*12*/  unsigned int  data_pointer;
+/*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
@@ -580,29 +708,47 @@ struct aic7xxx_scb {
 #define SCB_PIO_TRANSFER_SIZE  26      /* amount we need to upload/download
                                         * via PIO to initialize a transaction.
                                         */
-/*26*/  u_char next;                    /* Used to thread SCBs awaiting selection
+/*26*/  unsigned char next;             /* Used to thread SCBs awaiting selection
                                          * or disconnected down in the sequencer.
                                          */
-       /*-----------------end of hardware supported fields----------------*/
-       Scsi_Cmnd          *cmd;        /* Scsi_Cmnd for this scb */
-        struct aic7xxx_scb *q_next;     /* next scb in queue */
-#define SCB_FREE               0x00
-#define SCB_ACTIVE             0x01
-#define SCB_ABORTED            0x02
-#define SCB_DEVICE_RESET       0x04
-#define SCB_IMMED              0x08
-#define SCB_SENSE              0x10
-#define SCB_QUEUED_FOR_DONE    0x40
-#define SCB_PAGED_OUT          0x80
-#define SCB_WAITINGQ           0x100
-#define SCB_ASSIGNEDQ          0x200
-#define SCB_SENTORDEREDTAG     0x400
-#define SCB_IN_PROGRESS        (SCB_ACTIVE | SCB_PAGED_OUT | \
-                                SCB_WAITINGQ | SCB_ASSIGNEDQ)
-       int                 state;          /* current state of scb */
-       unsigned int        position;       /* Position in scb array */
-       struct hw_scatterlist  sg_list[MAX_SG]; /* SG list in adapter format */
-       unsigned char       sense_cmd[6];   /* Allocate 6 characters for sense command */
+/*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
+                                         */
+};
+
+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_flag_type;
+
+struct aic7xxx_scb {
+        struct aic7xxx_hwscb  *hscb;          /* corresponding hardware 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          sg_count;
+       unsigned char          sense_cmd[6];  /*
+                                               * Allocate 6 characters for
+                                               * sense command.
+                                               */
 };
 
 /*
@@ -627,20 +773,17 @@ static unsigned char
 generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
 
 typedef struct {
+  struct aic7xxx_hwscb *hscbs;
   scb_queue_type free_scbs;        /*
                                     * SCBs assigned to free slot on
                                     * card (no paging required)
                                     */
-  int            numscbs;          /* current number of scbs */
-  int            activescbs;       /* active scbs */
-} scb_usage_type;
-
-/*
- * 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
+  unsigned char  numscbs;          /* current number of scbs */
+  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;
 
 /*
  * Define a structure used for each host adapter, only one per IRQ.
@@ -648,17 +791,26 @@ typedef struct {
 struct aic7xxx_host {
   struct Scsi_Host        *host;             /* pointer to scsi host */
   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 */
   int                      base;             /* card base address */
-  int                      maxhscbs;         /* hardware SCBs */
-  int                      maxscbs;          /* max SCBs (including pageable) */
-#define A_SCANNED              0x0001
-#define B_SCANNED              0x0002
-#define EXTENDED_TRANSLATION   0x0004
-#define HAVE_SEEPROM           0x0008
-#define ULTRA_ENABLED          0x0010
-#define PAGE_ENABLED           0x0020
-#define IN_ISR                 0x0040
-#define USE_DEFAULTS           0x0080
+  unsigned int             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 */
@@ -669,36 +821,22 @@ struct aic7xxx_host {
   unsigned short           wdtr_pending;
   unsigned short           orderedtag;
   unsigned short           discenable;      /* Targets allowed to disconnect */
-  aha_type                 type;             /* card type */
-  aha_chip_type            chip_type;        /* chip base type */
+  aha_chip_type            chip_type;        /* card type */
+  aha_chip_class_type      chip_class;
   aha_bus_type             bus_type;         /* normal/twin/wide bus */
-  char *                   mbase;            /* I/O memory address */
-  unsigned char            chan_num;         /* for 3940/3985, channel number */
+  unsigned char            chan_num;         /* for 39xx, channel number */
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
   unsigned char            qcntmask;
-  struct seeprom_config    seeprom;
+  unsigned char            qfullcount;
+  unsigned char            curqincnt;
   struct Scsi_Host        *next;             /* allow for multiple IRQs */
-  struct aic7xxx_scb      *scb_array[AIC7XXX_MAXSCB];  /* active commands */
-  struct aic7xxx_scb      *pagedout_ntscbs[16];  /*
-                                                  * paged-out, non-tagged scbs
-                                                  * indexed by target.
-                                                  */
-  scb_queue_type           page_scbs;        /*
-                                              * SCBs that will require paging
-                                              * before use (no assigned slot)
-                                              */
+  unsigned char            activescbs;       /* active scbs */
   scb_queue_type           waiting_scbs;     /*
-                                              * SCBs waiting to be paged and
-                                              * started.
+                                              * SCBs waiting for space in
+                                              * the QINFIFO.
                                               */
-  scb_queue_type           assigned_scbs;    /*
-                                              * SCBs that were waiting but have
-                                              * have now been assigned a slot
-                                              * by aic7xxx_free_scb
-                                              */
-  scb_usage_type           scb_usage;
-  scb_usage_type          *scb_link;
+  scb_data_type           *scb_data;
 
   struct aic7xxx_cmd_queue {
     Scsi_Cmnd *head;
@@ -710,6 +848,7 @@ struct aic7xxx_host {
 #define  BUS_DEVICE_RESET_PENDING       0x02
     int  flags;
     int  commands_sent;
+    int  active_cmds;
   } device_status[16];
 #ifdef AIC7XXX_PROC_STATS
   /*
@@ -735,34 +874,10 @@ struct aic7xxx_host {
 #endif /* AIC7XXX_PROC_STATS */
 };
 
-struct aic7xxx_host_config {
-  int              irq;        /* IRQ number */
-  int              mbase;      /* memory base address*/
-  int              base;       /* I/O base address*/
-  int              maxhscbs;   /* hardware SCBs */
-  int              maxscbs;    /* max SCBs (including pageable) */
-  int              unpause;    /* unpause value for HCNTRL */
-  int              pause;      /* pause value for HCNTRL */
-  int              scsi_id;    /* host SCSI ID */
-  int              scsi_id_b;  /* host SCSI ID B channel for twin cards */
-  unsigned int     flags;      /* used the same as struct aic7xxx_host flags */
-  int              chan_num;   /* for 3940/3985, channel number */
-  unsigned char    busrtime;   /* bus release time */
-  unsigned char    bus_speed;  /* bus speed */
-  unsigned char    qcntmask;
-  aha_type         type;       /* card type */
-  aha_chip_type    chip_type;  /* chip base type */
-  aha_bus_type     bus_type;   /* normal/twin/wide bus */
-  aha_status_type  bios;       /* BIOS is enabled/disabled */
-  aha_status_type  parity;     /* bus parity enabled/disabled */
-  aha_status_type  low_term;   /* bus termination low byte */
-  aha_status_type  high_term;  /* bus termination high byte (wide cards only) */
-};
-
 /*
  * Valid SCSIRATE values. (p. 3-17)
- * Provides a mapping of transfer periods in ns to the proper value to
- * stick in the scsiscfr reg to use that transfer rate.
+ * Provides a mapping of transfer periods in ns/4 to the proper value to
+ * stick in the SCSIRATE reg to use that transfer rate.
  */
 static struct {
   short period;
@@ -771,17 +886,17 @@ static struct {
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
-  {  50,  0x100,  "20.0"  },
-  {  62,  0x110,  "16.0"  },
-  {  75,  0x120,  "13.4"  },
-  { 100,  0x000,  "10.0"  },
-  { 125,  0x010,   "8.0"  },
-  { 150,  0x020,   "6.67" },
-  { 175,  0x030,   "5.7"  },
-  { 200,  0x040,   "5.0"  },
-  { 225,  0x050,   "4.4"  },
-  { 250,  0x060,   "4.0"  },
-  { 275,  0x070,   "3.6"  }
+  { 12,  0x100,  "20.0"  },
+  { 15,  0x110,  "16.0"  },
+  { 18,  0x120,  "13.4"  },
+  { 25,  0x000,  "10.0"  },
+  { 31,  0x010,   "8.0"  },
+  { 37,  0x020,   "6.67" },
+  { 43,  0x030,   "5.7"  },
+  { 50,  0x040,   "5.0"  },
+  { 56,  0x050,   "4.4"  },
+  { 62,  0x060,   "4.0"  },
+  { 68,  0x070,   "3.6"  }
 };
 
 static int num_aic7xxx_syncrates =
@@ -790,166 +905,51 @@ static int num_aic7xxx_syncrates =
 #ifdef CONFIG_PCI
 static int number_of_3940s = 0;
 static int number_of_3985s = 0;
-#ifdef AIC7XXX_SHARE_SCBS
-static scb_usage_type *shared_3985_scbs = NULL;
-#endif
-#endif CONFIG_PCI
+#endif /* CONFIG_PCI */
 
 #ifdef AIC7XXX_DEBUG
 
-static void
-debug_config(struct aic7xxx_host_config *p)
-{
-  int scsi_conf;
-  unsigned char brelease;
-  unsigned char dfthresh;
-
-  static int DFT[] = { 0, 50, 75, 100 };
-  static int SST[] = { 256, 128, 64, 32 };
-  static const char *BUSW[] = { "", "-TWIN", "-WIDE" };
-
-  scsi_conf = inb(SCSICONF + p->base);
-
-  /*
-   * Scale the Data FIFO Threshhold and the Bus Release Time; they are
-   * stored in formats compatible for writing to sequencer registers.
-   */
-  dfthresh = p->bus_speed  >> 6;
-
-  if (p->chip_type == AIC_777x)
-  {
-    brelease = p->busrtime >> 2;
-  }
-  else
-  {
-    brelease = p->busrtime;
-  }
-  if (brelease == 0)
-  {
-    brelease = 2;
-  }
-
-  switch (p->type)
-  {
-    case AIC_7770:
-    case AIC_7771:
-      printk("%s%s AT EISA SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
-             p->base >> 12);
-      break;
-
-    case AIC_284x:
-      printk("%s%s AT VLB SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
-             p->base >> 12);
-      break;
-
-    case AIC_7850:
-    case AIC_7855:
-    case AIC_7860:
-    case AIC_7861:
-    case AIC_7870:
-    case AIC_7871:
-    case AIC_7872:
-    case AIC_7873:
-    case AIC_7874:
-    case AIC_7880:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7883:
-    case AIC_7884:
-      printk("%s%s (PCI-bus), I/O 0x%x, Mem 0x%x:\n", board_names[p->type],
-             BUSW[p->bus_type], p->base, p->mbase);
-      break;
-
-    default:
-      panic("aic7xxx: (debug_config) internal error.\n");
-  }
-
-  printk("    irq %d\n"
-        "    bus release time %d bclks\n"
-        "    data fifo threshold %d%%\n",
-        p->irq,
-        brelease,
-        DFT[dfthresh]);
-
-  printk("    SCSI CHANNEL A:\n"
-        "        scsi id %d\n"
-        "        scsi selection timeout %d ms\n"
-        "        scsi bus reset at power-on %sabled\n",
-        scsi_conf & 0x07,
-        SST[(scsi_conf >> 3) & 0x03],
-        (scsi_conf & 0x40) ? "en" : "dis");
-
-  if ((p->chip_type == AIC_777x) && (p->parity == AIC_UNKNOWN))
-  {
-    /*
-     * Set the parity for 7770 based cards.
-     */
-    p->parity = (scsi_conf & 0x20) ? AIC_ENABLED : AIC_DISABLED;
-  }
-  if (p->parity != AIC_UNKNOWN)
-  {
-    printk("        scsi bus parity %sabled\n",
-          (p->parity == AIC_ENABLED) ? "en" : "dis");
-  }
-
-  if ((p->type == AIC_7770) || (p->type == AIC_7771))
-  {
-    p->low_term = (scsi_conf & 0x80) ? AIC_ENABLED : AIC_DISABLED;
-  }
-  if (p->low_term != AIC_UNKNOWN)
-  {
-    printk("        scsi bus termination (low byte) %sabled\n",
-         (p->low_term == AIC_ENABLED) ? "en" : "dis");
-  }
-  if ((p->bus_type == AIC_WIDE) && (p->high_term != AIC_UNKNOWN))
-  {
-    printk("        scsi bus termination (high byte) %sabled\n",
-         (p->high_term == AIC_ENABLED) ? "en" : "dis");
-  }
-}
-
 #if 0
 static void
 debug_scb(struct aic7xxx_scb *scb)
 {
-  printk("control 0x%x, tcl 0x%x, sg_count %d, sg_ptr 0x%x, cmdp 0x%x, cmdlen %d\n",
-         scb->control, scb->target_channel_lun, scb->SG_segment_count,
-         (scb->SG_list_pointer[3] << 24) | (scb->SG_list_pointer[2] << 16) |
-         (scb->SG_list_pointer[1] << 8) | scb->SG_list_pointer[0],
-         (scb->SCSI_cmd_pointer[3] << 24) | (scb->SCSI_cmd_pointer[2] << 16) |
-         (scb->SCSI_cmd_pointer[1] << 8) | scb->SCSI_cmd_pointer[0],
-         scb->SCSI_cmd_length);
-  printk("reserved 0x%x, target status 0x%x, resid SG count %d, resid data count %d\n",
-         (scb->RESERVED[1] << 8) | scb->RESERVED[0], scb->target_status,
-         scb->residual_SG_segment_count,
-         ((scb->residual_data_count[2] << 16) |
-          (scb->residual_data_count[1] <<  8) |
-          (scb->residual_data_count[0]));
-  printk("data ptr 0x%x, data count %d, next waiting %d\n",
-         (scb->data_pointer[3] << 24) | (scb->data_pointer[2] << 16) |
-         (scb->data_pointer[1] << 8) | scb->data_pointer[0],
-         scb->data_count, scb->next_waiting);
-  printk("next ptr 0x%lx, Scsi Cmnd 0x%lx, state 0x%x, position %d\n",
-         (unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
-         scb->position);
+  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,
+    hscb->SCSI_cmd_pointer );
+  printk("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
+    hscb->data_count,
+    hscb->data_pointer,
+    hscb->SG_segment_count,
+    hscb->SG_list_pointer);
+  printk("        sg_addr:%lx sg_len:%ld\n",
+    hscb->sg_list[0].address,
+    hscb->sg_list[0].length);
 }
 #endif
 
 #else
-#  define debug_config(x)
 #  define debug_scb(x)
 #endif AIC7XXX_DEBUG
 
-#define TCL_OF_SCB(x)  (((x)->target_channel_lun >> 4) & 0xf),  \
-                       (((x)->target_channel_lun >> 3) & 0x01), \
-                       ((x)->target_channel_lun & 0x07)
+#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
+                        (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+                        ((scb->hscb)->target_channel_lun & 0x07)
 
-#define TARGET_INDEX(x)  ((x)->target | ((x)->channel << 3))
+#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 TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
 
 /*
  * XXX - these options apply unilaterally to _all_ 274x/284x/294x
- *       cards in the system. This should be fixed, but then,
- *       does anyone really have more than one in a machine?
+ *       cards in the system.  This should be fixed.
  */
 static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
 static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
@@ -959,6 +959,53 @@ static int aic7xxx_irq_trigger = -1;         /*
                                               *  1 use level triggered
                                               */
 static int aic7xxx_enable_ultra = 0;         /* enable ultra SCSI speeds */
+static int aic7xxx_verbose = 0;                     /* verbose messages */
+
+
+/****************************************************************************
+ *
+ * These functions are not used yet, but when we do memory mapped
+ * IO, we'll use them then.
+ *
+ ***************************************************************************/
+static inline unsigned char
+aic_inb(struct aic7xxx_host *p, long port)
+{
+  if (p->maddr != NULL)
+    return (p->maddr[port]);
+  else
+    return (inb(p->base + port));
+}
+
+static inline void
+aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
+{
+  if (p->maddr != NULL)
+    p->maddr[port] = val;
+  else
+    outb(val, p->base + port);
+}
+
+static inline void
+aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
+{
+  if (p->maddr != NULL)
+  {
+    __asm __volatile("
+      cld;
+    1:  lodsb;
+      movb %%al,(%0);
+      loop 1b"      :
+              :
+      "r" ((p)->maddr + (port)),
+      "S" ((valp)), "c" ((size))  :
+      "%esi", "%ecx", "%eax");
+  }
+  else
+  {
+    outsb(p->base + port, valp, size);
+  }
+}
 
 /*+F*************************************************************************
  * Function:
@@ -983,6 +1030,7 @@ aic7xxx_setup(char *s, int *dummy)
     { "no_reset",    &aic7xxx_no_reset },
     { "irq_trigger", &aic7xxx_irq_trigger },
     { "ultra",       &aic7xxx_enable_ultra },
+    { "verbose",     &aic7xxx_verbose },
     { NULL,          NULL }
   };
 
@@ -1008,150 +1056,328 @@ aic7xxx_setup(char *s, int *dummy)
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_loadseq
+ *   pause_sequencer
  *
  * Description:
- *   Load the sequencer code into the controller memory.
+ *   Pause the sequencer and wait for it to actually stop - this
+ *   is important since the sequencer can disable pausing for critical
+ *   sections.
  *-F*************************************************************************/
-static void
-aic7xxx_loadseq(int base)
+static inline void
+pause_sequencer(struct aic7xxx_host *p)
 {
-  static unsigned char seqprog[] = {
-    /*
-     * Each sequencer instruction is 29 bits
-     * long (fill in the excess with zeroes)
-     * and has to be loaded from least -> most
-     * significant byte, so this table has the
-     * byte ordering reversed.
-     */
-#   include "aic7xxx_seq.h"
-  };
-
-  /*
-   * When the AIC-7770 is paused (as on chip reset), the
-   * sequencer address can be altered and a sequencer
-   * program can be loaded by writing it, byte by byte, to
-   * the sequencer RAM port - the Adaptec documentation
-   * recommends using REP OUTSB to do this, hence the inline
-   * assembly. Since the address autoincrements as we load
-   * the program, reset it back to zero afterward. Disable
-   * sequencer RAM parity error detection while loading, and
-   * make sure the LOADRAM bit is enabled for loading.
-   */
-  outb(PERRORDIS | SEQRESET | LOADRAM, SEQCTL + base);
-
-  outsb(SEQRAM + base, seqprog, sizeof(seqprog));
-
-  /*
-   * WARNING!  This is a magic sequence!  After extensive
-   * experimentation, it seems that you MUST turn off the
-   * LOADRAM bit before you play with SEQADDR again, else
-   * you will end up with parity errors being flagged on
-   * your sequencer program. (You would also think that
-   * turning off LOADRAM and setting SEQRESET to reset the
-   * address to zero would work, but you need to do it twice
-   * for it to take effect on the address. Timing problem?)
-   */
-  do {
-    /*
-     * Actually, reset it until
-     * the address shows up as
-     * zero just to be safe..
-     */
-    outb(SEQRESET | FASTMODE, SEQCTL + base);
-  } while ((inb(SEQADDR0 + base) != 0) && (inb(SEQADDR1 + base) != 0));
+  outb(p->pause, p->base + HCNTRL);
+  while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+  {
+    ;
+  }
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_delay
+ *   unpause_sequencer
  *
  * Description:
- *   Delay for specified amount of time.
+ *   Unpause the sequencer. Unremarkable, yet done often enough to
+ *   warrant an easy way to do it.
  *-F*************************************************************************/
-static void
-aic7xxx_delay(int seconds)
+static inline void
+unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
 {
-  unsigned long i;
-
-  i = jiffies + (seconds * HZ);  /* compute time to stop */
-
-  while (jiffies < i)
+  if (unpause_always ||
+      ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
   {
-    ;  /* Do nothing! */
+    outb(p->unpause, p->base + HCNTRL);
   }
 }
 
 /*+F*************************************************************************
  * Function:
- *   rcs_version
+ *   restart_sequencer
  *
  * Description:
- *   Return a string containing just the RCS version number from either
- *   an Id or Revision RCS clause.
+ *   Restart the sequencer program from address zero.  This assumes
+ *   that the sequencer is already paused.
  *-F*************************************************************************/
-static const char *
-rcs_version(const char *version_info)
+static inline void
+restart_sequencer(struct aic7xxx_host *p)
 {
-  static char buf[10];
-  char *bp, *ep;
+  /* Set the sequencer address to 0. */
+  outb(0, p->base + SEQADDR0);
+  outb(0, p->base + SEQADDR1);
 
-  bp = NULL;
-  strcpy(buf, "????");
-  if (!strncmp(version_info, "$Id: ", 5))
-  {
-    if ((bp = strchr(version_info, ' ')) != NULL)
-    {
-      bp++;
-      if ((bp = strchr(bp, ' ')) != NULL)
-      {
-       bp++;
-      }
-    }
-  }
-  else
+  /*
+   * Reset and unpause the sequencer.  The reset is suppose to
+   * start the sequencer running, but we do an unpause to make
+   * sure.
+   */
+  outb(SEQRESET | FASTMODE, p->base + SEQCTL);
+
+  unpause_sequencer(p, /*unpause_always*/ TRUE);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_next_patch
+ *
+ * Description:
+ *   Find the next patch to download.
+ *-F*************************************************************************/
+static struct patch *
+aic7xxx_next_patch(struct patch *cur_patch, int options, int instrptr)
+{
+  while (cur_patch != NULL)
   {
-    if (!strncmp(version_info, "$Revision: ", 11))
+    if ((((cur_patch->options & options) != 0) && (cur_patch->negative == FALSE))
+      || (((cur_patch->options & options) == 0) && (cur_patch->negative == TRUE))
+      || (instrptr >= cur_patch->end))
     {
-      if ((bp = strchr(version_info, ' ')) != NULL)
+      /*
+       * Either we want to keep this section of code, or we have consumed
+       * this patch.  Skip to the next patch.
+       */
+      cur_patch++;
+      if (cur_patch->options == 0)
       {
-       bp++;
+        /* Out of patches. */
+        cur_patch = NULL;
       }
     }
-  }
-
-  if (bp != NULL)
-  {
-    if ((ep = strchr(bp, ' ')) != NULL)
+    else
     {
-      register int len = ep - bp;
-
-      strncpy(buf, bp, len);
-      buf[len] = '\0';
+      /* Found an OK patch. */
+      break;
     }
   }
-
-  return buf;
+  return (cur_patch);
 }
 
+
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_info
+ *   aic7xxx_download_instr
  *
  * Description:
- *   Return a string describing the driver.
+ *   Find the next patch to download.
  *-F*************************************************************************/
-const char *
-aic7xxx_info(struct Scsi_Host *notused)
+static void
+aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
 {
-  static char buffer[128];
+  unsigned char opcode;
+  struct ins_format3 *instr;
 
-  strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
-  strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
-  strcat(buffer, "/");
+  instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+  /* Pull the opcode */
+  opcode = instr->opcode_addr >> 1;
+  switch (opcode)
+  {
+    case AIC_OP_JMP:
+    case AIC_OP_JC:
+    case AIC_OP_JNC:
+    case AIC_OP_CALL:
+    case AIC_OP_JNE:
+    case AIC_OP_JNZ:
+    case AIC_OP_JE:
+    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;
+      for (i = 0; i < NUMBER(patches); i++)
+      {
+        patch = &patches[i];
+        if ((((patch->options & options) == 0) && (patch->negative == FALSE)) ||
+            (((patch->options & options) != 0) && (patch->negative == TRUE)))
+        {
+          if (address >= patch->end)
+          {
+            address_offset += patch->end - patch->begin;
+          }
+        }
+      }
+      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;
+    }
+
+    case AIC_OP_OR:
+    case AIC_OP_AND:
+    case AIC_OP_XOR:
+    case AIC_OP_ADD:
+    case AIC_OP_ADC:
+    case AIC_OP_ROL:
+      outsb(p->base + SEQRAM, &instr->immediate, 4);
+      break;
+
+    default:
+      panic("aic7xxx: Unknown opcode encountered in sequencer program.");
+      break;
+  }
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_loadseq
+ *
+ * Description:
+ *   Load the sequencer code into the controller memory.
+ *-F*************************************************************************/
+static void
+aic7xxx_loadseq(struct aic7xxx_host *p)
+{
+  int options;
+  struct patch *cur_patch;
+  int i;
+  int downloaded;
+
+  if (aic7xxx_verbose)
+  {
+    printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+  }
+  options = 1;  /* Code for all options. */
+  downloaded = 0;
+  if ((p->flags & ULTRA_ENABLED) != 0)
+    options |= ULTRA;
+  if (p->bus_type == AIC_TWIN)
+    options |= TWIN_CHANNEL;
+  if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+    options |= SCB_PAGING;
+
+  cur_patch = patches;
+  outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
+  outb(0, p->base + SEQADDR0);
+  outb(0, p->base + SEQADDR1);
+
+  for (i = 0; i < sizeof(seqprog) / 4;  i++)
+  {
+    cur_patch = aic7xxx_next_patch(cur_patch, options, i);
+    if (cur_patch && (cur_patch->begin <= i) && (cur_patch->end > i))
+    {
+      /* Skip this instruction for this configuration. */
+      continue;
+    }
+    aic7xxx_download_instr(p, options, i);
+    downloaded++;
+  }
+
+  outb(FASTMODE, p->base + SEQCTL);
+  outb(0, p->base + SEQADDR0);
+  outb(0, p->base + SEQADDR1);
+
+  if (aic7xxx_verbose)
+  {
+     printk(" %d instructions downloaded\n", downloaded);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_delay
+ *
+ * Description:
+ *   Delay for specified amount of time.  We use udelay because the timer
+ *   interrupt is not guaranteed to be enabled.  This will cause an
+ *   infinite loop since jiffies (clock ticks) is not updated.
+ *-F*************************************************************************/
+static void
+aic7xxx_delay(int seconds)
+{
+  int i;
+
+  /*                        
+   * Call udelay() for 1 millisecond inside a loop for  
+   * the requested amount of seconds.
+   */
+  for (i=0; i < seconds*1000; i++)
+  {
+    udelay(1000);  /* Delay for 1 millisecond. */
+  }
+}
+
+/*+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)
+{
+  static char buffer[128];
+
+  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
 
   return buffer;
 }
@@ -1161,9 +1387,12 @@ aic7xxx_info(struct Scsi_Host *notused)
  *   aic7xxx_length
  *
  * Description:
- *   How much data should be transferred for this SCSI command? Stop
- *   at segment sg_last if it's a scatter-gather command so we can
- *   compute underflow easily.
+ *   How much data should be transferred for this SCSI command?  Assume
+ *   all segments are to be transferred except for the last sg_last
+ *   segments.  This will allow us to compute underflow easily.  To
+ *   calculate the total length of the command, use sg_last = 0.  To
+ *   calculate the length of all but the last 2 SG segments, use
+ *   sg_last = 2.
  *-F*************************************************************************/
 static unsigned
 aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
@@ -1177,7 +1406,7 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
 
   if (cmd->use_sg)
   {
-    for (i = length = 0; (i < cmd->use_sg) && (i < segments); i++)
+    for (i = length = 0; i < segments; i++)
     {
       length += sg[i].length;
     }
@@ -1199,9 +1428,9 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
  *-F*************************************************************************/
 static void
 aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
-    short period, unsigned char offset, int target, char channel)
+    unsigned char *period, unsigned char *offset, int target, char channel)
 {
-  int i;
+  int i = num_aic7xxx_syncrates;
   unsigned long ultra_enb_addr;
   unsigned char ultra_enb, sxfrctl0;
 
@@ -1209,11 +1438,11 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
    * If the offset is 0, then the device is requesting asynchronous
    * transfers.
    */
-  if (offset != 0)
+  if ((*period >= aic7xxx_syncrates[i].period) && *offset != 0)
   {
     for (i = 0; i < num_aic7xxx_syncrates; i++)
     {
-      if ((aic7xxx_syncrates[i].period - period) >= 0)
+      if (*period <= aic7xxx_syncrates[i].period)
       {
         /*
          * Watch out for Ultra speeds when ultra is not enabled and
@@ -1229,99 +1458,57 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
            */
           continue;
         }
-        *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
+        *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
+        *period = aic7xxx_syncrates[i].period;
 
-        /*
-         * Ensure Ultra mode is set properly for this target.
-         */
-        ultra_enb_addr = ULTRA_ENB;
-        if ((channel == 'B') || (target > 7))
-        {
-          ultra_enb_addr++;
-        }
-        ultra_enb = inb(p->base + ultra_enb_addr);
-        sxfrctl0 = inb(p->base + SXFRCTL0);
-        if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
+        if (aic7xxx_verbose)
         {
-          ultra_enb |= 0x01 << (target & 0x07);
-          sxfrctl0 |= ULTRAEN;
+          printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
+                 "offset %d.\n", p->host_no, target, channel,
+                 aic7xxx_syncrates[i].english, *offset);
         }
-        else
-        {
-          ultra_enb &= ~(0x01 << (target & 0x07));
-          sxfrctl0 &= ~ULTRAEN;
-        }
-        outb(ultra_enb, p->base + ultra_enb_addr);
-        outb(sxfrctl0, p->base + SXFRCTL0);
-
-        printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
-               "offset %d.\n", p->host_no, target, channel,
-               aic7xxx_syncrates[i].english, offset);
-        return;
+        break;
       }
     }
   }
 
-  /*
-   * Default to asynchronous transfer
-   */
-  *scsirate = 0;
-  printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
-         p->host_no, target, channel);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_putscb
- *
- * Description:
- *   Transfer a SCB to the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int base = p->base;
-
-  outb(SCBAUTO, SCBCNT + base);
+  if (i >= num_aic7xxx_syncrates)
+  {
+    /*
+     * Use asynchronous transfers.
+     */
+    *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);
+    }
+  }
 
   /*
-   * By turning on the SCB auto increment, any reference
-   * to the SCB I/O space postincrements the SCB address
-   * we're looking at. So turn this on and dump the relevant
-   * portion of the SCB to the card.
-   *
-   * We can do 16bit transfers on all but 284x.
+   * Ensure Ultra mode is set properly for this target.
    */
-  if (p->type == AIC_284x)
+  ultra_enb_addr = ULTRA_ENB;
+  if ((channel == 'B') || (target > 7))
   {
-    outsb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
+    ultra_enb_addr++;
+  }
+  ultra_enb = inb(p->base + ultra_enb_addr);
+  sxfrctl0 = inb(p->base + SXFRCTL0);
+  if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+  {
+    ultra_enb |= 0x01 << (target & 0x07);
+    sxfrctl0 |= FAST20;
   }
   else
   {
-    outsl(SCBARRAY + base, scb, (SCB_PIO_TRANSFER_SIZE + 3) / 4);
+    ultra_enb &= ~(0x01 << (target & 0x07));
+    sxfrctl0 &= ~FAST20;
   }
-
-  outb(0, SCBCNT + base);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_getscb
- *
- * Description:
- *   Get a SCB from the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_getscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int base = p->base;
-
-  /*
-   * This is almost identical to aic7xxx_putscb().
-   */
-  outb(SCBAUTO, SCBCNT + base);
-  insb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
-  outb(0, SCBCNT + base);
+  outb(ultra_enb, p->base + ultra_enb_addr);
+  outb(sxfrctl0, p->base + SXFRCTL0);
 }
 
 /*+F*************************************************************************
@@ -1373,6 +1560,47 @@ scbq_remove_head(scb_queue_type *queue)
     queue->tail = NULL;
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   scbq_remove
+ *
+ * Description:
+ *   Removes an SCB from the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+  if (queue->head == scb)
+  {
+    /* At beginning of queue, remove from head. */
+    scbq_remove_head(queue);
+  }
+  else
+  {
+    struct aic7xxx_scb *curscb = queue->head;
+
+    /*
+     * Search until the next scb is the one we're looking for, or
+     * we run out of queue.
+     */
+    while ((curscb != NULL) && (curscb->q_next != scb))
+    {
+      curscb = curscb->q_next;
+    }
+    if (curscb != NULL)
+    {
+      /* Found it. */
+      curscb->q_next = scb->q_next;
+      if (scb->q_next == NULL)
+      {
+        /* Update the tail when removing the tail. */
+        queue->tail = curscb;
+      }
+    }
+  }
+}
+
 /*+F*************************************************************************
  * Function:
  *   scbq_insert_tail
@@ -1404,23 +1632,87 @@ scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
  *   to be reset and all devices on that channel must be aborted.
  *-F*************************************************************************/
 static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
+aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
+    int lun, unsigned char tag)
 {
-  int targ = (scb->target_channel_lun >> 4) & 0x0F;
-  char chan = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
+  char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int slun = scb->hscb->target_channel_lun & 0x07;
+  int match;
 
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n",
-         target, channel, targ, chan);
+  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
-  if (target == ALL_TARGETS)
+  match = ((chan == channel) || (channel == ALL_CHANNELS));
+  if (match != 0)
+    match = ((targ == target) || (target == ALL_TARGETS));
+  if (match != 0)
+    match = ((lun == slun) || (lun == ALL_LUNS));
+  if (match != 0)
+    match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+
+  return (match);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_add_curscb_to_free_list
+ *
+ * Description:
+ *   Adds the current scb (in SCBPTR) to the list of free SCBs.
+ *-F*************************************************************************/
+static void
+aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
+{
+  /*
+   * Invalidate the tag so that aic7xxx_find_scb doesn't think
+   * it's active
+   */
+  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+
+  outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
+  outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_rem_scb_from_disc_list
+ *
+ * Description:
+ *   Removes the current SCB from the disconnected list and adds it
+ *   to the free list.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
+{
+  unsigned char next;
+  unsigned char prev;
+
+  outb(scbptr, p->base + SCBPTR);
+  next = inb(p->base + SCB_NEXT);
+  prev = inb(p->base + SCB_PREV);
+
+  outb(0, p->base + SCB_CONTROL);
+
+  aic7xxx_add_curscb_to_free_list(p);
+
+  if (prev != SCB_LIST_NULL)
   {
-    return (chan == channel);
+    outb(prev, p->base + SCBPTR);
+    outb(next, p->base + SCB_NEXT);
   }
   else
   {
-    return ((chan == channel) && (targ == target));
+    outb(next, p->base + DISCONNECTED_SCBH);
+  }
+
+  if (next != SCB_LIST_NULL)
+  {
+    outb(next, p->base + SCBPTR);
+    outb(prev, p->base + SCB_PREV);
   }
+  return next;
 }
 
 /*+F*************************************************************************
@@ -1428,51 +1720,93 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
  *   aic7xxx_busy_target
  *
  * Description:
- *   Set the specified target active.
+ *   Set the specified target busy.
  *-F*************************************************************************/
 static void
-aic7xxx_busy_target(unsigned char target, char channel, int base)
+aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
+    char channel, unsigned char scbid)
+{
+  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);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_index_busy_target
+ *
+ * Description:
+ *   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)
 {
-  unsigned char active;
-  unsigned long active_port = ACTIVE_A + base;
+  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;
 
-  if ((target > 0x07) || (channel == 'B'))
+  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);
+  if (unbusy)
   {
-    /*
-     * targets on the Second channel or above id 7 store info in byte two
-     * of ACTIVE
-     */
-    active_port++;
+    outb(SCB_LIST_NULL, p->base + scb_offset);
   }
-  active = inb(active_port);
-  active |= (0x01 << (target & 0x07));
-  outb(active, active_port);
+  outb(active_scb, p->base + SCBPTR);
+  return (busy_scbid);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_unbusy_target
+ *   aic7xxx_find_scb
  *
  * Description:
- *   Set the specified target inactive.
+ *   Look through the SCB array of the card and attempt to find the
+ *   hardware SCB that corresponds to the passed in SCB.  Return
+ *   SCB_LIST_NULL if unsuccessful.  This routine assumes that the
+ *   card is already paused.
  *-F*************************************************************************/
-static void
-aic7xxx_unbusy_target(unsigned char target, char channel, int base)
+static unsigned char
+aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  unsigned char active;
-  unsigned long active_port = ACTIVE_A + base;
+  unsigned char saved_scbptr;
+  unsigned char curindex;
 
-  if ((target > 0x07) || (channel == 'B'))
+  saved_scbptr = inb(p->base + SCBPTR);
+  curindex = 0;
+  for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
   {
-    /*
-     * targets on the Second channel or above id 7 store info in byte two
-     * of ACTIVE
-     */
-    active_port++;
+    outb(curindex, p->base + SCBPTR);
+    if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+    {
+      break;
+    }
+  }
+  outb(saved_scbptr, p->base + SCBPTR);
+  if (curindex >= p->scb_data->maxhscbs)
+  {
+    curindex = SCB_LIST_NULL;
   }
-  active = inb(active_port);
-  active &= ~(0x01 << (target & 0x07));
-  outb(active, active_port);
+
+  return (curindex);
 }
 
 /*+F*************************************************************************
@@ -1480,68 +1814,60 @@ aic7xxx_unbusy_target(unsigned char target, char channel, int base)
  *   aic7xxx_allocate_scb
  *
  * Description:
- *   Get a free SCB either from one already assigned to a hardware
- *   slot, or one that will require an SCB to be paged out before
- *   use.  If there are none, attempt to allocate a new one.
+ *   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)
 {
-  struct aic7xxx_scb *scbp = NULL;
-  int maxscbs;
+  struct aic7xxx_scb   *scbp = NULL;
+  struct aic7xxx_hwscb *hscbp = NULL;
+#ifdef AGRESSIVE
+  long processor_flags;
+
+  save_flags(processor_flags);
+  cli();
+#endif
 
-  scbp = p->scb_link->free_scbs.head;
+  scbp = p->scb_data->free_scbs.head;
   if (scbp != NULL)
   {
-    scbq_remove_head(&p->scb_link->free_scbs);
+    scbq_remove_head(&p->scb_data->free_scbs);
   }
   else
   {
-    /*
-     * This should always be NULL if paging is not enabled.
-     */
-    scbp = p->page_scbs.head;
-    if (scbp != NULL)
-    {
-      scbq_remove_head(&p->page_scbs);
-    }
-    else
+    if (p->scb_data->numscbs < p->scb_data->maxscbs)
     {
-      /*
-       * Set limit the SCB allocation to the maximum number of
-       * hardware SCBs if paging is not enabled; otherwise use
-       * the maximum (255).
-       */
-      if (p->flags & PAGE_ENABLED)
-        maxscbs = p->maxscbs;
-      else
-        maxscbs = p->maxhscbs;
-      if (p->scb_link->numscbs < maxscbs)
-      {
-        int scb_index = p->scb_link->numscbs;
-        int scb_size = sizeof(struct aic7xxx_scb);
+      int scb_index = p->scb_data->numscbs;
+      int scb_size = sizeof(struct aic7xxx_scb) +
+                     sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
 
-        p->scb_array[scb_index] = kmalloc(scb_size, GFP_ATOMIC | GFP_DMA);
-        scbp = (p->scb_array[scb_index]);
-        if (scbp != NULL)
-        {
-          memset(scbp, 0, sizeof(*scbp));
-          scbp->tag = scb_index;
-          if (scb_index < p->maxhscbs)
-            scbp->position = scb_index;
-          else
-           scbp->position = SCB_LIST_NULL;
-          p->scb_link->numscbs++;
-        }
+      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++;
+        /*
+         * Place in the scb array; never is removed
+         */
+        p->scb_data->scb_array[scb_index] = scbp;
       }
     }
   }
+#ifdef AIC7XXX_DEBUG
   if (scbp != NULL)
   {
-#ifdef AIC7XXX_DEBUG
-    p->scb_link->activescbs++;
-#endif
+    p->activescbs++;
   }
+#endif
+
+#ifdef AGRESSIVE
+  restore_flags(processor_flags);
+#endif
   return (scbp);
 }
 
@@ -1581,6 +1907,7 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
+    p->device_status[TARGET_INDEX(cmd)].active_cmds--;
     cmd->scsi_done(cmd);
   }
   p->completeq.tail = NULL;
@@ -1591,53 +1918,29 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
  *   aic7xxx_free_scb
  *
  * Description:
- *   Free the scb and update the page, waiting, free scb lists.
+ *   Free the scb and insert into the free scb list.
  *-F*************************************************************************/
 static void
 aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  struct aic7xxx_scb *wscb;
+  struct aic7xxx_hwscb *hscb;
+  long flags;
 
-  scb->state = SCB_FREE;
+  hscb = scb->hscb;
+  save_flags(flags);
+  cli();
+
+  scb->flags = SCB_FREE;
   scb->cmd = NULL;
-  scb->control = 0;
-  scb->state = 0;
+  hscb->control = 0;
+  hscb->target_status = 0;
 
-  if (scb->position == SCB_LIST_NULL)
-  {
-    scbq_insert_head(&p->page_scbs, scb);
-  }
-  else
-  {
-    /*
-     * If there are any SCBS on the waiting queue, assign the slot of this
-     * "freed" SCB to the first one.  We'll run the waiting queues after
-     * all command completes for a particular interrupt are completed or
-     * when we start another command.
-     */
-    wscb = p->waiting_scbs.head;
-    if (wscb != NULL)
-    {
-      scbq_remove_head(&p->waiting_scbs);
-      wscb->position = scb->position;
-      scbq_insert_tail(&p->assigned_scbs, wscb);
-      wscb->state = (wscb->state & ~SCB_WAITINGQ) | SCB_ASSIGNEDQ;
-
-      /* 
-       * The "freed" SCB will need to be assigned a slot before being
-       * used, so put it in the page_scbs queue.
-       */
-      scb->position = SCB_LIST_NULL;
-      scbq_insert_head(&p->page_scbs, scb);
-    }
-    else
-    {
-      scbq_insert_head(&p->scb_link->free_scbs, scb);
-    }
+  scbq_insert_head(&p->scb_data->free_scbs, scb);
 #ifdef AIC7XXX_DEBUG
-    p->scb_link->activescbs--;  /* For debugging purposes. */
+  p->activescbs--;  /* For debugging purposes. */
 #endif
-  }
+
+  restore_flags(flags);
 }
 
 /*+F*************************************************************************
@@ -1652,68 +1955,113 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   Scsi_Cmnd *cmd = scb->cmd;
 
+  if (scb->flags & SCB_RECOVERY_SCB)
+  {
+    p->flags &= ~IN_TIMEOUT;
+  }
+  if (cmd->result == DID_OK)
+  {
+    if (scb->flags & SCB_ABORTED)
+    {
+      cmd->result = (DID_RESET << 16);
+    }
+  }
+  if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+  {
+    unsigned short mask;
+
+    mask = 0x01 << TARGET_INDEX(scb->cmd);
+    if (scb->flags & SCB_MSGOUT_WDTR)
+    {
+      p->wdtr_pending &= ~mask;
+    }
+    if (scb->flags & SCB_MSGOUT_SDTR)
+    {
+      p->sdtr_pending &= ~mask;
+    }
+  }
   aic7xxx_free_scb(p, scb);
   aic7xxx_queue_cmd_complete(p, cmd);
 
+#ifdef AIC7XXX_PROC_STATS
+  {
+    int actual;
+
+    /*
+     * XXX: we should actually know how much actually transferred
+     * XXX: for each command, but apparently that's too difficult.
+     */
+    actual = aic7xxx_length(cmd, 0);
+    if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
+        && (aic7xxx_error(cmd) == 0))
+    {
+      struct aic7xxx_xferstats *sp;
+      long *ptr;
+      int x;
+
+      sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
+      sp->xfers++;
+
+      if (cmd->request.cmd == WRITE)
+      {
+        sp->w_total++;
+        sp->w_total512 += (actual >> 9);
+        ptr = sp->w_bins;
+      }
+      else
+      {
+        sp->r_total++;
+        sp->r_total512 += (actual >> 9);
+        ptr = sp->r_bins;
+      }
+      for (x = 9; x <= 17; x++)
+      {
+        if (actual < (1 << x))
+        {
+          ptr[x - 9]++;
+          break;
+        }
+      }
+      if (x > 17)
+      {
+        ptr[x - 9]++;
+      }
+    }
+  }
+#endif /* AIC7XXX_PROC_STATS */
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_done_aborted_scbs
+ *   aic7xxx_run_done_queue
  *
  * Description:
- *   Calls the scsi_done() for the Scsi_Cmnd of each scb in the
- *   aborted list, and adds each scb to the free list.
+ *   Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ *   aborted list, and adds each scb to the free list.  If complete
+ *   is TRUE, we also process the commands complete list.
  *-F*************************************************************************/
 static void
-aic7xxx_done_aborted_scbs(struct aic7xxx_host *p)
+aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
 {
-  Scsi_Cmnd *cmd;
   struct aic7xxx_scb *scb;
   int i;
 
-  for (i = 0; i < p->scb_link->numscbs; i++)
+  for (i = 0; i < p->scb_data->numscbs; i++)
   {
-    scb = (p->scb_array[i]);
-    if (scb->state & SCB_QUEUED_FOR_DONE)
+    scb = p->scb_data->scb_array[i];
+    if (scb->flags & SCB_QUEUED_FOR_DONE)
     {
 #ifdef AIC7XXX_DEBUG_ABORT
-      printk("aic7xxx: (done_aborted_scbs) Aborting scb %d, TCL=%d/%d/%d\n",
-      scb->position, TCL_OF_SCB(scb));
+      printk("(scsi%d:%d:%d) Aborting scb %d\n",
+             p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
 #endif
-      /*
-       * Process the command after marking the scb as free
-       * and adding it to the free list.
-       */
-      cmd = scb->cmd;
-      p->device_status[TARGET_INDEX(cmd)].flags = 0;
-      aic7xxx_free_scb(p, scb);
-      cmd->scsi_done(cmd);  /* call the done function */
+      aic7xxx_done(p, scb);
     }
   }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_add_waiting_scb
- *
- * Description:
- *   Add this SCB to the head of the "waiting for selection" list.
- *-F*************************************************************************/
-static void
-aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
-{
-  unsigned char next;
-  unsigned char curscb;
-
-  curscb = inb(SCBPTR + base);
-  next = inb(WAITING_SCBH + base);
-
-  outb(scb->position, SCBPTR + base);
-  outb(next, SCB_NEXT + base);
-  outb(scb->position, WAITING_SCBH + base);
-
-  outb(curscb, SCBPTR + base);
+  if (complete)
+  {
+    aic7xxx_done_cmds_complete(p);
+  }
 }
 
 /*+F*************************************************************************
@@ -1726,26 +2074,23 @@ aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
  *-F*************************************************************************/
 static unsigned char
 aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
-    unsigned char prev)
+    unsigned char scbpos, unsigned char prev)
 {
   unsigned char curscb, next;
-  int target = (scb->target_channel_lun >> 4) & 0x0F;
-  char channel = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
-  int base = p->base;
 
   /*
    * Select the SCB we want to abort and pull the next pointer out of it.
    */
-  curscb = inb(SCBPTR + base);
-  outb(scb->position, SCBPTR + base);
-  next = inb(SCB_NEXT + base);
+  curscb = inb(p->base + SCBPTR);
+  outb(scbpos, p->base + SCBPTR);
+  next = inb(p->base + SCB_NEXT);
 
   /*
    * Clear the necessary fields
    */
-  outb(0, SCB_CONTROL + base);
-  outb(SCB_LIST_NULL, SCB_NEXT + base);
-  aic7xxx_unbusy_target(target, channel, base);
+  outb(0, p->base + SCB_CONTROL);
+
+  aic7xxx_add_curscb_to_free_list(p);
 
   /*
    * Update the waiting list
@@ -1755,27 +2100,97 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
     /*
      * First in the list
      */
-    outb(next, WAITING_SCBH + base);
+    outb(next, p->base + WAITING_SCBH);
   }
   else
   {
     /*
      * Select the scb that pointed to us and update its next pointer.
      */
-    outb(prev, SCBPTR + base);
-    outb(next, SCB_NEXT + base);
+    outb(prev, p->base + SCBPTR);
+    outb(next, p->base + SCB_NEXT);
   }
   /*
    * Point us back at the original scb position and inform the SCSI
    * system that the command has been aborted.
    */
-  outb(curscb, SCBPTR + base);
-  scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+  outb(curscb, p->base + SCBPTR);
+  scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+  scb->flags &= ~SCB_ACTIVE;
   scb->cmd->result = (DID_RESET << 16);
 
   return (next);
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_search_qinfifo
+ *
+ * Description:
+ *   Search the queue-in FIFO for matching SCBs and conditionally
+ *   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)
+{
+  unsigned char saved_queue[AIC7XXX_MAXSCB];
+  int      queued = inb(p->base + QINCNT) & p->qcntmask;
+  int      i;
+  int      found;
+  struct aic7xxx_scb *scbp;
+  scb_queue_type removed_scbs;
+
+  found = 0;
+  scbq_init (&removed_scbs);
+  for (i = 0; i < (queued - found); i++)
+  {
+    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))
+    {
+       /*
+        * We found an scb that needs to be removed.
+        */
+       if (requeue)
+       {
+         scbq_insert_head(&removed_scbs, scbp);
+       }
+       else
+       {
+         scbp->flags = flags;
+         scbp->flags &= ~SCB_ACTIVE;
+         /*
+          * XXX - Don't know what error to use here.
+          */
+         aic7xxx_error(scbp->cmd) = DID_RESET;
+       }
+       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)
+    {
+      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;
+    }
+  }
+
+  return (found);
+}
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_reset_device
@@ -1785,118 +2200,250 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
  *   all active and queued scbs for that target/channel.
  *-F*************************************************************************/
 static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+                     int lun, unsigned char tag)
 {
-  int base = p->base;
-  struct aic7xxx_scb *scb;
+  struct aic7xxx_scb *scbp;
   unsigned char active_scb;
   int i = 0;
-  int found = 0;
+  int found;
 
   /*
    * Restore this when we're done
    */
-  active_scb = inb(SCBPTR + base);
+  active_scb = inb(p->base + SCBPTR);
 
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: (reset_device) target/channel %d/%c, active_scb %d\n",
-         target, channel, active_scb);
+  printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
+         p->host_no, target, CHAN_TO_INT(channel), active_scb);
 #endif
+
   /*
-   * Search the QINFIFO.
+   * Deal with the busy target and linked next issues.
    */
   {
-    int saved_queue[AIC7XXX_MAXSCB];
-    int queued = inb(QINCNT + base) & p->qcntmask;
+    int min_target, max_target;
+    unsigned char busy_scbid;
 
-    for (i = 0; i < (queued - found); i++)
+    /* Make all targets 'relative' to bus A. */
+    if (target == ALL_TARGETS)
     {
-      saved_queue[i] = inb(QINFIFO + base);
-      outb(saved_queue[i], SCBPTR + base);
-      scb = (p->scb_array[inb(SCB_TAG + base)]);
-      if (aic7xxx_match_scb(scb, target, channel))
+      switch (channel)
       {
-        /*
-         * We found an scb that needs to be aborted.
-         */
-#ifdef AIC7XXX_DEBUG_ABORT
-        printk("aic7xxx: (reset_device) aborting SCB %d, TCL=%d/%d/%d\n",
-               saved_queue[i], TCL_OF_SCB(scb));
-#endif
-        scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-        scb->cmd->result = (DID_RESET << 16);
-        outb(0, SCB_CONTROL + base);
-        i--;
-        found++;
+        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 ALL_CHANNELS:
+        default:
+         min_target = 0;
+         max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+         break;
       }
     }
-    /*
-     * Now put the saved scbs back.
-     */
-    for (queued = 0; queued < i; queued++)
+    else
+    { 
+      min_target = target + channel == 'B' ? 8 : 0;
+      max_target = min_target;
+    }
+
+    for (i = min_target; i <= max_target; i++)
     {
-      outb(saved_queue[queued], QINFIFO + base);
+      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
+      if (busy_scbid < p->scb_data->numscbs)
+      {
+       struct aic7xxx_scb *busy_scb;
+       struct aic7xxx_scb *next_scb;
+       unsigned char next_scbid;
+
+       busy_scb = p->scb_data->scb_array[busy_scbid];
+  
+       next_scbid = busy_scb->hscb->data_count >> 24;
+
+       if (next_scbid == SCB_LIST_NULL)
+        {
+         busy_scbid = aic7xxx_find_scb(p, busy_scb);
+
+         if (busy_scbid != SCB_LIST_NULL)
+          {
+           outb(busy_scbid, p->base + SCBPTR);
+           next_scbid = inb(p->base + SCB_LINKED_NEXT);
+         }
+       }
+
+       if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
+        {
+         aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
+       }
+
+       if (next_scbid != SCB_LIST_NULL)
+        {
+         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;
+       }
+      }
     }
   }
 
+  found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+      SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
+
   /*
    * Search waiting for selection list.
    */
   {
-    unsigned char next, prev;
+    unsigned char next, prev, scb_index;
 
-    next = inb(WAITING_SCBH + base);  /* Start at head of list. */
+    next = inb(p->base + WAITING_SCBH);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
 
     while (next != SCB_LIST_NULL)
     {
-      outb(next, SCBPTR + base);
-      scb = (p->scb_array[inb(SCB_TAG + base)]);
-      /*
-       * Select the SCB.
-       */
-      if (aic7xxx_match_scb(scb, target, channel))
+      outb(next, p->base + SCBPTR);
+      scb_index = inb(p->base + SCB_TAG);
+      if (scb_index >= p->scb_data->numscbs)
       {
-        next = aic7xxx_abort_waiting_scb(p, scb, prev);
+        panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
+              scb_index, p->scb_data->numscbs);
+      }
+      scbp = p->scb_data->scb_array[scb_index];
+      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      {
+        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)
+        {
+          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))
+          {
+            scbq_insert_head(&p->waiting_scbs, next_scb);
+            next_scb->flags |= SCB_WAITINGQ;
+          }
+        }
         found++;
       }
       else
       {
         prev = next;
-        next = inb(SCB_NEXT + base);
+        next = inb(p->base + SCB_NEXT);
+      }
+    }
+  }
+
+  /*
+   * Go through disconnected list and remove any entries we have queued
+   * for completion, zeroing their control byte too.
+   */
+  {
+    unsigned char next, prev, scb_index;
+
+    next = inb(p->base + DISCONNECTED_SCBH);
+    prev = SCB_LIST_NULL;
+
+    while (next != SCB_LIST_NULL)
+    {
+      outb(next, p->base + SCBPTR);
+      scb_index = inb(p->base + 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);
+      }
+      scbp = p->scb_data->scb_array[scb_index];
+      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      {
+        next = aic7xxx_rem_scb_from_disc_list(p, next);
+      }
+      else
+      {
+        prev = next;
+        next = inb(p->base + SCB_NEXT);
+      }
+    }
+  }
+
+  /*
+   * 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++)
+  {
+    unsigned char scbid;
+
+    outb(i, p->base + SCBPTR);
+    scbid = inb(p->base + SCB_TAG);
+    if (scbid < p->scb_data->numscbs)
+    {
+      scbp = p->scb_data->scb_array[scbid];
+      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      {
+        aic7xxx_add_curscb_to_free_list(p);
       }
     }
   }
 
   /*
    * Go through the entire SCB array now and look for commands for
-   * for this target that are active.  These are other (most likely
+   * for this target that are stillactive.  These are other (most likely
    * tagged) commands that were disconnected when the reset occurred.
    */
-  for (i = 0; i < p->scb_link->numscbs; i++)
+  for (i = 0; i < p->scb_data->numscbs; i++)
   {
-    scb = (p->scb_array[i]);
-    if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel))
+    scbp = p->scb_data->scb_array[i];
+    if (((scbp->flags & SCB_ACTIVE) != 0) &&
+        aic7xxx_match_scb(scbp, target, channel, lun, tag))
     {
-      /*
-       * Ensure the target is "free"
-       */
-      aic7xxx_unbusy_target(target, channel, base);
-      if (! (scb->state & SCB_PAGED_OUT))
+      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)
       {
-        outb(scb->position, SCBPTR + base);
-        outb(0, SCB_CONTROL + base);
+        scbq_remove(&p->waiting_scbs, scbp);
+        scbp->flags &= ~SCB_WAITINGQ;
       }
-      scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-      scb->cmd->result = (DID_RESET << 16);
-      found++;
     }
   }
 
-  outb(active_scb, SCBPTR + base);
+  outb(active_scb, p->base + SCBPTR);
   return (found);
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_clear_intstat
+ *
+ * Description:
+ *   Clears the interrupt status.
+ *-F*************************************************************************/
+static void
+aic7xxx_clear_intstat(struct aic7xxx_host *p)
+{
+  /* Clear any interrupt conditions this may have caused. */
+  outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
+  outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+       CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
+  outb(CLRSCSIINT, p->base + CLRINT);
+}
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_reset_current_bus
@@ -1905,11 +2452,28 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel)
  *   Reset the current SCSI bus.
  *-F*************************************************************************/
 static void
-aic7xxx_reset_current_bus(int base)
+aic7xxx_reset_current_bus(struct aic7xxx_host *p)
 {
-  outb(SCSIRSTO, SCSISEQ + base);
+  unsigned char scsiseq;
+
+  /* Disable reset interrupts. */
+  outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+
+  /* Turn on the bus reset. */
+  scsiseq = inb(p->base + SCSISEQ);
+  outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+
+  udelay(1000);
+
+  /* Turn off the bus reset. */
+  outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+
+  aic7xxx_clear_intstat(p);
+
+  /* Re-enable reset interrupts. */
+  outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+
   udelay(1000);
-  outb(0, SCSISEQ + base);
 }
 
 /*+F*************************************************************************
@@ -1922,25 +2486,24 @@ aic7xxx_reset_current_bus(int base)
 static int
 aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
 {
-  int base = p->base;
-  unsigned char sblkctl;
-  char cur_channel;
   unsigned long offset, offset_max;
   int found;
+  unsigned char sblkctl;
+  char cur_channel;
 
+  pause_sequencer(p);
   /*
-   * Clean up all the state information for the
-   * pending transactions on this bus.
+   * Clean up all the state information for the pending transactions
+   * on this bus.
    */
-  found = aic7xxx_reset_device(p, ALL_TARGETS, channel);
+  found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
   if (channel == 'B')
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
-    outb(0, ACTIVE_B + base);
-    offset = TARG_SCRATCH + base + 8;
-    offset_max = TARG_SCRATCH + base + 16;
+    offset = TARG_SCRATCH + 8;
+    offset_max = TARG_SCRATCH + 16;
   }
   else
   {
@@ -1950,1292 +2513,1427 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
       p->needwdtr = p->needwdtr_copy;
       p->sdtr_pending = 0x0;
       p->wdtr_pending = 0x0;
-      outb(0, ACTIVE_A + base);
-      outb(0, ACTIVE_B + base);
-      offset = TARG_SCRATCH + base;
-      offset_max = TARG_SCRATCH + base + 16;
+      offset = TARG_SCRATCH;
+      offset_max = TARG_SCRATCH + 16;
     }
     else
     {
+      /* Channel A */
       p->needsdtr |= (p->needsdtr_copy & 0x00FF);
       p->sdtr_pending &= 0xFF00;
-      outb(0, ACTIVE_A + base);
-      offset = TARG_SCRATCH + base;
-      offset_max = TARG_SCRATCH + base + 8;
+      offset = TARG_SCRATCH;
+      offset_max = TARG_SCRATCH + 8;
     }
   }
+
   while (offset < offset_max)
   {
     /*
-     * Revert to async/narrow transfers
-     * until we renegotiate.
+     * Revert to async/narrow transfers until we renegotiate.
      */
     u_char targ_scratch;
-    targ_scratch = inb(offset);
+
+    targ_scratch = inb(p->base + offset);
     targ_scratch &= SXFR;
-    outb(targ_scratch, offset);
+    outb(targ_scratch, p->base + offset);
     offset++;
   }
 
   /*
    * Reset the bus and unpause/restart the controller
    */
-
-  /*
-   * Case 1: Command for another bus is active
-   */
-  sblkctl = inb(SBLKCTL + base);
+  sblkctl = inb(p->base + SBLKCTL);
   cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
   if (cur_channel != channel)
   {
+    /*
+     * Case 1: Command for another bus is active
+     */
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("aic7xxx: (reset_channel) Stealthily resetting channel %c\n",
-           channel);
+    printk("scsi%d: Stealthily resetting channel %c\n",
+           p->host_no, channel);
 #endif
     /*
-     * Stealthily reset the other bus without upsetting the current bus
+     * Stealthily reset the other bus without upsetting the current bus.
      */
-    outb(sblkctl ^ SELBUSB, SBLKCTL + base);
+    outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
+    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
     if (initiate_reset)
     {
-      aic7xxx_reset_current_bus(base);
+      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(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
-    outb(CLRSCSIINT, CLRINT + base);
-    outb(sblkctl, SBLKCTL + base);
-
-    UNPAUSE_SEQUENCER(p);
+    outb(0, p->base + SCSISEQ);
+    aic7xxx_clear_intstat(p);
+    outb(sblkctl, p->base + SBLKCTL);
+    unpause_sequencer(p, /* unpause_always */ FALSE);
   }
-  /*
-   * Case 2: A command from this bus is active or we're idle
-   */
   else
   {
+    /*
+     * Case 2: A command from this bus is active or we're idle.
+     */
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("aic7xxx: (reset_channel) Resetting current channel %c\n",
-           channel);
+    printk("scsi%d: Resetting current channel %c\n",
+           p->host_no, channel);
 #endif
+    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
     if (initiate_reset)
     {
-      aic7xxx_reset_current_bus(base);
+      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(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
-    outb(CLRSCSIINT, CLRINT + base);
-    RESTART_SEQUENCER(p);
+    outb(0, p->base + SCSISEQ);
+    aic7xxx_clear_intstat(p);
+    restart_sequencer(p);
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
+    printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
 #endif
   }
 
-  /*
-   * 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));
-
   /*
    * Now loop through all the SCBs that have been marked for abortion,
    * and call the scsi_done routines.
    */
-  aic7xxx_done_aborted_scbs(p);
-  return found;
+  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+  return (found);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_page_scb
+ *   aic7xxx_run_waiting_queues
  *
  * Description:
- *   Swap in_scbp for out_scbp down in the cards SCB array.
- *   We assume that the SCB for out_scbp is already selected in SCBPTR.
- *
+ *   Scan the awaiting_scbs queue downloading and starting as many
+ *   scbs as we can.
  *-F*************************************************************************/
 static inline void
-aic7xxx_page_scb(struct aic7xxx_host *p, struct aic7xxx_scb *out_scbp,
-    struct aic7xxx_scb *in_scbp)
+aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
-  int index;
+  struct aic7xxx_scb *scb;
 
-  /* Page-out */
-#if 0
-printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n",
-       out_scbp->cmd->target, in_scbp->cmd->target);
-#endif
-  aic7xxx_getscb(p, out_scbp);
-  out_scbp->state |= SCB_PAGED_OUT;
-  if (!(out_scbp->control & TAG_ENB))
-  {
-    /* Stick in non-tagged array */
-    index = (out_scbp->target_channel_lun >> 4) | 
-            (out_scbp->target_channel_lun & SELBUSB);
-    p->pagedout_ntscbs[index] = out_scbp;
-  }
-
-  /* Page-in */
-  in_scbp->position = out_scbp->position;
-  out_scbp->position = SCB_LIST_NULL;
-  aic7xxx_putscb(p, in_scbp);
-  in_scbp->state &= ~SCB_PAGED_OUT;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_run_waiting_queues
- *
- * Description:
- *   Scan the assigned_scbs and waiting_scbs queues.  For scbs in the
- *   assigned_scbs queue, we download and start them.  For scbs in the
- *   waiting_scbs queue, we page in as many as we can being careful
- *   not to cause a deadlock for a reconnecting target.
- *
- *-F*************************************************************************/
-static inline void
-aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
-{
-  struct aic7xxx_scb *scb;
-  u_char cur_scb, intstat;
-  u_long base = p->base;
-  long flags;
-
-  if ((p->assigned_scbs.head == NULL) && (p->waiting_scbs.head == NULL))
-    return;
-
-  save_flags(flags);
-  cli();
-
-  PAUSE_SEQUENCER(p);
-  cur_scb = inb(SCBPTR + base);
-  intstat = inb(INTSTAT + base);
+  if (p->waiting_scbs.head == NULL)
+    return;
 
+  pause_sequencer(p);
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
-  scb = p->assigned_scbs.head;
-  while (scb != NULL)
-  {
-    scbq_remove_head(&(p->assigned_scbs));
-    outb(scb->position, SCBPTR + base);
-    aic7xxx_putscb(p, scb);
-    /* Mark this as an active command. */
-    scb->state = (scb->state & ~SCB_ASSIGNEDQ) | SCB_ACTIVE;
-    outb(scb->position, QINFIFO + base);
-    scb = p->assigned_scbs.head;
-  }
-
-  /* Now deal with SCBs that require paging. */
   scb = p->waiting_scbs.head;
-  if (scb != NULL)
+  while (scb != NULL)
   {
-    u_char disc_scb = inb(DISCONNECTED_SCBH + base);
-    u_char active = inb(FLAGS + base) & (SELECTED | IDENTIFY_SEEN);
-    int count = 0;
-    u_char next_scb;
-
-    while (scb != NULL)
+    if (p->curqincnt >= p->qfullcount)
     {
-      /* Attempt to page this SCB in */
-      if (disc_scb == SCB_LIST_NULL)
-        break;
-
-      /*
-       * Advance disc_scb to the next one in the list.
-       */
-      outb(disc_scb, SCBPTR + base);
-      next_scb = inb(SCB_NEXT + base); 
-
-      /*
-       * We have to be careful about when we allow an SCB to be paged out. 
-       * There must always be at least one slot availible for a reconnecting
-       * target in case it references an SCB that has been paged out.  Our
-       * heuristic is that either the disconnected list has at least two
-       * entries in it or there is one entry and the sequencer is activily
-       * working on an SCB which implies that it will either complete or
-       * disconnect before another reconnection can occur.
-       */
-      if ((next_scb != SCB_LIST_NULL) || active)
+      p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
+      if (p->curqincnt >= p->qfullcount)
       {
-        u_char out_scbi;
-        struct aic7xxx_scb *out_scbp;
-
-        scbq_remove_head(&(p->waiting_scbs));
-
-        /*
-         * Find the in-core SCB for the one we're paging out.
-         */
-        out_scbi = inb(SCB_TAG + base); 
-        out_scbp = (p->scb_array[out_scbi]);
-
-        /* Do the page out and mark the paged in SCB as active. */
-        aic7xxx_page_scb(p, out_scbp, scb);
-
-        /* Mark this as an active command. */
-        scb->state = (scb->state & ~SCB_WAITINGQ) | SCB_ACTIVE;
-
-        /* Queue the command */
-        outb(scb->position, QINFIFO + base);
-        count++;
-
-        /* Advance to the next disconnected SCB */
-        disc_scb = next_scb;
-        scb = p->waiting_scbs.head;
+        break;
       }
-      else
-        scb = NULL;
     }
 
-    if (count)
+    /*
+     * 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)
     {
-      /* 
-       * Update the head of the disconnected list.
+      /*
+       * We only care about this statistic when paging
+       * since it's impossible to overflow the qinfifo
+       * in the non-paging case.
        */
-      outb(disc_scb, DISCONNECTED_SCBH + base);
-      if (disc_scb != SCB_LIST_NULL)
-      {
-        outb(disc_scb, SCBPTR + base);
-        outb(SCB_LIST_NULL, SCB_PREV + base);
-      }
+      p->curqincnt++;
     }
+    scb = p->waiting_scbs.head;
   }
-  /* Restore old position */
-  outb(cur_scb, SCBPTR + base);
 
-  /*
-   * Guard against unpausing the sequencer if there is an interrupt
-   * waiting to happen.
-   */
-  if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
-  {
-    UNPAUSE_SEQUENCER(p);
-  }
+  unpause_sequencer(p, FALSE);
+}
 
-  restore_flags(flags);
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_sdtr
+ *
+ * Description:
+ *   Constucts a synchronous data transfer message in the message
+ *   buffer on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
+    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);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_isr
+ *   aic7xxx_construct_wdtr
  *
  * Description:
- *   SCSI controller interrupt handler.
+ *   Constucts a wide data transfer message in the message buffer
+ *   on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
+    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);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_calc_residual
  *
- *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- *         be disabled all through this function unless we say otherwise.
+ * Description:
+ *   Calculate the residual data not yet transferred.
  *-F*************************************************************************/
 static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  int base, intstat, actual, scb_index, run_aborted_queue = FALSE;
-  struct aic7xxx_host *p;
-  struct aic7xxx_scb *scb = NULL;
-  short         transfer;
-  unsigned char ha_flags, scsi_id, bus_width;
-  unsigned char offset, rate, scratch, scratch_offset;
-  unsigned char max_offset, rej_byte;
-  unsigned short target_mask;
-  char channel;
-  unsigned int addr; /* must be 32 bits */
+  struct aic7xxx_hwscb *hscb;
   Scsi_Cmnd *cmd;
+  int actual;
 
-  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+  cmd = scb->cmd;
+  hscb = scb->hscb;
 
   /*
-   * Search for the host with a pending interrupt.  If we can't find
-   * one, then we've encountered a spurious interrupt.
+   *  Don't destroy valid residual information with
+   *  residual coming from a check sense operation.
    */
-  while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND))
+  if (((scb->hscb->control & DISCONNECTED) == 0) &&
+      (scb->flags & SCB_SENSE) == 0)
   {
-    if (p->next == NULL)
-    {
-      p = NULL;
-    }
-    else
+    /*
+     *  We had an underflow. At this time, there's only
+     *  one other driver that bothers to check for this,
+     *  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 -= (hscb->residual_data_count[2] << 16) |
+              (hscb->residual_data_count[1] <<  8) |
+              hscb->residual_data_count[0];
+
+    if (actual < cmd->underflow)
     {
-      p = (struct aic7xxx_host *) p->next->hostdata;
+      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);
+      aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+      aic7xxx_status(cmd) = hscb->target_status;
     }
   }
 
-  if (p == NULL)
-    return;
-
   /*
-   * Keep track of interrupts for /proc/scsi
+   * Clean out the residual information in the SCB for the
+   * next consumer.
    */
-  p->isr_count++;
+  hscb->residual_data_count[2] = 0;
+  hscb->residual_data_count[1] = 0;
+  hscb->residual_data_count[0] = 0;
+  hscb->residual_SG_segment_count = 0;
+}
 
-  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_device_reset
+ *
+ * Description:
+ *   Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+{
+  unsigned short targ_mask;
+  unsigned char  targ_scratch;
+  int scratch_offset = target;
+  int found;
+
+  if (channel == 'B')
   {
-    /*
-     * 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("aic7xxx: (aic7xxx_isr) Encountered spurious interrupt.\n");
-    return;
+    scratch_offset += 8;
   }
-
-  base = p->base;
+  targ_mask = (0x01 << scratch_offset);
   /*
-   * Handle all the interrupt sources - especially for SCSI
-   * interrupts, we won't get a second chance at them.
+   * Go back to async/narrow transfers and renegotiate.
    */
-  intstat = inb(INTSTAT + base);
+  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 &= 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);
+  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+}
 
-  /*
-   * Indicate that we're in the interrupt handler.
-   */
-  p->flags |= IN_ISR;
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_seqint
+ *
+ * Description:
+ *   Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  struct aic7xxx_scb *scb;
+  unsigned short target_mask;
+  unsigned char target, scratch_offset;
+  char channel;
 
-  if (intstat & BRKADRINT)
+  if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
   {
-    int i;
-    unsigned char errno = inb(ERROR + base);
-
-    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)
-      {
-        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
-      }
-    }
-    panic("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
-          inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
+    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_mask = (0x01 << scratch_offset);
 
-  if (intstat & SEQINT)
+  switch (intstat & SEQINT_MASK)
   {
-    /*
-     * Although the sequencer is paused immediately on
-     * a SEQINT, an interrupt for a SCSIINT condition will
-     * unpaused the sequencer before this point.
-     */
-    PAUSE_SEQUENCER(p);
+    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;
 
-    scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
-    scratch_offset = scsi_id;
-    channel = 'A';
-    if (inb(SBLKCTL + base) & SELBUSB)
-    {
-      channel = 'B';
-      scratch_offset += 8;
-    }
-    target_mask = (0x01 << scratch_offset);
+        busy_scbid = aic7xxx_index_busy_target(p, target, channel,
+            /*unbusy*/ FALSE);
+        arg1 = inb(p->base + ARG_1);
 
-    switch (intstat & SEQINT_MASK)
-    {
-      case NO_MATCH:
-       if (p->flags & PAGE_ENABLED)
+        if (arg1 == SCB_LIST_NULL)
         {
-         /* SCB Page-in request */
-         struct aic7xxx_scb *outscb;
-         u_char arg_1 = inb(ARG_1 + base);
-          int use_disconnected = FALSE;
-
-          /*
-           * The sequencer expects this value upon return.  Assume
-           * we will find the paged out SCB and set the value now.
-           * If we don't, and one of the methods used to acquire an
-           * SCB calls aic7xxx_done(), we will end up in our queue
-           * routine and unpause the sequencer without giving it the
-           * correct return value, which causes a hang.
-           */
-         outb(SCB_PAGEDIN, RETURN_1 + base);
-         if (arg_1 == SCB_LIST_NULL)
-          {
-           /* Non-tagged command */
-           int index = scsi_id;
-            if (channel == 'B')
-            {
-              index |= SELBUSB;
-            }
-           scb = p->pagedout_ntscbs[index];
-         }
-         else
-           scb = (p->scb_array[arg_1]);
+          /* untagged request */
+          scb_index = busy_scbid;
+        }
+        else
+        {
+          scb_index = arg1;
+        }
 
-          if (!(scb->state & SCB_PAGED_OUT))
+        if (scb_index < p->scb_data->numscbs)
+        {
+          scb = p->scb_data->scb_array[scb_index];
+          if (scb->hscb->control & ABORT_SCB)
           {
-           printk(KERN_WARNING "scsi%d: No active paged-out SCB for reconnecting "
-                 "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
-                 p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
-           aic7xxx_unbusy_target(scsi_id, channel, base);
-           outb(CLRSELTIMEO, CLRSINT1 + base);
-            outb(0, RETURN_1 + base);
+            /*
+             * 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;
 
-         /*
-          * Now to pick the SCB to page out.  Either take a free SCB, an
-           * assigned SCB, an SCB that just completed, or the first one
-           * on the disconnected SCB list.
-          */
-         if (p->scb_link->free_scbs.head != NULL)
-          {
-           outscb = p->scb_link->free_scbs.head;
-           scbq_remove_head(&p->scb_link->free_scbs);
-           scb->position = outscb->position;
-           outscb->position = SCB_LIST_NULL;
-           scbq_insert_head(&p->page_scbs, outscb);
-           outb(scb->position, SCBPTR + base);
-           aic7xxx_putscb(p, scb);
-           scb->state &= ~SCB_PAGED_OUT;
-         }
-         else if (p->assigned_scbs.head != NULL)
-          {
-            outscb = p->assigned_scbs.head;
-            scbq_remove_head(&p->assigned_scbs);
-            scb->position = outscb->position;
-            outscb->position = SCB_LIST_NULL;
-            scbq_insert_head(&p->waiting_scbs, outscb);
-            outscb->state = (outscb->state & ~SCB_ASSIGNEDQ) | SCB_WAITINGQ;
-            outb(scb->position, SCBPTR + base);
-           aic7xxx_putscb(p, scb);
-            scb->state &= ~SCB_PAGED_OUT;
-          }
-          else if (intstat & CMDCMPLT)
-          {
-            int scb_index;
+    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;
 
-            outb(CLRCMDINT, CLRINT + base);
-            scb_index = inb(QOUTFIFO + base);
-            if (!(inb(QOUTCNT + base) & p->qcntmask))
-            {
-              intstat &= ~CMDCMPLT;
-            }
-            outscb = (p->scb_array[scb_index]);
-            if (!(outscb->state & SCB_ACTIVE))
+        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);
+      }
+      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));
+      }
+      break;
+
+    case NO_IDENT:
+      {
+        /*
+         * The reconnecting target either did not send an identify
+         * message, or did, but we didn't find and 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;
+
+        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));
+
+        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)
+      {
+        printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
+               p->host_no, CHAN_TO_INT(channel), target);
+        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);
+      }
+      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];
+
+       switch (message_code)
+       {
+          case MSG_EXT_SDTR:
+          {
+            unsigned char period;
+            unsigned char offset;
+            unsigned char saved_offset;
+            unsigned char targ_scratch;
+            unsigned char max_offset;
+            unsigned char rate;
+
+            if (message_length != MSG_EXT_SDTR_LEN)
             {
-             printk(KERN_WARNING "scsi%d: No command for completed SCB %d "
-                    "during NO_MATCH interrupt\n", scb_index, p->host_no);
-              use_disconnected = TRUE;
+              outb(SEND_REJ, p->base + RETURN_1);
+              break;
             }
+
+            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);
+
+            if (targ_scratch & WIDEXFER)
+              max_offset = MAX_OFFSET_16BIT;
             else
+              max_offset = MAX_OFFSET_8BIT;
+            offset = MIN(saved_offset, max_offset);
+
+            aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+
+            /*
+             * Preserve the WideXfer flag.
+             */
+            targ_scratch = rate | (targ_scratch & WIDEXFER);
+
+            /*
+             * Update both the target scratch area and current SCSIRATE.
+             */
+            outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+            outb(targ_scratch, p->base + SCSIRATE);
+
+            /*
+             * See if we initiated Sync Negotiation and didn't have
+             * have to fall down to async transfers.
+             */
+            if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
             {
-              scb->position = outscb->position;
-              outscb->position = SCB_LIST_NULL;
-              outb(scb->position, SCBPTR + base);
-              aic7xxx_putscb(p, scb);
-              scb->state &= ~SCB_PAGED_OUT;
-              outscb->cmd->result |= (aic7xxx_error(outscb->cmd) << 16);
-              if ((outscb->cmd->flags & WAS_SENSE) && 
-                 !(outscb->cmd->flags & ASKED_FOR_SENSE))
+              /* We started it. */
+              if (saved_offset == offset)
               {
-                /*
-                 * Got sense information.
-                 */
-               outscb->cmd->flags &= ASKED_FOR_SENSE;
+               /*
+                * Don't send an SDTR back to the target.
+                */
+               outb(0, p->base + RETURN_1);
               }
-              p->device_status[TARGET_INDEX(outscb->cmd)].flags
-                |= DEVICE_SUCCESS;
-              aic7xxx_done(p, outscb);
-            }
-          }
-          else
-          {
-            use_disconnected = TRUE;
-          }
-          if (use_disconnected)
-          {
-           u_char tag;
-           u_char next;
-           u_char disc_scb = inb(DISCONNECTED_SCBH + base);
-           if (disc_scb != SCB_LIST_NULL)
-            {
-             outb(disc_scb, SCBPTR + base);
-             tag = inb(SCB_TAG + base);
-             outscb = (p->scb_array[tag]);
-             next = inb(SCB_NEXT + base);
-             if (next != SCB_LIST_NULL)
-              {
-               outb(next, SCBPTR + base);
-               outb(SCB_LIST_NULL, SCB_PREV + base);
-               outb(disc_scb, SCBPTR + base);
-             }
-             outb(next, DISCONNECTED_SCBH + base);
-             aic7xxx_page_scb(p, outscb, scb);
-           }
-            else if (inb(QINCNT + base) & p->qcntmask)
-            {
-              /* Pull one of our queued commands as a last resort. */
-              disc_scb = inb(QINFIFO + base);
-              outb(disc_scb, SCBPTR + base);
-              tag = inb(SCB_TAG + base);
-              outscb = (p->scb_array[tag]);
-              if ((outscb->control & 0x23) != TAG_ENB)
+              else
               {
-                /*
-                 * This is not a simple tagged command so its position
-                 * in the queue matters.  Take the command at the end of
-                 * the queue instead.
-                 */
-                int i;
-                int saved_queue[AIC7XXX_MAXSCB];
-                int queued = inb(QINCNT + base) & p->qcntmask;
-
-                /* Count the command we removed already */
-                saved_queue[0] = disc_scb;
-                queued++;
-
-                /* Empty the input queue. */
-                for (i = 1; i < queued; i++)
-                {
-                  saved_queue[i] = inb(QINFIFO + base);
-                }
-
-                /* Put everyone back but the last entry. */
-                queued--;
-                for (i = 0; i < queued; i++)
-                {
-                  outb(saved_queue[i], QINFIFO + base);
-                }
-
-                outb(saved_queue[queued], SCBPTR + base);
-                tag = inb(SCB_TAG + base);
-                outscb = (p->scb_array[tag]);
+               /* We went too low - force async. */
+               outb(SEND_REJ, p->base + RETURN_1);
               }
-              scb->position = outscb->position;
-              outscb->position = SCB_LIST_NULL;
-              scbq_insert_head(&p->waiting_scbs, outscb);
-              outscb->state |= SCB_WAITINGQ;
-              aic7xxx_putscb(p, scb);
-              scb->state &= ~SCB_PAGED_OUT;
             }
             else
             {
-             printk(KERN_WARNING "scsi%d: Page-in request with no candidates "
-                   "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
-                   p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
-              aic7xxx_unbusy_target(scsi_id, channel, base);
-              outb(CLRSELTIMEO, CLRSINT1 + base);
-              outb(0, RETURN_1 + base);
+              /*
+               * 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);
             }
+            /*
+             * Clear the flags.
+             */
+            p->needsdtr &= ~target_mask;
+            break;
           }
-       }
-       else
-        {
-         printk(KERN_WARNING "scsi%d: No active SCB for reconnecting "
-               "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
-               p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
-         aic7xxx_unbusy_target(scsi_id, channel, base);
-         outb(0, SCB_CONTROL + base);
-         outb(CLRSELTIMEO, CLRSINT1 + base);
-          outb(0, RETURN_1 + base);
-        }
-       break;
 
-      case BAD_PHASE:
-       panic("scsi%d: Unknown scsi bus phase.\n", p->host_no);
-       break;
+          case MSG_EXT_WDTR:
+          {
+            unsigned char scratch, bus_width;
 
-      case SEND_REJECT:
-        rej_byte = inb(REJBYTE + base);
-        if ((rej_byte & 0xF0) == 0x20)
-        {
-          scb_index = inb(SCB_TAG + base);
-          scb = (p->scb_array[scb_index]);
-          printk(KERN_WARNING "scsi%d: Tagged message received without identify."
-                 "Disabling tagged commands for target %d channel %c.\n",
-                  p->host_no, scsi_id, channel);
-          scb->cmd->device->tagged_supported = 0;
-          scb->cmd->device->tagged_queue = 0;
-        }
-        else
-        {
-          printk(KERN_WARNING "scsi%d: Rejecting unknown message (0x%x) received "
-                 "from target %d channel %c.\n",
-                 p->host_no, rej_byte, scsi_id, channel);
-        }
-       break;
+            if (message_length != MSG_EXT_WDTR_LEN)
+            {
+              outb(SEND_REJ, p->base + RETURN_1);
+              break;
+            }
 
-      case NO_IDENT:
-       panic("scsi%d: Target %d, channel %c, did not send an IDENTIFY "
-             "message. SAVED_TCL 0x%x.\n",
-              p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
-       break;
+            bus_width = inb(p->base + MSGIN_EXT_BYTES);
+            scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
 
-      case SDTR_MSG:
-       /*
-        * Help the sequencer to translate the negotiated
-        * transfer rate. Transfer is 1/4 the period
-        * in ns as is returned by the sync negotiation
-        * message. So, we must multiply by four.
-        */
-       transfer = (inb(ARG_1 + base) << 2);
-       offset = inb(ACCUM + base);
-       scratch = inb(TARG_SCRATCH + base + 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
+            {
+              /*
+               * 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. */
+                 }
+                 break;
+
+               default:
+                 break;
+              }
+              aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
+              outb(SEND_MSG, p->base + RETURN_1);
+            }
+            p->needwdtr &= ~target_mask;
+            outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
+            outb(scratch, p->base + SCSIRATE);
+            break;
+         }  /* case MSG_EXT_WDTR */
+
+          default:
+            /*
+             * Unknown extended message - reject it.
+             */
+            outb(SEND_REJ, p->base + RETURN_1);
+            break;
+       }  /* switch (message_code) */
+      }  /* case EXTENDED_MSG */
+      break;
+
+    case REJECT_MSG:
+      {
        /*
-        * The maximum offset for a wide device is 0x08; for a
-        * 8-bit bus device the maximum offset is 0x0F.
+        * 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.
         */
-       if (scratch & WIDEXFER)
+       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)
        {
-         max_offset = 0x08;
+          /*
+           * 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
        {
-         max_offset = 0x0F;
-       }
-       aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset),
-                         scsi_id, channel);
-       /*
-        * Preserve the wide transfer flag.
-        */
-       scratch = rate | (scratch & WIDEXFER);
-       outb(scratch, TARG_SCRATCH + base + scratch_offset);
-       outb(scratch, SCSIRATE + base);
-       if ((scratch & 0x0F) == 0)
-       {
-          /*
-           * One of two things happened.  Either the device requested
-           * asynchronous data transfers, or it requested a synchronous
-           * data transfer rate that was so low that asynchronous
-           * transfers are faster (not to mention the controller won't
-           * support them).  In both cases the synchronous data transfer
-           * rate and the offset are set to 0 indicating asynchronous
-           * transfers.
-           *
-           * If the device requested an asynchronous transfer, then
-           * accept the request.  If the device is being forced to
-           * asynchronous data transfers and this is the first time
-           * we've seen the request, accept the request.  If we've
-           * already seen the request, then attempt to force
-           * asynchronous data transfers by rejecting the message.
-           */
-          if ((offset == 0) || (p->sdtr_pending & target_mask))
+          if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
           {
             /*
-             * Device requested asynchronous transfers or we're
-             * forcing asynchronous transfers for the first time.
+             * note asynch xfers and clear flag
              */
-            outb(0, RETURN_1 + base);
-          }
-          else
-          {
-            /*
-            * The first time in forcing asynchronous transfers
-             * failed, so we try sending a reject message.
-            */
-           outb(SEND_REJ, RETURN_1 + base);
+            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);
           }
+          /*
+           * Otherwise, we ignore it.
+           */
        }
-       else
-       {
-         /*
-          * See if we initiated Sync Negotiation
-          */
-         if (p->sdtr_pending & target_mask)
-         {
-           /*
-            * Don't send an SDTR back to the target.
-            */
-           outb(0, RETURN_1 + base);
-         }
-         else
-         {
-           /*
-            * Send our own SDTR in reply.
-            */
-           printk("aic7xxx: Sending SDTR!!\n");
-           outb(SEND_SDTR, RETURN_1 + base);
-         }
-       }
-       /*
-        * Clear the flags.
-        */
-       p->needsdtr &= ~target_mask;
-       p->sdtr_pending &= ~target_mask;
-       break;
+        outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+        outb(targ_scratch, p->base + SCSIRATE);
+      }
+      break;
 
-      case WDTR_MSG:
+    case BAD_STATUS:
       {
-       bus_width = inb(ARG_1 + base);
-       printk(KERN_INFO "scsi%d: Received MSG_WDTR, Target %d, channel %c "
-              "needwdtr(0x%x).\n", p->host_no, scsi_id, channel, p->needwdtr);
-       scratch = inb(TARG_SCRATCH + base + scratch_offset);
+       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;
 
-       if (p->wdtr_pending & target_mask)
+       /*
+        * 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))
        {
-         /*
-          * Don't send an WDTR back to the target, since we asked first.
-          */
-         outb(0, RETURN_1 + base);
-         switch (bus_width)
-         {
-           case BUS_8_BIT:
-             scratch &= 0x7F;
-             break;
-
-           case BUS_16_BIT:
-             printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
-                     "transfers.\n", p->host_no, scsi_id, channel);
-             scratch |= 0x80;
-             break;
-
-           case BUS_32_BIT:
-             outb(SEND_REJ, RETURN_1 + base);
-             printk(KERN_INFO "scsi%d: Target %d, channel %c, requesting 32 bit "
-                     "transfers, rejecting...\n", p->host_no, scsi_id, channel);
-             break;
-         }
+          printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+                "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
+                intstat, scb_index, scb->flags, (unsigned int) scb->cmd);
        }
        else
        {
-         /*
-          * Send our own WDTR in reply.
-          */
-         printk(KERN_INFO "scsi%d: Will send WDTR!!\n", p->host_no);
-         switch (bus_width)
-         {
-           case BUS_8_BIT:
-             scratch &= 0x7F;
-             break;
+          cmd = scb->cmd;
+         hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+          aic7xxx_status(cmd) = hscb->target_status;
 
-           case BUS_32_BIT:
-             /*
-               * Negotiate 16 bits.
-               */
-             bus_width = BUS_16_BIT;
-             /* Yes, we mean to fall thru here. */
-
-           case BUS_16_BIT:
-             printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
-                     "transfers.\n", p->host_no, scsi_id, channel);
-             scratch |= 0x80;
-             break;
-         }
-         outb(bus_width | SEND_WDTR, RETURN_1 + base);
-       }
-       p->needwdtr &= ~target_mask;
-       p->wdtr_pending &= ~target_mask;
-       outb(scratch, TARG_SCRATCH + base + scratch_offset);
-       outb(scratch, SCSIRATE + base);
-       break;
+          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));
+              break;
+
+            case CHECK_CONDITION:
+              if ((aic7xxx_error(cmd) == 0) && !(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 = VIRT_TO_BUS(&cmd->sense_buffer);
+               scb->sg_list[0].length = sizeof(cmd->sense_buffer);
+               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+                /*
+                 * XXX - We should allow disconnection, but can't as it
+                 * might allow overlapped tagged commands.
+                 */
+               /* hscb->control &= DISCENB; */
+                hscb->control = 0;
+               hscb->target_status = 0;
+               hscb->SG_segment_count = 1;
+
+               addr = VIRT_TO_BUS(&scb->sg_list[0]);
+               memcpy(&hscb->SG_list_pointer, &addr,
+                      sizeof(hscb->SG_list_pointer));
+
+               memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
+                      sizeof(hscb->data_pointer));
+               /* Maintain SCB_LINKED_NEXT */
+               hscb->data_count &= 0xFF000000;
+               hscb->data_count |= scb->sg_list[0].length;
+
+               addr = VIRT_TO_BUS(scb->sense_cmd);
+               memcpy(&hscb->SCSI_cmd_pointer, &addr,
+                      sizeof(hscb->SCSI_cmd_pointer));
+               hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+
+                scb->sg_count = hscb->SG_segment_count;
+               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);
+              }  /* first time sense, no errors */
+             else
+             {
+               if (aic7xxx_error(cmd) == 0)
+               {
+                 aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+               }
+             }
+              break;
+
+            case QUEUE_FULL:
+#ifdef NOT_YET
+              if (scb->hscb->control & TAG_ENB)
+              {
+               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;
+              }
+#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))
+              {
+               /*
+                * The mid-level SCSI code should be fixed to
+                * retry the command at a later time instead of
+                * trying right away.
+                */
+               aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
+              }
+              udelay(1000);  /*  A small pause (1ms) to help the drive */
+              break;
+
+            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_error(cmd))
+              {
+               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+              }
+              break;
+          }  /* end switch */
+       }  /* end else of */
       }
+      break;
 
-      case REJECT_MSG:
+    case AWAITING_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 scb_index;
+        unsigned char message_offset;
 
-       scratch = inb(TARG_SCRATCH + base + scratch_offset);
+       scb_index = inb(p->base + SCB_TAG);
+       scb = p->scb_data->scb_array[scb_index];
 
-       if (p->wdtr_pending & target_mask)
+       /*
+        * 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)
        {
-         /*
-          * note 8bit xfers and clear flag
-          */
-         scratch &= 0x7F;
-         p->needwdtr &= ~target_mask;
-         p->wdtr_pending &= ~target_mask;
-         printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
-                 "negotiation; using 8 bit transfers.\n",
-                 p->host_no, scsi_id, channel);
+          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));
        }
-       else
+        else if (scb->flags & SCB_ABORT)
+        {
+          if ((scb->hscb->control & TAG_ENB) != 0)
+          {
+            outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+          }
+          else
+          {
+            outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+          }
+          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)
        {
-         if (p->sdtr_pending & target_mask)
-         {
-           /*
-            * note asynch xfers and clear flag
-            */
-           scratch &= 0xF0;
-           p->needsdtr &= ~target_mask;
-           p->sdtr_pending &= ~target_mask;
-           printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
-                   "synchronous negotiation; using asynchronous transfers.\n",
-                   p->host_no, scsi_id, channel);
-         }
-         /*
-          * Otherwise, we ignore it.
-          */
+          aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+          unsigned char target_scratch;
+          unsigned short ultra_enable;
+          int i, sxfr;
+
+          /*
+           * Pull the user defined setting from scratch RAM.
+           */
+          target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+          sxfr = target_scratch & SXFR;
+          ultra_enable = inb(p->base + ULTRA_ENB) |
+              (inb(p->base + ULTRA_ENB + 1) << 8);
+          if (ultra_enable & target_mask)
+          {
+            sxfr |= 0x100;
+          }
+          for (i = 0; i < num_aic7xxx_syncrates; i++)
+          {
+            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);
+        }
+        else 
+        {
+          panic("aic7xxx: AWAITING_MSG for an SCB that does "
+                "not have a waiting message.");
        }
-       outb(scratch, TARG_SCRATCH + base + scratch_offset);
-       outb(scratch, SCSIRATE + base);
-       break;
       }
+      break;
 
-      case BAD_STATUS:
-        /* 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 sequencerrunning in the common case of command completes
-         * without error.
-         */
+    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++)
+        {
+          printk(KERN_INFO "     sg[%d] - Addr 0x%x : Length %d\n",
+                 i, scb->sg_list[i].address, scb->sg_list[i].length);
+        }
+       /*
+        * 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;
+      }
+      break;
 
-       scb_index = inb(SCB_TAG + base);
-       scb = (p->scb_array[scb_index]);
-       outb(0, RETURN_1 + base);   /* CHECK_CONDITION may change this */
-       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
-       {
-         printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-                "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
-                intstat, scb_index, scb->state, (unsigned long) scb->cmd);
-       }
-       else
-       {
-         cmd = scb->cmd;
-          scb->target_status = inb(SCB_TARGET_STATUS + base);
-         aic7xxx_status(cmd) = scb->target_status;
+/* #if AIC7XXX_NOT_YET */
+    /* XXX Fill these in later */
+    case MSG_BUFFER_BUSY:
+      printk("aic7xxx: Message buffer busy.\n");
+      break;
+    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;
 
-         cmd->result |= scb->target_status;
+    default:              /* unknown */
+      printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+             p->host_no, intstat, inb(p->base + SCSISIGI));
+      break;
+  }
 
-         switch (status_byte(scb->target_status))
-         {
-           case GOOD:
-              printk(KERN_WARNING "aic7xxx: Interrupted for status of GOOD???\n");
-             break;
+  /*
+   * Clear the sequencer interrupt and unpause the sequencer.
+   */
+  outb(CLRSEQINT, p->base + CLRINT);
+  unpause_sequencer(p, /* unpause always */ TRUE);
+}
 
-           case CHECK_CONDITION:
-             if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
-             {
-                unsigned char tcl;
-               unsigned int  req_buf; /* must be 32 bits */
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_scsiint
+ *
+ * Description:
+ *   Interrupt handler for SCSI interrupts (SCSIINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  unsigned char scb_index;
+  unsigned char status;
+  struct aic7xxx_scb *scb;
 
-                tcl = scb->target_channel_lun;
+  scb_index = inb(p->base + SCB_TAG);
+  status = inb(p->base + SSTAT1);
 
-               /*
-                 * Send a sense command to the requesting target.
-                 */
-               cmd->flags |= WAS_SENSE;
-               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 = VIRT_TO_BUS(&cmd->sense_buffer);
-               scb->sg_list[0].length = sizeof(cmd->sense_buffer);
-               req_buf = VIRT_TO_BUS(&scb->sg_list[0]);
-               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
-                scb->control = scb->control & DISCENB;
-               scb->target_channel_lun = tcl;
-               addr = VIRT_TO_BUS(scb->sense_cmd);
-               scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
-               memcpy(scb->SCSI_cmd_pointer, &addr,
-                      sizeof(scb->SCSI_cmd_pointer));
-               scb->SG_segment_count = 1;
-               memcpy(scb->SG_list_pointer, &req_buf,
-                      sizeof(scb->SG_list_pointer));
-                scb->data_count = scb->sg_list[0].length;
-               memcpy(scb->data_pointer, &(scb->sg_list[0].address),
-                      sizeof(scb->data_pointer));
-
-                aic7xxx_putscb(p, scb);
-                /*
-                 * Ensure that the target is "BUSY" so we don't get overlapping
-                 * commands if we happen to be doing tagged I/O.
-                 */
-               aic7xxx_busy_target(scsi_id, channel, base);
+  if (scb_index < p->scb_data->numscbs)
+  {
+    scb = p->scb_data->scb_array[scb_index];
+    if ((scb->flags & SCB_ACTIVE) == 0)
+    {
+      scb = NULL;
+    }
+  }
+  else
+  {
+    scb = NULL;
+  }
 
-                aic7xxx_add_waiting_scb(base, scb);
-               outb(SEND_SENSE, RETURN_1 + base);
-             }  /* first time sense, no errors */
-              else
-              {
-                cmd->flags &= ~ASKED_FOR_SENSE;
-               if (aic7xxx_error(cmd) == 0)
-                {
-                 aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-                }
-              }
-             break;
-
-           case BUSY:
-             printk(KERN_WARNING "scsi%d: Target busy, TCL=0x%x.\n",
-                     p->host_no, scb->target_channel_lun);
-             if (!aic7xxx_error(cmd))
-             {
-                /* The error code here used to be DID_BUS_BUSY,
-                 * but after extensive testing, it has been determined
-                 * that a DID_BUS_BUSY return is a waste of time.  If
-                 * the problem is something that will go away, then it
-                 * will, if it isn't, then you don't want the endless
-                 * looping that you get with a DID_BUS_BUSY.  Better
-                 * to be on the safe side and specify an error condition
-                 * that will eventually lead to a reset or abort of some
-                 * sort instead of an endless loop.
-                 */
-               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-             }
-             break;
-
-           case QUEUE_FULL:
-             printk(KERN_WARNING "scsi%d: Queue full.\n", p->host_no);
-              scb->state |= SCB_ASSIGNEDQ;
-              scbq_insert_tail(&p->assigned_scbs, scb);
-             break;
-
-           default:
-             printk(KERN_WARNING "scsi%d: Unexpected target status 0x%x.\n",
-                    p->host_no, scb->target_status);
-             if (!aic7xxx_error(cmd))
-             {
-               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-             }
-             break;
-         }  /* end switch */
-       }  /* end else of */
-       break;
+  if ((status & SCSIRSTI) != 0)
+  {
+    char channel;
 
-      case RESIDUAL:
-       scb_index = inb(SCB_TAG + base);
-       scb = (p->scb_array[scb_index]);
-       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
-       {
-         printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-                "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
-                intstat, scb_index, scb->state, (unsigned long) scb->cmd);
-       }
-       else
-       {
-         cmd = scb->cmd;
-         /*
-          *  Don't destroy valid residual information with
-          *  residual coming from a check sense operation.
-          */
-         if (!(cmd->flags & WAS_SENSE))
-         {
-           /*
-            *  We had an underflow. At this time, there's only
-            *  one other driver that bothers to check for this,
-            *  and cmd->underflow seems to be set rather half-
-            *  heartedly in the higher-level SCSI code.
-            */
-           actual = aic7xxx_length(cmd, scb->residual_SG_segment_count);
-
-           actual -= (inb(SCB_RESID_DCNT2 + base) << 16) |
-                     (inb(SCB_RESID_DCNT1 + base) <<  8) |
-                     inb(SCB_RESID_DCNT0 + base);
-
-           if (actual < cmd->underflow)
-           {
-             printk(KERN_WARNING "scsi%d: Target %d underflow - "
-                    "Wanted at least %u, got %u, residual SG count %d.\n",
-                    p->host_no, cmd->target, cmd->underflow, actual,
-                     inb(SCB_RESID_SGCNT + base));
-             aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-             aic7xxx_status(cmd) = scb->target_status;
-           }
-         }
-       }
-       break;
+    channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
 
-      case ABORT_TAG:
-       scb_index = inb(SCB_TAG + base);
-       scb = (p->scb_array[scb_index]);
-       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
-       {
-         printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-                "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx\n", p->host_no,
-                intstat, scb_index, scb->state, (unsigned long) scb->cmd);
-       }
-       else
-       {
-         cmd = scb->cmd;
-         /*
-          * We didn't receive a valid tag back from the target
-          * on a reconnect.
-          */
-         printk("scsi%d: Invalid tag received on target %d, channel %c, "
-                 "lun %d - Sending ABORT_TAG.\n", p->host_no,
-                 scsi_id, channel, cmd->lun & 0x07);
-
-         cmd->result = (DID_RETRY_COMMAND << 16);
-          aic7xxx_done(p, scb);
-       }
-       break;
+    printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
+           p->host_no, channel);
+    /*
+     * Go through and abort all commands for the channel, but do not
+     * reset the channel again.
+     */
+    aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+    scb = NULL;
+  }
+  else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
+  {
+    /*
+     * First look at what phase we were last in.  If it's message-out,
+     * 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';
+    int printerror = TRUE;
 
-      case AWAITING_MSG:
-       scb_index = inb(SCB_TAG + base);
-       scb = (p->scb_array[scb_index]);
-       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
-       {
-         printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-                "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
-                intstat, scb_index, scb->state, (unsigned long) scb->cmd);
-       }
-       else
-       {
-         /*
-          * This SCB had a zero length command, informing the sequencer
-          * that we wanted to send a special message to this target.
-          * We only do this for BUS_DEVICE_RESET messages currently.
-          */
-          if (scb->state & SCB_DEVICE_RESET)
-          {
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (isr) sending bus device reset to target %d\n",
-          scsi_id);
-#endif
-            outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
-            outb(1, MSG_LEN + base);
-          }
-          else
-          {
-            panic("scsi%d: AWAITING_SCB for an SCB that does "
-                  "not have a waiting message.\n", p->host_no);
-          }
-       }
-       break;
+    outb(0, p->base + SCSISEQ);
+    if (lastphase == P_MESGOUT)
+    {
+      unsigned char sindex;
+      unsigned char message;
 
-      case IMMEDDONE:
-        scb_index = inb(SCB_TAG + base);
-       scb = (p->scb_array[scb_index]);
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: received IMMEDDONE for target %d, scb %d, state %d\n",
-         scsi_id, scb_index, scb->state);
-#endif
-        if (scb->state & SCB_DEVICE_RESET)
-        {
-          int found;
+      sindex = inb(p->base + SINDEX);
+      message = inb(p->base + sindex - 1);
 
-          /*
-           * Go back to async/narrow transfers and renegotiate.
-           */
-          aic7xxx_unbusy_target(scsi_id, channel, base);
-          p->needsdtr |= (p->needsdtr_copy & target_mask);
-          p->needwdtr |= (p->needwdtr_copy & target_mask);
-          p->sdtr_pending &= ~target_mask;
-          p->wdtr_pending &= ~target_mask;
-          scratch = inb(TARG_SCRATCH + base + scratch_offset);
-          scratch &= SXFR;
-          outb(scratch, TARG_SCRATCH + base + scratch_offset);
-          found = aic7xxx_reset_device(p, (int) scsi_id, channel);
-          printk(KERN_INFO "scsi%d: Bus Device Reset delivered, %d SCBs "
-                 "aborted.\n", p->host_no, found);
-          /* Indicate that we want to call aic7xxx_done_aborted_scbs() */
-          run_aborted_queue = TRUE;
+      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)
+      {
+        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);
+        scb = NULL;
+        printerror = 0;
+      }
+      else if (message == MSG_BUS_DEV_RESET)
+      {
+        aic7xxx_handle_device_reset(p, target, channel);
+        scb = NULL;
+        printerror = 0;
+      }
+    }
+    if (printerror != 0)
+    {
+      if (scb != NULL)
+      {
+        unsigned char tag;
+
+        if ((scb->hscb->control & TAG_ENB) != 0)
+        {
+          tag = scb->hscb->tag;
         }
         else
         {
-          panic("scsi%d: Immediate complete for unknown operation.\n",
-                p->host_no);
+          tag = SCB_LIST_NULL;
         }
-        break;
+        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+      }
+      else
+      {
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+      }
+      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);
+    restart_sequencer(p);
+  }
+  else if ((status & SELTO) != 0)
+  {
+    unsigned char scbptr;
+    unsigned char nextscb;
+    Scsi_Cmnd *cmd;
+
+    scbptr = inb(p->base + WAITING_SCBH);
+    outb(scbptr, p->base + SCBPTR);
+    scb_index = inb(p->base + SCB_TAG);
 
-      case DATA_OVERRUN:
+    scb = NULL;
+    if (scb_index < p->scb_data->numscbs)
+    {
+      scb = p->scb_data->scb_array[scb_index];
+      if ((scb->flags & SCB_ACTIVE) == 0)
       {
-        unsigned int overrun;
-
-        scb = (p->scb_array[inb(base + SCB_TAG)]);
-        overrun = inb(base + STCNT0) | (inb(base + STCNT1) << 8) |
-                  (inb(base + STCNT2) << 16);
-        overrun =0x00FFFFFF - overrun;
-        printk(KERN_WARNING "scsi%d: data overrun of %d bytes detected; forcing "
-               "a retry.\n", p->host_no, overrun);
-        aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
-        break;
+        scb = NULL;
       }
+    }
+    if (scb == NULL)
+    {
+      printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
+             p->host_no, 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));
+    }
+    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.
+       */
+      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);
+
+      /*
+       * Shift the waiting for selection queue forward
+       */
+      nextscb = inb(p->base + SCB_NEXT);
+      outb(nextscb, p->base + WAITING_SCBH);
+
+      /*
+       * Put this SCB back on the free list.
+       */
+      aic7xxx_add_curscb_to_free_list(p);
+    }
+    /*
+     * Stop the selection.
+     */
+    outb(0, p->base + SCSISEQ);
+    outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
+    outb(CLRSCSIINT, p->base + CLRINT);
+    restart_sequencer(p);
+  }
+  else if (scb == NULL)
+  {
+    printk(KERN_WARNING "scsi%d: 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));
+    /*
+     * 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);
+    unpause_sequencer(p, /* unpause always */ TRUE);
+    scb = NULL;
+  }
+  else if (status & SCSIPERR)
+  {
+    /*
+     * Determine the bus phase and queue an appropriate message.
+     */
+    char  *phase;
+    Scsi_Cmnd *cmd;
+    unsigned char mesg_out = MSG_NOOP;
+    unsigned char lastphase = inb(p->base + LASTPHASE);
 
-#if AIC7XXX_NOT_YET
-      /* XXX Fill these in later */
-      case MESG_BUFFER_BUSY:
+    cmd = scb->cmd;
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        phase = "Data-Out";
         break;
-      case MSGIN_PHASEMIS:
+      case P_DATAIN:
+        phase = "Data-In";
+        mesg_out = MSG_INITIATOR_DET_ERR;
         break;
-#endif
+      case P_COMMAND:
+        phase = "Command";
+        break;
+      case P_MESGOUT:
+        phase = "Message-Out";
+        break;
+      case P_STATUS:
+        phase = "Status";
+        mesg_out = MSG_INITIATOR_DET_ERR;
+        break;
+      case P_MESGIN:
+        phase = "Message-In";
+        mesg_out = MSG_PARITY_ERROR;
+        break;
+      default:
+        phase = "unknown";
+        break;
+    }
+
+    /*
+     * 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);
 
-      default:               /* unknown */
-       printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
-              p->host_no, intstat, inb(SCSISIGI + base));
-       break;
+    /*
+     * We've set the hardware to assert ATN if we get a parity
+     * error on "in" phases, so all we need to do is stuff the
+     * message buffer with the appropriate message.  "In" phases
+     * have set mesg_out to something other than MSG_NOP.
+     */
+    if (mesg_out != MSG_NOOP)
+    {
+      outb(mesg_out, p->base + MSG_OUT);
+      outb(1, p->base + MSG_LEN);
+      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);
+    unpause_sequencer(p, /* unpause_always */ TRUE);
+  }
+  else
+  {
+    /*
+     * 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);
+    unpause_sequencer(p, /* unpause always */ TRUE);
+    scb = NULL;
+  }
+  if (scb != NULL)
+  {
+    aic7xxx_done(p, scb);
+    aic7xxx_done_cmds_complete(p);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_isr
+ *
+ * Description:
+ *   SCSI controller interrupt handler.
+ *
+ *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
+ *         be disabled all through this function unless we say otherwise.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct aic7xxx_host *p;
+  unsigned char intstat;
+  unsigned long flags;
 
-    /*
-     * Clear the sequencer interrupt and unpause the sequencer.
-     */
-    outb(CLRSEQINT, CLRINT + base);
-    UNPAUSE_SEQUENCER(p);
-  }
+  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
 
-  if (intstat & SCSIINT)
+  /*
+   * Search for the host with a pending interrupt.  If we can't find
+   * one, then we've encountered a spurious interrupt.
+   */
+  while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
   {
-    int status = inb(SSTAT1 + base);
-    scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
-    channel = 'A';
-    if (inb(SBLKCTL + base) & SELBUSB)
-    {
-      channel = 'B';
-    }
-
-    scb_index = inb(SCB_TAG + base);
-    scb = (p->scb_array[scb_index]);
-    if (status & SCSIRSTI)
-    {
-      PAUSE_SEQUENCER(p);
-      printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
-             p->host_no, channel);
-      /*
-       * Go through and abort all commands for the channel, but do not
-       * reset the channel again.
-       */
-      aic7xxx_reset_channel(p, channel, FALSE);
-      run_aborted_queue = TRUE;
-    }
-    else if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+    if (p->next == NULL)
     {
-      printk(KERN_WARNING "scsi%d: SCSIINT - No command for SCB.\n", p->host_no);
-      /*
-       * Turn off the interrupt and set status to zero, so that it
-       * falls through the rest of the SCSIINT code.
-       */
-      outb(status, CLRSINT1 + base);
-      UNPAUSE_SEQUENCER(p);
-      outb(CLRSCSIINT, CLRINT + base);
-      scb = NULL;
+      p = NULL;
     }
-    else if (status & SCSIPERR)
+    else
     {
-      char  *phase;
-      unsigned char mesg_out = MSG_NOP;
-      unsigned char lastphase = inb(LASTPHASE + base);
-
-      cmd = scb->cmd;
-      switch (lastphase)
-      {
-        case P_DATAOUT:
-          phase = "Data-Out";
-          break;
-        case P_DATAIN:
-          phase = "Data-In";
-          mesg_out = MSG_INITIATOR_DET_ERROR;
-          break;
-        case P_COMMAND:
-          phase = "Command";
-          break;
-        case P_MESGOUT:
-          phase = "Message-Out";
-          break;
-        case P_STATUS:
-          phase = "Status";
-          mesg_out = MSG_INITIATOR_DET_ERROR;
-          break;
-        case P_MESGIN:
-          phase = "Message-In";
-          mesg_out = MSG_MSG_PARITY_ERROR;
-          break;
-        default:
-          phase = "unknown";
-          break;
-      }
-
-      /*
-       * A parity error has occurred during a data
-       * transfer phase. Flag it and continue.
-       */
-      printk(KERN_WARNING "scsi%d: Parity error during phase %s on target %d, "
-             "channel %d, lun %d.\n", p->host_no, phase,
-             cmd->target, cmd->channel & 0x01, cmd->lun & 0x07);
-
-      /*
-       * We've set the hardware to assert ATN if we get a parity
-       * error on "in" phases, so all we need to do is stuff the
-       * message buffer with the appropriate message. In phases
-       * have set mesg_out to something other than MSG_NOP.
-       */
-      if (mesg_out != MSG_NOP)
-      {
-        outb(mesg_out, MSG0 + base);
-        outb(1, MSG_LEN + base);
-        cmd->result = DID_PARITY << 16;
-      }
-      else
-      {
-        /*
-         * Should we allow the target to make this decision for us?
-         */
-        cmd->result = DID_RETRY_COMMAND << 16;
-      }
-      aic7xxx_done(p, scb);
+      p = (struct aic7xxx_host *) p->next->hostdata;
     }
-    else if (status & SELTO)
-    {
-      unsigned char waiting;
+  }
 
-      cmd = scb->cmd;
+  if (p == NULL)
+    return;
 
-      cmd->result = (DID_TIME_OUT << 16);
-      /*
-       * Clear an pending messages for the timed out
-       * target and mark the target as free.
-       */
-      ha_flags = inb(FLAGS + base);
-      outb(0, MSG_LEN + base);
-      aic7xxx_unbusy_target(scsi_id, channel, base);
-      /*
-       * Stop the selection.
-       */
-      outb(0, SCSISEQ + base);
-      outb(0, SCB_CONTROL + base);
-      outb(CLRSELTIMEO, CLRSINT1 + base);
-      outb(CLRSCSIINT, CLRINT + base);
+  /*
+   * Handle all the interrupt sources - especially for SCSI
+   * interrupts, we won't get a second chance at them.
+   */
+  intstat = inb(p->base + INTSTAT);
 
-      /*
-       * Shift the waiting for selection queue forward
-       */
-      waiting = inb(WAITING_SCBH + base);
-      outb(waiting, SCBPTR + base);
-      waiting = inb(SCB_NEXT + base);
-      outb(waiting, WAITING_SCBH + base);
+  /*
+   * Keep track of interrupts for /proc/scsi
+   */
+  p->isr_count++;
 
-      RESTART_SEQUENCER(p);
-      aic7xxx_done(p, scb);
-    }
-    else if (!(status & BUSFREE))
+  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+  {
+    /*
+     * 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)
     {
-      /*
-       * 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, CLRSINT1 + base);
-      UNPAUSE_SEQUENCER(p);
-      outb(CLRSCSIINT, CLRINT + base);
+      /* Try clearing all interrupts. */
+      outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
     }
+    return;
+  }
+
+  if (p->flags & IN_ISR)
+  {
+    printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
+           p->host_no);
+    return;
   }
 
-  if (run_aborted_queue)
-    aic7xxx_done_aborted_scbs(p);
+  /*
+   * Indicate that we're in the interrupt handler.
+   */
+  save_flags(flags);
+  cli();
+  p->flags |= IN_ISR;
 
   if (intstat & CMDCMPLT)
   {
-    int complete;
+    struct aic7xxx_scb *scb = NULL;
+    Scsi_Cmnd *cmd;
+    unsigned char qoutcnt;
+    unsigned char scb_index;
+    int i, interrupts_cleared = 0;
 
     /*
      * The sequencer will continue running when it
      * issues this interrupt. There may be >1 commands
      * finished, so loop until we've processed them all.
      */
-    do {
-      complete = inb(QOUTFIFO + base);
+    qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
 
-      scb = (p->scb_array[complete]);
-      if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
-      {
-       printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n"
-              "       QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%lx, "
-               "pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base),
-               inb(QINCNT + base), scb->state, (unsigned long) scb->cmd,
-               scb->position);
-       outb(CLRCMDINT, CLRINT + base);
-       continue;
-      }
-      cmd = scb->cmd;
-      cmd->result |= (aic7xxx_error(cmd) << 16);
-      if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
+#if 1
+  if (qoutcnt >= p->qfullcount - 1)
+    printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
+           "qoutcnt = %d.\n", qoutcnt);
+#endif
+    while (qoutcnt > 0)
+    {
+      for (i = 0; i < qoutcnt; i++)
       {
-        /*
-         * Got sense information.
-         */
-       cmd->flags &= ASKED_FOR_SENSE;
+        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)
+          {
+            tag = scb->hscb->tag;
+          }
+          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);
       }
-      p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-
       /*
        * Clear interrupt status before checking the output queue again.
        * This eliminates a race condition whereby a command could
@@ -3243,56 +3941,152 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
        * so notification of the command being complete never made it
        * back up to the kernel.
        */
-      outb(CLRCMDINT, CLRINT + base);
-      aic7xxx_done(p, scb);
+      outb(CLRCMDINT, p->base + CLRINT);
+      interrupts_cleared++;
+      qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
+    }
 
-#ifdef AIC7XXX_PROC_STATS
-      /*
-       * XXX: we should actually know how much actually transferred
-       * XXX: for each command, but apparently that's too difficult.
-       */
-      actual = aic7xxx_length(cmd, 0);
-      if (!(cmd->flags & WAS_SENSE) && (actual > 0))
+    if (interrupts_cleared == 0)
+    {
+      outb(CLRCMDINT, p->base + CLRINT);
+    }
+
+    aic7xxx_done_cmds_complete(p);
+  }
+
+  if (intstat & BRKADRINT)
+  {
+    int i;
+    unsigned char errno = inb(p->base + ERROR);
+
+    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)
       {
-        struct aic7xxx_xferstats *sp;
-        long *ptr;
-        int x;
+        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);
+  }
+
+  if (intstat & SEQINT)
+  {
+    aic7xxx_handle_seqint(p, intstat);
+  }
+
+  if (intstat & SCSIINT)
+  {
+    aic7xxx_handle_scsiint(p, intstat);
+  }
+
+  if (p->waiting_scbs.head != NULL)
+  {
+    aic7xxx_run_waiting_queues(p);
+  }
+
+  p->flags &= ~IN_ISR;
+  restore_flags(flags);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_device_queue_depth
+ *
+ * Description:
+ *   Determines the queue depth for a given device.  There are two ways
+ *   a queue depth can be obtained for a tagged queueing device.  One
+ *   way is the default queue depth which is determined by whether
+ *   AIC7XXX_CMDS_PER_LUN is defined.  If it is defined, then it is used
+ *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
+ *   default queue depth (dependent on the number of hardware SCBs).
+ *   The other way we determine queue depth is through the use of the
+ *   aic7xxx_tag_info array which is enabled by defining
+ *   AIC7XXX_TAGGED_QUEUEING_BY_DEVICE.  This array can be initialized
+ *   with queue depths for individual devices.  It also allows tagged
+ *   queueing to be [en|dis]abled for a specific adapter.
+ *-F*************************************************************************/
+static void
+aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
+{
+  int default_depth = 2;
+
+  device->queue_depth = default_depth;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+  if (device->tagged_supported)
+  {
+    unsigned short target_mask;
+    int tag_enabled = TRUE;
+
+    target_mask = (1 << (device->id | (device->channel << 3)));
 
-        sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
-        sp->xfers++;
+#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;
+    }
+#endif
+    if (!(p->discenable & target_mask))
+    {
+      printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+             "enable tagged queueing.\n",
+             p->host_no, device->id, device->channel);
+    }
+    else
+    {
+#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+      device->queue_depth = default_depth;
+#else
+      if (p->instance > NUMBER(aic7xxx_tag_info))
+      {
+        device->queue_depth = default_depth;
+      }
+      else
+      {
+        unsigned char  tindex;
 
-        if (cmd->request.cmd == WRITE)
+        tindex = device->id | (device->channel << 3);
+        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
         {
-          sp->w_total++;
-          sp->w_total512 += (actual >> 9);
-          ptr = sp->w_bins;
+          tag_enabled = FALSE;
+          device->queue_depth = 2;  /* Tagged queueing is disabled. */
         }
-        else
+        else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
         {
-          sp->r_total++;
-          sp->r_total512 += (actual >> 9);
-          ptr = sp->r_bins;
+          device->queue_depth = default_depth;
         }
-        for (x = 9; x <= 17; x++)
+        else
         {
-          if (actual < (1 << x))
-          {
-            ptr[x - 9]++;
-            break;
-          }
+          device->queue_depth =
+            aic7xxx_tag_info[p->instance].tag_commands[tindex];
         }
-        if (x > 17)
+      }
+#endif
+      if ((device->tagged_queue == 0) && tag_enabled)
+      {
+        if (aic7xxx_verbose)
         {
-          ptr[x - 9]++;
+         printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
+                "queue depth %d.\n", p->host_no,
+                device->id, device->channel, device->queue_depth);
         }
+        device->tagged_queue = 1;
+        device->current_tag = SCB_LIST_NULL;
       }
-#endif /* AIC7XXX_PROC_STATS */
-
-    } while (inb(QOUTCNT + base) & p->qcntmask);
+    }
   }
-  aic7xxx_done_cmds_complete(p);
-  p->flags &= ~IN_ISR;
-  aic7xxx_run_waiting_queues(p);
+#endif
 }
 
 /*+F*************************************************************************
@@ -3307,59 +4101,18 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
  *   algorithm for determining the queue depth based on the maximum
  *   SCBs for the controller.
  *-F*************************************************************************/
-static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
+static void
+aic7xxx_select_queue_depth(struct Scsi_Host *host,
     Scsi_Device *scsi_devs)
 {
-  Scsi_Device *device = scsi_devs;
-  int tq_depth = 2;
+  Scsi_Device *device;
   struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
 
-#ifdef AIC7XXX_CMDS_PER_LUN
-  tq_depth = AIC7XXX_CMDS_PER_LUN;
-#else
-  {
-    if (p->maxhscbs <= 4)
-    {
-      tq_depth = 4;  /* Not many SCBs to work with. */
-    }
-    else
-    {
-      tq_depth = 8;
-    }
-  }
-#endif
-
   for (device = scsi_devs; device != NULL; device = device->next)
   {
     if (device->host == host)
     {
-      device->queue_depth = 2;
-#ifdef AIC7XXX_TAGGED_QUEUEING
-      if (device->tagged_supported)
-      {
-        unsigned short target_mask = (1 << device->id) | device->channel;
-
-        if (!(p->discenable & target_mask))
-        {
-          printk(KERN_INFO "scsi%d: Disconnection disabled, unable to enable "
-                 "tagged queueing for target %d, channel %d, LUN %d.\n",
-                 host->host_no, device->id, device->channel, device->lun);
-        }
-        else
-        {
-          device->queue_depth = tq_depth;
-          if (device->tagged_queue == 0)
-          {
-            printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, "
-                  "channel %d, LUN %d, queue depth %d.\n", host->host_no,
-                   device->id, device->channel, device->lun,
-                   device->queue_depth);
-            device->tagged_queue = 1;
-            device->current_tag = SCB_LIST_NULL;
-          }
-        }
-      }
-#endif
+      aic7xxx_device_queue_depth(p, device);
     }
   }
 }
@@ -3386,7 +4139,7 @@ static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
  *   The fourth byte's lowest bit seems to be an enabled/disabled
  *   flag (rest of the bits are reserved?).
  *-F*************************************************************************/
-static aha_type
+static aha_chip_type
 aic7xxx_probe(int slot, int base, aha_status_type *bios)
 {
   int i;
@@ -3395,7 +4148,7 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
   static struct {
     int n;
     unsigned char signature[sizeof(buf)];
-    aha_type type;
+    aha_chip_type type;
     int bios_disabled;
   } AIC7xxx[] = {
     { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
@@ -3434,7 +4187,8 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
        return (AIC7xxx[i].type);
       }
 
-      printk("aic7xxx: Disabled at slot %d, ignored.\n", slot);
+      printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
+             "disabled at slot %d, ignored.\n", slot);
     }
   }
 
@@ -3461,10 +4215,9 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
  *   useful in that it gives us an 800 nsec timer.  After a read from the
  *   SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
  *   later.
- *
  *-F*************************************************************************/
 static int
-read_2840_seeprom(int base, struct seeprom_config *sc)
+read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
 {
   int i = 0, k = 0;
   unsigned char temp;
@@ -3477,11 +4230,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(STATUS_2840 + base) & EEPROM_TF) == 0)   \
+  while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0)        \
   {                                            \
     ;  /* Do nothing */                                \
   }                                            \
-  (void) inb(SEECTL_2840 + base);
+  (void) inb(p->base + SEECTL_2840);
 
   /*
    * Read the first 32 registers of the seeprom.  For the 2840,
@@ -3494,8 +4247,8 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     /*
      * Send chip select for one clock cycle.
      */
-    outb(CK_2840 | CS_2840, SEECTL_2840 + base);
-    CLOCK_PULSE(base);
+    outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+    CLOCK_PULSE(p);
 
     /*
      * Now we're ready to send the read command followed by the
@@ -3504,11 +4257,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = CS_2840 | seeprom_read.bits[i];
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
     }
     /*
      * Send the 6 bit address (MSB first, LSB last).
@@ -3518,11 +4271,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
       temp = k;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = CS_2840 | temp;
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
     }
 
     /*
@@ -3534,12 +4287,12 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     for (i = 0; i <= 16; i++)
     {
       temp = CS_2840;
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840 + base) & DI_2840);
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
     }
     /*
      * The serial EEPROM has a checksum in the last word.  Keep a
@@ -3555,12 +4308,12 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(0, SEECTL_2840 + base);
-    CLOCK_PULSE(base);
-    outb(CK_2840, SEECTL_2840 + base);
-    CLOCK_PULSE(base);
-    outb(0, SEECTL_2840 + base);
-    CLOCK_PULSE(base);
+    outb(0, p->base + SEECTL_2840);
+    CLOCK_PULSE(p);
+    outb(CK_2840, p->base + SEECTL_2840);
+    CLOCK_PULSE(p);
+    outb(0, p->base + SEECTL_2840);
+    CLOCK_PULSE(p);
   }
 
 #if 0
@@ -3574,17 +4327,64 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     }
     printk(" 0x%x", seeprom[k]);
   }
-  printk("\n");
-#endif
-
-  if (checksum != sc->checksum)
+  printk("\n");
+#endif
+
+  if (checksum != sc->checksum)
+  {
+    printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
+    return (0);
+  }
+
+  return (1);
+#undef CLOCK_PULSE
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   acquire_seeprom
+ *
+ * Description:
+ *   Acquires access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline int
+acquire_seeprom(struct aic7xxx_host *p)
+{
+  int wait;
+
+  /*
+   * Request access of the memory port.  When access is
+   * granted, SEERDY will go high.  We use a 1 second
+   * timeout which should be near 1 second more than
+   * is needed.  Reason: after the 7870 chip reset, there
+   * should be no contention.
+   */
+  outb(SEEMS, p->base + SEECTL);
+  wait = 1000;  /* 1000 msec = 1 second */
+  while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+  {
+    wait--;
+    udelay(1000);  /* 1 msec */
+  }
+  if ((inb(p->base + SEECTL) & SEERDY) == 0)
   {
-    printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
+    outb(0, p->base + SEECTL);
     return (0);
   }
-
   return (1);
-#undef CLOCK_PULSE
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   release_seeprom
+ *
+ * Description:
+ *   Releases access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline void
+release_seeprom(struct aic7xxx_host *p)
+{
+  outb(0, p->base + SEECTL);
 }
 
 /*+F*************************************************************************
@@ -3626,7 +4426,7 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
  *   first).  The clock cycling from low to high initiates the next data
  *   bit to be sent from the chip.
  *
- *   The 7870 interface to the 93C46 serial EEPROM is through the SEECTL
+ *   The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
  *   register.  After successful arbitration for the memory port, the
  *   SEECS bit of the SEECTL register is connected to the chip select.
  *   The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
@@ -3636,17 +4436,14 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
  *   to this is when we first request access to the memory port.  The
  *   SEERDY goes high to signify that access has been granted and, for
  *   this case, has no implied timing.
- *
  *-F*************************************************************************/
 static int
-read_seeprom(int base, int offset, struct seeprom_config *sc,
-    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 long timeout;
   unsigned char temp;
   unsigned short checksum = 0;
-  unsigned short *seeprom = (unsigned short *) sc;
   struct seeprom_cmd {
     unsigned char len;
     unsigned char bits[3];
@@ -3654,43 +4451,33 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(SEECTL + base) & SEERDY) == 0)   \
+  while ((inb(p->base + SEECTL) & SEERDY) == 0)        \
   {                                            \
     ;  /* Do nothing */                                \
   }
 
   /*
-   * Request access of the memory port.  When access is
-   * granted, SEERDY will go high.  We use a 1 second
-   * timeout which should be near 1 second more than
-   * is needed.  Reason: after the 7870 chip reset, there
-   * should be no contention.
+   * Request access of the memory port.
    */
-  outb(SEEMS, SEECTL + base);
-  timeout = jiffies + 100;  /* 1 second timeout */
-  while ((jiffies < timeout) && ((inb(SEECTL + base) & SEERDY) == 0))
-  {
-    ; /* Do nothing!  Wait for access to be granted.  */
-  }
-  if ((inb(SEECTL + base) & SEERDY) == 0)
+  if (acquire_seeprom(p) == 0)
   {
-    outb(0, SEECTL + base);
     return (0);
   }
 
   /*
-   * Read the first 32 registers of the seeprom.  For the 7870,
-   * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
-   * but only the first 32 are used by Adaptec BIOS.  The loop
-   * will range from 0 to 31.
+   * Read 'len' registers of the seeprom.  For the 7870, the 93C46
+   * SEEPROM is a 1024-bit device with 64 16-bit registers but only
+   * the first 32 are used by Adaptec BIOS.  Some adapters use the
+   * 93C56 SEEPROM which is a 2048-bit device.  The loop will range
+   * from 0 to 'len' - 1.
    */
-  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  for (k = 0; k < len; k++)
   {
     /*
      * Send chip select for one clock cycle.
      */
-    outb(SEEMS | SEECK | SEECS, SEECTL + base);
-    CLOCK_PULSE(base);
+    outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+    CLOCK_PULSE(p);
 
     /*
      * Now we're ready to send the read command followed by the
@@ -3699,25 +4486,25 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
     }
     /*
-     * Send the 6 bit address (MSB first, LSB last).
+     * Send the 6 or 8 bit address (MSB first, LSB last).
      */
     for (i = ((int) chip - 1); i >= 0; i--)
     {
       temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
     }
 
     /*
@@ -3729,56 +4516,57 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
     for (i = 0; i <= 16; i++)
     {
       temp = SEEMS | SEECS;
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL + base) & SEEDI);
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
     }
 
     /*
-     * The serial EEPROM has a checksum in the last word.  Keep a
-     * running checksum for all words read except for the last
-     * word.  We'll verify the checksum after all words have been
-     * read.
+     * The serial EEPROM should have a checksum in the last word.
+     * Keep a running checksum for all words read except for the
+     * last word.  We'll verify the checksum after all words have
+     * been read.
      */
-    if (k < (sizeof(*sc) / 2) - 1)
+    if (k < (len - 1))
     {
-      checksum = checksum + seeprom[k];
+      checksum = checksum + scarray[k];
     }
 
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(SEEMS, SEECTL + base);
-    CLOCK_PULSE(base);
-    outb(SEEMS | SEECK, SEECTL + base);
-    CLOCK_PULSE(base);
-    outb(SEEMS, SEECTL + base);
-    CLOCK_PULSE(base);
+    outb(SEEMS, p->base + SEECTL);
+    CLOCK_PULSE(p);
+    outb(SEEMS | SEECK, p->base + SEECTL);
+    CLOCK_PULSE(p);
+    outb(SEEMS, p->base + SEECTL);
+    CLOCK_PULSE(p);
   }
 
   /*
    * Release access to the memory port and the serial EEPROM.
    */
-  outb(0, SEECTL + base);
+  release_seeprom(p);
 
 #if 0
-  printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+  printk("Computed checksum 0x%x, checksum read 0x%x\n",
+         checksum, scarray[len - 1]);
   printk("Serial EEPROM:");
-  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  for (k = 0; k < len; k++)
   {
     if (((k % 8) == 0) && (k != 0))
     {
       printk("\n              ");
     }
-    printk(" 0x%x", seeprom[k]);
+    printk(" 0x%x", scarray[k]);
   }
   printk("\n");
 #endif
 
-  if (checksum != sc->checksum)
+  if (checksum != scarray[len - 1])
   {
     return (0);
   }
@@ -3789,563 +4577,452 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
 
 /*+F*************************************************************************
  * Function:
- *   detect_maxscb
+ *   write_brdctl
  *
  * Description:
- *   Detects the maximum number of SCBs for the controller and returns
- *   the count and a mask in config (config->maxscbs, config->qcntmask).
+ *   Writes a value to the BRDCTL register.
  *-F*************************************************************************/
-static void
-detect_maxscb(struct aic7xxx_host_config *config)
+static inline void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
 {
-  unsigned char sblkctl_reg;
-  int base, i;
-
-#ifdef AIC7XXX_PAGE_ENABLE
-  config->flags |= PAGE_ENABLED;
-#endif
-  base = config->base;
-  switch (config->type)
-  {
-    case AIC_7770:
-    case AIC_7771:
-    case AIC_284x:
-      /*
-       * 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_reg = inb(SBLKCTL + base) ^ AUTOFLUSHDIS;
-      outb(sblkctl_reg, SBLKCTL + base);
-      if (inb(SBLKCTL + base) == sblkctl_reg)
-      {
-        /*
-         * We detected a Rev E board, we allow paging on this board.
-         */
-        printk(KERN_INFO "aic7xxx: %s Rev E and subsequent.\n",
-               board_names[config->type]);
-       outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base);
-      }
-      else
-      {
-        /* Do not allow paging. */
-        config->flags &= ~PAGE_ENABLED;
-        printk(KERN_INFO "aic7xxx: %s Rev C and previous.\n",
-               board_names[config->type]);
-      }
-      break;
-
-    default:
-      break;
-  }
-
-  /*
-   * Walk the SCBs to determine how many there are.
-   */
-  i = 1;
-  outb(0, SCBPTR + base);
-  outb(0, SCBARRAY + base);
-
-  while (i < AIC7XXX_MAXSCB)
-  {
-    outb(i, SCBPTR + base);
-    outb(i, SCBARRAY + base);
-    if (inb(SCBARRAY + base) != i)
-      break;
-    outb(0, SCBPTR + base);
-    if (inb(SCBARRAY + base) != 0)
-      break;
-
-    outb(i, SCBPTR + base);      /* Clear the control byte. */
-    outb(0, SCBARRAY + base);
-
-    config->qcntmask |= i;       /* Update the count mask. */
-    i++;
-  }
-  outb(i, SCBPTR + base);   /* Ensure we clear the control bytes. */
-  outb(0, SCBARRAY + base);
-  outb(0, SCBPTR + base); 
-  outb(0, SCBARRAY + base);
-
-  config->maxhscbs = i;
-  config->qcntmask |= i;
-  if ((config->flags & PAGE_ENABLED) && (config->maxhscbs < AIC7XXX_MAXSCB))
-  {
-    config->maxscbs = AIC7XXX_MAXSCB;
-  }
-  else
-  {
-    config->flags &= ~PAGE_ENABLED;  /* Disable paging if we have 255 SCBs!. */
-    config->maxscbs = config->maxhscbs;
-  }
-
-  printk(KERN_INFO "aic7xxx: Memory check yields %d SCBs", config->maxhscbs);
-  if (config->flags & PAGE_ENABLED)
-    printk(", %d page-enabled SCBs.\n", config->maxscbs);
-  else
-    printk(", paging not enabled.\n");
-
+  unsigned char brdctl;
+
+  brdctl = BRDCS | BRDSTB;
+  outb(brdctl, p->base + BRDCTL);
+  brdctl |= value;
+  outb(brdctl, p->base + BRDCTL);
+  brdctl &= ~BRDSTB;
+  outb(brdctl, p->base + BRDCTL);
+  brdctl &= ~BRDCS;
+  outb(brdctl, p->base + BRDCTL);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_register
+ *   read_brdctl
  *
  * Description:
- *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *   Reads the BRDCTL register.
  *-F*************************************************************************/
-static int
-aic7xxx_register(Scsi_Host_Template *template,
-    struct aic7xxx_host_config *config)
+static inline unsigned char
+read_brdctl(struct aic7xxx_host *p)
 {
-  int i;
-  unsigned char sblkctl, flags = 0;
-  int max_targets;
-  int found = 1;
-  unsigned int sram, base;
-  unsigned char target_settings;
-  unsigned char scsi_conf, host_conf;
-  unsigned short ultraenable = 0;
-  int have_seeprom = FALSE;
-  struct Scsi_Host *host;
-  struct aic7xxx_host *p;
-  struct seeprom_config sc;
-
-  base = config->base;
-
-  /*
-   * Lock out other contenders for our i/o space.
-   */
-  request_region(base, MAXREG - MINREG, "aic7xxx");
+  outb(BRDRW | BRDCS, p->base + BRDCTL);
+  return (inb(p->base + BRDCTL));
+}
 
-  switch (config->type)
+/*+F*************************************************************************
+ * Function:
+ *   configure_termination
+ *
+ * Description:
+ *   Configures the termination settings on PCI adapters that have
+ *   SEEPROMs available.
+ *-F*************************************************************************/
+static void
+configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
+    unsigned short adapter_control, unsigned char max_targ)
+{
+  unsigned char brdctl_int, brdctl_ext;
+  int internal50_present;
+  int internal68_present = 0;
+  int external_present = 0;
+  int eprom_present;
+  int high_on;
+  int low_on;
+  int old_verbose;
+
+  if (acquire_seeprom(p))
   {
-    case AIC_7770:
-    case AIC_7771:
-      /*
-       * Use the boot-time option for the interrupt trigger type.  If not
-       * supplied (-1), then we use BIOS settings to determine the interrupt
-       * trigger type (level or edge) and use this value for pausing and
-       * unpausing the sequencer.
-       */
-      switch (aic7xxx_irq_trigger)
-      {
-        case  0: config->unpause = INTEN;          /* Edge */
-                 break;
-        case  1: config->unpause = IRQMS | INTEN;  /* Level */
-                 break;
-        case -1:
-        default: config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN; 
-                 break;
-      }
-      config->pause = config->unpause | PAUSE;
+    if (adapter_control & CFAUTOTERM)
+    {
+      old_verbose = aic7xxx_verbose;
+      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination.  Please "
+                       "verify driver");
+      printk(KERN_INFO "         detected settings and use manual termination "
+                       "if necessary."); 
+
+      /* Configure auto termination. */
+      outb(SEECS | SEEMS, p->base + SEECTL);
 
       /*
-       * For some 274x boards, we must clear the CHIPRST bit and pause
-       * the sequencer. For some reason, this makes the driver work.
-       * For 284x boards, we give it a CHIPRST just like the 294x boards.
+       * 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.
        */
-      outb(config->pause | CHIPRST, HCNTRL + base);
-      aic7xxx_delay(1);
-      if (inb(HCNTRL + base) & CHIPRST)
-      {
-       printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
-      }
-      outb(config->pause, HCNTRL + base);
+      write_brdctl(p, 0);
 
       /*
-       * Just to be on the safe side with the 274x, we will re-read the irq
-       * since there was some issue about resetting the board.
+       * 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).
        */
-      config->irq = inb(INTDEF + base) & 0x0F;
-      if ((config->type == AIC_7771) &&
-          (inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
-      {
-        config->bios = AIC_DISABLED;
-        config->flags |= USE_DEFAULTS;
-      }
-      else
+      brdctl_int = read_brdctl(p);
+      internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
+      if (max_targ > 8)
       {
-        host_conf = inb(HOSTCONF + base);
-        config->bus_speed = host_conf & DFTHRSH;
-        config->busrtime = (host_conf << 2) & BOFF;
+        internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
       }
 
       /*
-       * Setup the FIFO threshold and the bus off time
+       * Set the rom bank to 1 and determine
+       * the other signals.
        */
-      outb(config->bus_speed & DFTHRSH, BUSSPD + base);
-      outb(config->busrtime, BUSTIME + base);
+      write_brdctl(p, BRDDAT5);
 
       /*
-       * A reminder until this can be detected automatically.
+       * 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.
        */
-      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-            (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-      break;
-
-    case AIC_284x:
-      outb(CHIPRST, HCNTRL + base);
-      config->unpause = UNPAUSE_284X;
-      config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
-      aic7xxx_delay(1);
-      outb(config->pause, HCNTRL + base);
-
-      config->parity = AIC_ENABLED;
-      config->irq = inb(INTDEF + base) & 0x0F;
-      host_conf = inb(HOSTCONF + base);
-
-      printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
-      have_seeprom = read_2840_seeprom(base, &sc);
-      if (!have_seeprom)
+      brdctl_ext = read_brdctl(p);
+      external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
+      eprom_present = brdctl_ext & BRDDAT7;
+      if (aic7xxx_verbose)
       {
-       printk("aic7xxx: Unable to read SEEPROM.\n");
-      }
-      else
-      {
-       printk("done.\n");
-        config->flags |= HAVE_SEEPROM;
-        if (sc.bios_control & CF284XEXTEND)
-          config->flags |= EXTENDED_TRANSLATION;
-        if (!(sc.bios_control & CFBIOSEN))
+        if (max_targ > 8)
         {
-          /*
-           * The BIOS is disabled; the values left over in scratch
-           * RAM are still valid.  Do not use defaults as in the
-           * AIC-7770 case.
-           */
-          config->bios = AIC_DISABLED;
+          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
         {
-         config->parity = (sc.adapter_control & CFSPARITY) ?
-                          AIC_ENABLED : AIC_DISABLED;
-         config->low_term = (sc.adapter_control & CF284XSTERM) ?
-                               AIC_ENABLED : AIC_DISABLED;
-         /*
-          * XXX - Adaptec *does* make 284x wide controllers, but the
-          *       documents do not say where the high byte termination
-          *       enable bit is located.
-           */
+          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);
       }
 
-      host_conf = inb(HOSTCONF + base);
-      config->bus_speed = host_conf & DFTHRSH;
-      config->busrtime = (host_conf << 2) & BOFF;
-
-      /*
-       * Setup the FIFO threshold and the bus off time
-       */
-      outb(config->bus_speed & DFTHRSH, BUSSPD + base);
-      outb(config->busrtime, BUSTIME + base);
-
-      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-            (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-      break;
-
-    case AIC_7860:
-    case AIC_7861:
-    case AIC_7880:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7883:
-    case AIC_7884:
-      /*
-       * Remember if Ultra was enabled in case there is no SEEPROM.
-       * Fall through to the rest of the AIC_78xx code.
-       */
-      if ((inb(SXFRCTL0 + base) & ULTRAEN) || aic7xxx_enable_ultra)
-        config->flags |= ULTRA_ENABLED;
-
-    case AIC_7850:
-    case AIC_7855:
-    case AIC_7870:
-    case AIC_7871:
-    case AIC_7872:
-    case AIC_7873:
-    case AIC_7874:
       /*
-       * Grab the SCSI ID before chip reset in case there is no SEEPROM.
+       * Now set the termination based on what we found.  BRDDAT6
+       * controls wide termination enable.
        */
-      config->scsi_id = inb(SCSIID + base) & OID;
-      outb(CHIPRST, HCNTRL + base);
-      config->unpause = UNPAUSE_294X;
-      config->pause = config->unpause | PAUSE;
-      aic7xxx_delay(1);
-      outb(config->pause, HCNTRL + base);
-
-      config->parity = AIC_ENABLED;
+      high_on = FALSE;
+      low_on = FALSE;
+      if ((max_targ > 8) &&
+          ((external_present == 0) || (internal68_present == 0)))
+      {
+        high_on = TRUE;
+      }
 
-      printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
-      if ((config->type == AIC_7873) || (config->type == AIC_7883))
+      if ((internal50_present + internal68_present + external_present) <= 1)
       {
-        have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
-                                    &sc, c56_66);
+        low_on = TRUE;
       }
-      else
+          
+      if (internal50_present && internal68_present && external_present)
       {
-        have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
-                                    &sc, c46);
+        printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
+               "         Only two connectors on the adapter may be "
+               "used at a time!\n");
       }
-      if (!have_seeprom)
+
+      if (high_on == TRUE)
+        write_brdctl(p, BRDDAT6);
+      else
+        write_brdctl(p, 0);
+
+      if (low_on == TRUE)
+        *sxfrctl1 |= STPWEN;
+
+      if (aic7xxx_verbose)
       {
-        for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
+        if (max_targ > 8)
         {
-          if (inb(sram) != 0x00)
-            break;
-        }
-        if (sram == base + TARG_SCRATCH)
-        {
-          for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
-          {
-            if (inb(sram) != 0xFF)
-              break;
-          }
-        }
-        if ((sram != base + 0x60) && (config->scsi_id != 0))
-        {
-          config->flags &= ~USE_DEFAULTS;
-         printk("\naic7xxx: Unable to read SEEPROM; "
-                 "using leftover BIOS values.\n");
+          printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+                 low_on ? "ON" : "OFF",
+                 high_on ? "ON" : "OFF");
         }
         else
         {
-          printk("\n");
-          printk(KERN_INFO "aic7xxx: Unable to read SEEPROM; using default "
-                 "settings.\n");
-          config->flags |= USE_DEFAULTS;
-          config->flags &= ~ULTRA_ENABLED;
-          config->scsi_id = 7;
+          printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
         }
-        scsi_conf = ENSPCHK | RESET_SCSI;
+      }
+      aic7xxx_verbose = old_verbose;
+    }
+    else
+    {
+      if (adapter_control & CFSTERM)
+      {
+        *sxfrctl1 |= STPWEN;
+      }
+      outb(SEEMS | SEECS, p->base + SEECTL);
+      /*
+       * Configure high byte termination.
+       */
+      if (adapter_control & CFWSTERM)
+      {
+        write_brdctl(p, BRDDAT6);
       }
       else
       {
-       printk("done.\n");
-        config->flags |= HAVE_SEEPROM;
-        if (!(sc.bios_control & CFBIOSEN))
-        {
-          /*
-           * The BIOS is disabled; the values left over in scratch
-           * RAM are still valid.  Do not use defaults as in the
-           * AIC-7770 case.
-           */
-          config->bios = AIC_DISABLED;
-          scsi_conf = ENSPCHK | RESET_SCSI;
-        }
-        else
-        {
-          scsi_conf = 0;
-          if (sc.adapter_control & CFRESETB)
-            scsi_conf |= RESET_SCSI;
-          if (sc.adapter_control & CFSPARITY)
-            scsi_conf |= ENSPCHK;
-         if (sc.bios_control & CFEXTEND)
-            config->flags |= EXTENDED_TRANSLATION;
-         config->scsi_id = (sc.brtime_id & CFSCSIID);
-         config->parity = (sc.adapter_control & CFSPARITY) ?
-                            AIC_ENABLED : AIC_DISABLED;
-         config->low_term = (sc.adapter_control & CFSTERM) ?
-                              AIC_ENABLED : AIC_DISABLED;
-         config->high_term = (sc.adapter_control & CFWSTERM) ?
-                               AIC_ENABLED : AIC_DISABLED;
-         config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
-          if (((config->type == AIC_7880) || (config->type == AIC_7881) ||
-               (config->type == AIC_7882) || (config->type == AIC_7883) ||
-               (config->type == AIC_7884)) && (sc.adapter_control & CFULTRAEN))
-          {
-            printk(KERN_INFO "aic7xxx: Enabling support for Ultra SCSI "
-                   "speed.\n");
-            config->flags |= ULTRA_ENABLED;
-          }
-        }
+        write_brdctl(p, 0);
+      }
+      if (aic7xxx_verbose)
+      {
+        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+               (adapter_control & CFSTERM) ? "ON" : "OFF",
+               (adapter_control & CFWSTERM) ? "ON" : "OFF");
       }
+    }
+    release_seeprom(p);
+  }
+}
 
-      outb(scsi_conf | (config->scsi_id & 0x07), SCSICONF + base);
-      config->bus_speed = DFTHRSH_100;
-      outb(config->bus_speed, DSPCISTATUS + base);
+/*+F*************************************************************************
+ * Function:
+ *   detect_maxscb
+ *
+ * Description:
+ *   Detects the maximum number of SCBs for the controller and returns
+ *   the count and a mask in p (p->maxscbs, p->qcntmask).
+ *-F*************************************************************************/
+static void
+detect_maxscb(struct aic7xxx_host *p)
+{
+  int i;
+  unsigned char max_scbid = 255;
 
-      /*
-       * In case we are a wide card...
-       */
-      outb(config->scsi_id, SCSICONF + base + 1);
+  /*
+   * It's possible that we've already done this for multichannel
+   * adapters.
+   */
+  if (p->scb_data->maxhscbs == 0)
+  {
+    /*
+     * We haven't initialized the SCB settings yet.  Walk the SCBs to
+     * determince how many there are.
+     */
+    outb(0, p->base + FREE_SCBH);
 
-      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-            (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-      break;
+    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)
+        break;
+      outb(0, p->base + SCBPTR);
+      if (inb(p->base + SCB_CONTROL) != 0)
+        break;
 
-    default:
-      panic(KERN_WARNING "aic7xxx: (aic7xxx_register) Internal error.\n");
+      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);
+    }
+
+    /* Make sure the last SCB terminates the free list. */
+    outb(i - 1, p->base + SCBPTR);
+    outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+
+    /* Ensure we clear the first (0) SCBs control byte. */
+    outb(0, p->base + SCBPTR);
+    outb(0, p->base + 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;
   }
+}
 
-  detect_maxscb(config);
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_register
+ *
+ * Description:
+ *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+{
+  int i;
+  unsigned char sblkctl, flags = 0;
+  int max_targets;
+  int found = 1;
+  char channel_ids[] = {'A', 'B', 'C'};
+  unsigned char target_settings;
+  unsigned char scsi_conf, sxfrctl1;
+  unsigned short ultraenable = 0;
+  struct Scsi_Host *host;
 
-  if (config->chip_type == AIC_777x)
-  {
-    if (config->pause & IRQMS)
-    {
-      printk(KERN_INFO "aic7xxx: Using level sensitive interrupts.\n");
-    }
-    else
-    {
-      printk(KERN_INFO "aic7xxx: Using edge triggered interrupts.\n");
-    }
-  }
+  /*
+   * Lock out other contenders for our i/o space.
+   */
+  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(SBLKCTL + base);
-  if (config->flags & PAGE_ENABLED)
+  sblkctl = inb(p->base + SBLKCTL);
+  if (p->flags & PAGE_ENABLED)
     flags = PAGESCBS;
 
   switch (sblkctl & SELBUS_MASK)
   {
     case SELNARROW:     /* narrow/normal bus */
-      config->scsi_id = inb(SCSICONF + base) & 0x07;
-      config->bus_type = AIC_SINGLE;
-      outb(flags | SINGLE_BUS, FLAGS + base);
+      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 */
-      config->scsi_id = inb(SCSICONF + base + 1) & 0x0F;
-      config->bus_type = AIC_WIDE;
-      printk("aic7xxx: Enabling wide channel of %s-Wide.\n",
-            board_names[config->type]);
-      outb(flags | WIDE_BUS, FLAGS + base);
+      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 */
-      config->scsi_id = inb(SCSICONF + base) & 0x07;
-#ifdef AIC7XXX_TWIN_SUPPORT
-      config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07;
-      config->bus_type = AIC_TWIN;
-      printk(KERN_INFO "aic7xxx: Enabled channel B of %s-Twin.\n",
-            board_names[config->type]);
-      outb(flags | TWIN_BUS, FLAGS + base);
-#else
-      config->bus_type = AIC_SINGLE;
-      printk(KERN_INFO "aic7xxx: Channel B of %s-Twin will be ignored.\n",
-            board_names[config->type]);
-      outb(flags, FLAGS + base);
-#endif
+      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(SBLKCTL + base));
-      outb(0, FLAGS + base);
+            "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
+      outb(0, p->base + SEQ_FLAGS);
       return (0);
   }
 
   /*
-   * For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
-   * take the card out of diagnostic mode and make the host adapter
-   * LED follow bus activity (will not always be on).
-   */
-  outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL + base);
-
-  /*
-   * The IRQ level in i/o port 4 maps directly onto the real
-   * IRQ number. If it's ok, register it with the kernel.
-   *
-   * NB. the Adaptec documentation says the IRQ number is only
-   *     in the lower four bits; the ECU information shows the
-   *     high bit being used as well. Which is correct?
-   *
-   * The PCI cards get their interrupt from PCI BIOS.
+   * Detect SCB parameters and initialize the SCB array.
    */
-  if ((config->chip_type == AIC_777x) && ((config->irq < 9) || (config->irq > 15)))
-  {
-    printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ level, "
-          "ignoring.\n");
-    return (0);
-  }
+  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);
 
-  /*
-   * Print out debugging information before re-enabling
-   * the card - a lot of registers on it can't be read
-   * when the sequencer is active.
-   */
-  debug_config(config);
+  host = p->host;
 
-  /*
-   * Register each "host" and fill in the returned Scsi_Host
-   * structure as best we can. Some of the parameters aren't
-   * really relevant for bus types beyond ISA, and none of the
-   * high-level SCSI code looks at it anyway. Why are the fields
-   * there? Also save the pointer so that we can find the
-   * information when an IRQ is triggered.
-   */
-  host = scsi_register(template, sizeof(struct aic7xxx_host));
-  host->can_queue = config->maxscbs;
+  host->can_queue = p->scb_data->maxscbs;
   host->cmd_per_lun = 2;
+  host->sg_tablesize = AIC7XXX_MAX_SG;
   host->select_queue_depths = aic7xxx_select_queue_depth;
-  host->this_id = config->scsi_id;
-  host->io_port = config->base;
+  host->this_id = p->scsi_id;
+  host->io_port = p->base;
   host->n_io_port = 0xFF;
-  host->base = (unsigned char *)config->mbase;
-  host->irq = config->irq;
-  if (config->bus_type == AIC_WIDE)
+  host->base = (unsigned char *) p->mbase;
+  host->irq = p->irq;
+  if (p->bus_type == AIC_WIDE)
   {
     host->max_id = 16;
   }
-  if (config->bus_type == AIC_TWIN)
+  if (p->bus_type == AIC_TWIN)
   {
     host->max_channel = 1;
   }
 
-  p = (struct aic7xxx_host *) host->hostdata;
-
   p->host = host;
-  p->host_no = (int)host->host_no;
+  p->host_no = host->host_no;
   p->isr_count = 0;
-  p->base = base;
-  p->maxscbs = config->maxscbs;
-  p->maxhscbs = config->maxhscbs;
-  p->qcntmask = config->qcntmask;
-  p->mbase = (char *)config->mbase;
-  p->type = config->type;
-  p->chip_type = config->chip_type;
-  p->flags = config->flags;
-  p->chan_num = config->chan_num;
-  p->scb_link = &(p->scb_usage);
-#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS)
-  if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
-  {
-    shared_3985_scbs = &(p->scb_usage);
-    p->scb_link = &(p->scb_usage);
-  }
-#endif
-  p->scb_link->numscbs = 0;
-  p->bus_type = config->bus_type;
-  p->seeprom = sc;
   p->next = NULL;
   p->completeq.head = NULL;
   p->completeq.tail = NULL;
-  scbq_init(&p->scb_link->free_scbs);
-  scbq_init(&p->page_scbs);
+  scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
-  scbq_init(&p->assigned_scbs);
-
-  p->unpause = config->unpause;
-  p->pause = config->pause;
 
-  for (i = 0; i <= 15; i++)
+  for (i = 0; i <= NUMBER(p->device_status); 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;
   }
-  if (aic7xxx_boards[config->irq] == NULL)
+  if (aic7xxx_boards[p->irq] == NULL)
   {
+    int result;
+    int irq_flags = 0;
+
+#ifdef AIC7XXX_OLD_ISR_TYPE
+    irg_flags = SA_INTERRUPT;
+#endif
     /*
      * Warning! This must be done before requesting the irq.  It is
      * possible for some boards to raise an interrupt as soon as
@@ -4353,17 +5030,26 @@ aic7xxx_register(Scsi_Host_Template *template,
      * kernel, an interrupt is triggered immediately.  Therefore, we
      * must ensure the board data is correctly set before the request.
      */
-    aic7xxx_boards[config->irq] = host;
+    aic7xxx_boards[p->irq] = host;
 
     /*
-     * Register IRQ with the kernel.
+     * Register IRQ with the kernel.  Only allow sharing IRQs with
+     * PCI devices.
      */
-    if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
-       "aic7xxx", NULL))
+    if (p->chip_class == AIC_777x)
+    {
+      result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
+    }
+    else
+    {
+      result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
+                "aic7xxx", NULL));
+    }
+    if (result < 0)
     {
       printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
-             config->irq);
-      aic7xxx_boards[config->irq] = NULL;
+             p->irq);
+      aic7xxx_boards[p->irq] = NULL;
       return (0);
     }
   }
@@ -4374,79 +5060,74 @@ aic7xxx_register(Scsi_Host_Template *template,
      * registered host adapter. Add this host adapter's Scsi_Host
      * to the beginning of the linked list of hosts at the same IRQ.
      */
-    p->next = aic7xxx_boards[config->irq];
-    aic7xxx_boards[config->irq] = host;
-  }
-
-  /*
-   * Load the sequencer program, then re-enable the board -
-   * resetting the AIC-7770 disables it, leaving the lights
-   * on with nobody home. On the PCI bus you *may* be home,
-   * but then your mailing address is dynamically assigned
-   * so no one can find you anyway :-)
-   */
-  printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
-  aic7xxx_loadseq(base);
-
-  /*
-   * Set Fast Mode and Enable the board
-   */
-  outb(FASTMODE, SEQCTL + base);
-
-  if (p->chip_type == AIC_777x)
-  {
-    outb(ENABLE, BCTL + base);
+    p->next = aic7xxx_boards[p->irq];
+    aic7xxx_boards[p->irq] = host;
   }
 
-  printk("done.\n");
-
   /*
    * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
    */
   if (p->bus_type == AIC_TWIN)
   {
     /*
-     * Select Channel B.
+     * The controller is gated to channel B after a chip reset; set
+     * bus B values first.
      */
-    outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
-
-    outb(config->scsi_id_b, SCSIID + base);
-    scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
-    outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
-    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
-    outb(ENSELTIMO, SIMODE1 + base);
-#endif
+    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)
     {
-      outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+      outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
     }
     else
     {
-      outb(DFON | SPIOEN, SXFRCTL0 + base);
+      outb(DFON | SPIOEN, p->base + SXFRCTL0);
     }
 
-    /*
-     * Select Channel A
-     */
-    outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+    if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+    {
+      /* Reset SCSI bus B. */
+      if (aic7xxx_verbose)
+        printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+
+      aic7xxx_reset_current_bus(p);
+    }
+
+    /* Select channel A */
+    outb(SELNARROW, p->base + SBLKCTL);
   }
-  outb(config->scsi_id, SCSIID + base);
-  scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
-  outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
-  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
-  outb(ENSELTIMO, SIMODE1 + base);
-#endif
+
+  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)
   {
-    outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+    outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
   }
   else
   {
-    outb(DFON | SPIOEN, SXFRCTL0 + base);
+    outb(DFON | SPIOEN, p->base + SXFRCTL0);
+  }
+
+  if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+  {
+    /* Reset SCSI bus A. */
+    if (aic7xxx_verbose)
+      printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+
+    aic7xxx_reset_current_bus(p);
+
+    /*
+     * Delay for the reset delay.
+     */
+    aic7xxx_delay(AIC7XXX_RESET_DELAY);
   }
 
   /*
@@ -4473,67 +5154,47 @@ aic7xxx_register(Scsi_Host_Template *template,
   /*
    * Grab the disconnection disable table and invert it for our needs
    */
-  if (have_seeprom)
+  if (p->flags & USE_DEFAULTS)
   {
-    p->discenable = 0x0;
+    printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
+           "device parameters.\n");
+    p->discenable = 0xFFFF;
   }
   else
   {
-    if (config->bios == AIC_DISABLED)
-    {
-      printk(KERN_INFO "aic7xxx : Host adapter BIOS disabled. Using default SCSI "
-             "device parameters.\n");
-      p->discenable = 0xFFFF;
-    }
-    else
-    {
-      p->discenable = ~((inb(DISC_DSB + base + 1) << 8) |
-          inb(DISC_DSB + base));
-    }
+    p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
+        inb(p->base + DISC_DSB));
   }
 
   for (i = 0; i < max_targets; i++)
   {
-    if (config->flags & USE_DEFAULTS)
+    if (p->flags & USE_DEFAULTS)
     {
-      target_settings = 0;  /* 10 MHz */
+      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))
+        ultraenable |= (0x01 << i);
     }
     else
     {
-      if (have_seeprom)
+      target_settings = inb(p->base + TARG_SCRATCH + i);
+      if (target_settings & 0x0F)
       {
-       target_settings = ((sc.device_flags[i] & CFXFER) << 4);
-       if (sc.device_flags[i] & CFSYNCH)
-       {
-         p->needsdtr_copy |= (0x01 << i);
-       }
-       if (sc.device_flags[i] & CFWIDEB)
-       {
-         p->needwdtr_copy |= (0x01 << i);
-       }
-       if (sc.device_flags[i] & CFDISC)
-        {
-          p->discenable |= (0x01 << i);
-        }
+        p->needsdtr_copy |= (0x01 << i);
+        /*
+         * Default to asynchronous transfers (0 offset)
+         */
+        target_settings &= 0xF0;
       }
-      else
+      if (target_settings & 0x80)
       {
-        target_settings = inb(TARG_SCRATCH + base + i);
-        if (target_settings & 0x0F)
-        {
-          p->needsdtr_copy |= (0x01 << i);
-          /*
-           * Default to asynchronous transfers (0 offset)
-           */
-          target_settings &= 0xF0;
-        }
-        if (target_settings & 0x80)
-        {
-          p->needwdtr_copy |= (0x01 << i);
-          target_settings &= 0x7F;
-        }
+        p->needwdtr_copy |= (0x01 << i);
+        /*
+         * Clear the wide flag. When wide negotiation is successful,
+         * we'll enable it.
+         */
+        target_settings &= 0x7F;
       }
       if (p->flags & ULTRA_ENABLED)
       {
@@ -4544,7 +5205,7 @@ aic7xxx_register(Scsi_Host_Template *template,
           case 0x20:
             ultraenable |= (0x01 << i);
             break;
-          case 0x40:
+          case 0x40:  /* treat 10MHz as 10MHz without Ultra enabled */
             target_settings &= ~(0x70);
             break;
           default:
@@ -4552,7 +5213,7 @@ aic7xxx_register(Scsi_Host_Template *template,
         }
       }
     }
-    outb(target_settings, (TARG_SCRATCH + base + i));
+    outb(target_settings, p->base + TARG_SCRATCH + i);
   }
 
   /*
@@ -4567,103 +5228,448 @@ aic7xxx_register(Scsi_Host_Template *template,
   p->needsdtr = p->needsdtr_copy;
   p->needwdtr = p->needwdtr_copy;
   p->orderedtag = 0;
-#if 0
-  printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr);
-  printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr);
-#endif
-  outb(ultraenable & 0xFF, ULTRA_ENB + base);
-  outb((ultraenable >> 8) & 0xFF, ULTRA_ENB + base + 1);
+  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);
+
+  /*
+   * Allocate enough hardware scbs to handle the maximum number of
+   * concurrent transactions we can have.  We have to make sure that
+   * the allocated memory is contiguous memory.  The Linux kmalloc
+   * routine should only allocate contiguous memory, but note that
+   * this could be a problem if kmalloc() is changed.
+   */
+  if (p->scb_data->hscbs == NULL)
+  {
+    size_t array_size;
+    unsigned int hscb_physaddr;
+
+    array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
+    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");
+      release_region(p->base, MAXREG - MINREG);
+      /*
+       * Ensure that we only free the IRQ when there is _not_ another
+       * aic7xxx adapter sharing this IRQ.  The adapters are always
+       * added to the beginning of the list, so we can grab the next
+       * pointer and place it back in the board array.
+       */
+      if (p->next == NULL)
+      {
+        free_irq(p->irq, aic7xxx_isr);
+      }
+      aic7xxx_boards[p->irq] = p->next;
+      return(0);
+    }
+    /* At least the control byte of each SCB needs to be 0. */
+    memset(p->scb_data->hscbs, 0, array_size);
+
+    /* 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);
+
+  /*
+   * 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);
+
+  /*
+   * Message out buffer starts empty
+   */
+  outb(0, p->base + MSG_LEN);
+
+  /*
+   * Load the sequencer program, then re-enable the board -
+   * resetting the AIC-7770 disables it, leaving the lights
+   * on with nobody home. On the PCI bus you *may* be home,
+   * but then your mailing address is dynamically assigned
+   * so no one can find you anyway :-)
+   */
+  aic7xxx_loadseq(p);
+
+  if (p->chip_class == AIC_777x)
+  {
+    outb(ENABLE, p->base + BCTL);  /* Enable the boards BUS drivers. */
+  }
+
+  /*
+   * 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);
+
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_chip_reset
+ *
+ * Description:
+ *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
+ *   is paused upon return.
+ *-F*************************************************************************/
+static void
+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;
+
+  /*
+   * 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);
+
+  /*
+   * 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))
+  {
+    udelay(1000);  /* 1 msec = 1000 usec */
+    wait = wait - 1;
+  }
+
+  if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+  {
+    printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
+  }
+
+  outb(hcntrl | PAUSE, p->base + HCNTRL);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_alloc
+ *
+ * Description:
+ *   Allocate and initialize a host structure.  Returns NULL upon error
+ *   and a pointer to a aic7xxx_host struct upon success.
+ *-F*************************************************************************/
+static struct aic7xxx_host *
+aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
+    aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+{
+  struct aic7xxx_host *p = NULL;
+  struct Scsi_Host *host;
+
+  /*
+   * Allocate a storage area by registering us with the mid-level
+   * SCSI layer.
+   */
+  host = scsi_register(sht, sizeof(struct aic7xxx_host));
+
+  if (host != NULL)
+  {
+    p = (struct aic7xxx_host *) host->hostdata;
+    memset(p, 0, sizeof(struct aic7xxx_host));
+    p->host = host;
+
+    if (scb_data != NULL)
+    {
+      /*
+       * We are sharing SCB data areas; use the SCB data pointer
+       * provided.
+       */
+      p->scb_data = scb_data;
+      p->flags |= SHARED_SCBDATA;
+    }
+    else
+    {
+      /*
+       * We are not sharing SCB data; allocate one.
+       */
+      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;
+      }
+    }
+    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;
+    }
+  }
+  return (p);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_free
+ *
+ * Description:
+ *   Frees and releases all resources associated with an instance of
+ *   the driver (struct aic7xxx_host *).
+ *-F*************************************************************************/
+static void
+aic7xxx_free (struct aic7xxx_host *p)
+{
+  int i;
+
+  /*
+   * 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.
+   */
+  if (!(p->flags & SHARED_SCBDATA))
+  {
+    /*
+     * 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);
+  }
   /*
-   * Set the number of available SCBs.
+   * Free the instance of the device structure.
    */
-  outb(config->maxhscbs, SCBCOUNT + base);
+  scsi_unregister(p->host);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_load_seeprom
+ *
+ * Description:
+ *   Load the seeprom and configure adapter and target settings.
+ *   Returns 1 if the load was successful and 0 otherwise.
+ *-F*************************************************************************/
+static int
+load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
+{
+  int have_seeprom = 0;
+  int i, max_targets;
+  unsigned char target_settings, scsi_conf;
+  unsigned short scarray[128];
+  struct seeprom_config *sc = (struct seeprom_config *) scarray;
+
+  if (aic7xxx_verbose)
+  {
+    printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
+  }
+  switch (p->chip_type)
+  {
+    case AIC_7770:  /* None of these adapters have seeproms. */
+    case AIC_7771:
+    case AIC_7850:
+    case AIC_7855:
+      break;
 
-  /*
-   * 2s compliment of maximum tag value.
-   */
-  i = p->maxscbs;
-  outb(-i & 0xFF, COMP_SCBCOUNT + base);
+    case AIC_284x:
+      have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
+      break;
 
-  /*
-   * Set the QCNT (queue count) mask to deal with broken aic7850s that
-   * sporatically get garbage in the upper bits of their QCNT registers.
-   */
-  outb(config->qcntmask, QCNTMASK + base);
+    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),
+                                  scarray, sizeof(*sc)/2, C46);
+      break;
 
-  /*
-   * Clear the active flags - no targets are busy.
-   */
-  outb(0, ACTIVE_A + base);
-  outb(0, ACTIVE_B + base);
+    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;
 
-  /*
-   * We don't have any waiting selections or disconnected SCBs.
-   */
-  outb(SCB_LIST_NULL, WAITING_SCBH + base);
-  outb(SCB_LIST_NULL, DISCONNECTED_SCBH + base);
+    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),
+                                  scarray, sizeof(scarray)/2, C56_66);
+      break;
 
-  /*
-   * Message out buffer starts empty
-   */
-  outb(0, MSG_LEN + base);
+    default:
+      break;
+  }
 
-  /*
-   * Reset the SCSI bus. Is this necessary?
-   *   There may be problems for a warm boot without resetting
-   *   the SCSI bus. Either BIOS settings in scratch RAM
-   *   will not get reinitialized, or devices may stay at
-   *   previous negotiated settings (SDTR and WDTR) while
-   *   the driver will think that no negotiations have been
-   *   performed.
-   *
-   * Some devices need a long time to "settle" after a SCSI
-   * bus reset.
-   */
-  if (!aic7xxx_no_reset)
+  if (!have_seeprom)
+  {
+    if (aic7xxx_verbose)
+    {
+      printk("\naic7xxx: No SEEPROM available; using defaults.\n");
+    }
+    p->flags |= USE_DEFAULTS;
+  }
+  else
   {
-    printk("aic7xxx: Resetting the SCSI bus...");
-    if (p->bus_type == AIC_TWIN)
+    if (aic7xxx_verbose)
+    {
+      printk("done\n");
+    }
+    p->flags |= HAVE_SEEPROM;
+
+    /*
+     * Update the settings in sxfrctl1 to match the termination settings.
+     */
+    *sxfrctl1 = 0;
+
+    /*
+     * First process the settings that are different between the VLB
+     * and PCI adapter seeproms.
+     */
+    if (p->chip_class == AIC_777x)
     {
+      /* VLB adapter seeproms */
+      if (sc->bios_control & CF284XEXTEND)
+        p->flags |= EXTENDED_TRANSLATION;
+
+      if (sc->adapter_control & CF284XSTERM)
+        *sxfrctl1 |= STPWEN;
       /*
-       * Select Channel B.
+       * 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
+       * adapters.  For narrow adapters, going through the extra
+       * 8 target entries will not cause any harm since they will
+       * will not be used.
+       *
+       * XXX - We should probably break out the bus detection
+       *       from the register function so we can use it here
+       *       to tell us how many targets there really are.
        */
-      outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
+      max_targets = 16;
+    }
+    else
+    {
+      /* PCI adapter seeproms */
+      if (sc->bios_control & CFEXTEND)
+        p->flags |= EXTENDED_TRANSLATION;
 
-      outb(SCSIRSTO, SCSISEQ + base);
-      udelay(1000);
-      outb(0, SCSISEQ + base);
+      if (sc->adapter_control & CFSTERM)
+        *sxfrctl1 |= STPWEN;
 
-      /* Ensure we don't get a RSTI interrupt from this. */
-      outb(CLRSCSIRSTI, CLRSINT1 + base);
-      outb(CLRSCSIINT, CLRINT + base);
+      /* Limit to 16 targets just in case. */
+      max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
+    }
 
-     /*
-       * Select Channel A.
-       */
-      outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+    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);
     }
+    outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
+    outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
 
-    outb(SCSIRSTO, SCSISEQ + base);
-    udelay(1000);
-    outb(0, SCSISEQ + base);
+    p->scsi_id = sc->brtime_id & CFSCSIID;
 
-    /* Ensure we don't get a RSTI interrupt from this. */
-    outb(CLRSCSIRSTI, CLRSINT1 + base);
-    outb(CLRSCSIINT, CLRINT + base);
+    scsi_conf = (p->scsi_id & 0x7);
+    if (sc->adapter_control & CFSPARITY)
+      scsi_conf |= ENSPCHK;
+    if (sc->adapter_control & CFRESETB)
+      scsi_conf |= RESET_SCSI;
 
-    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+    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;
+      }
+    }
 
-    printk("done.\n");
-  }
+    /* Set the host ID */
+    outb(scsi_conf, p->base + SCSICONF);
+    /* In case we are a wide card */
+    outb(p->scsi_id, p->base + SCSICONF + 1);
 
-  /*
-   * 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);
-  return (found);
+    if (p->chip_class != AIC_777x)
+    {
+      /*
+       * 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);
+    }
+  }
+  return (have_seeprom);
 }
 
 /*+F*************************************************************************
@@ -4672,17 +5678,24 @@ aic7xxx_register(Scsi_Host_Template *template,
  *
  * Description:
  *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe().  A sequence of
+ *       probe(), attach()/detach(), and init() makes more sense than
+ *       one do-it-all function.  This may be useful when (and if) the
+ *       mid-level SCSI code is overhauled.
  *-F*************************************************************************/
 int
 aic7xxx_detect(Scsi_Host_Template *template)
 {
-  int found = 0, slot, base;
-  unsigned char irq = 0;
+  int found = 0;
+  aha_status_type adapter_bios;
+  aha_chip_class_type chip_class;
+  aha_chip_type chip_type;
+  int slot, base;
+  int chan_num = 0;
+  unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
   int i;
-  struct aic7xxx_host_config config;
-
-  template->proc_dir = &proc_scsi_aic7xxx;
-  config.chan_num = 0;
+  struct aic7xxx_host *p;
 
   /*
    * Since we may allow sharing of IRQs, it is imperative
@@ -4696,6 +5709,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
     aic7xxx_boards[i] = NULL;
   }
 
+  template->proc_dir = &proc_scsi_aic7xxx;
+  template->name = aic7xxx_info(NULL);
+  template->sg_tablesize = AIC7XXX_MAX_SG;
+
   /*
    * Initialize the spurious count to 0.
    */
@@ -4717,33 +5734,174 @@ aic7xxx_detect(Scsi_Host_Template *template)
       continue;
     }
 
-    config.type = aic7xxx_probe(slot, HID0 + base, &(config.bios));
-    if (config.type != AIC_NONE)
+    chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
+    if (chip_type != AIC_NONE)
     {
+
+      switch (chip_type)
+      {
+        case AIC_7770:
+        case AIC_7771:
+          printk("aic7xxx: <%s> at EISA %d\n",
+                 board_names[chip_type], slot);
+          break;
+        case AIC_284x:
+          printk("aic7xxx: <%s> at VLB %d\n",
+                 board_names[chip_type], slot);
+          break;
+        default:
+          break;
+      }
+
       /*
        * We found a card, allow 1 spurious interrupt.
        */
       aic7xxx_spurious_count = 1;
 
       /*
-       * We "find" a AIC-7770 if we locate the card
-       * signature and we can set it up and register
-       * it with the kernel without incident.
+       * Pause the card preserving the IRQ type.  Allow the operator
+       * to override the IRQ trigger.
        */
-      config.chip_type = AIC_777x;
-      config.base = base;
-      config.mbase = 0;
-      config.irq = irq;
-      config.parity = AIC_ENABLED;
-      config.low_term = AIC_UNKNOWN;
-      config.high_term = AIC_UNKNOWN;
-      config.flags = 0;
-      if (aic7xxx_extended)
-        config.flags |= EXTENDED_TRANSLATION;
-      config.bus_speed = DFTHRSH_100;
-      config.busrtime = BOFF;
-      found += aic7xxx_register(template, &config);
+      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);
+
+      irq = inb(INTDEF + base) & 0x0F;
+      switch (irq)
+      {
+        case 9:
+        case 10:
+        case 11:
+        case 12:
+        case 14:
+        case 15:
+          break;
+
+        default:
+          printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+          "level, ignoring.\n");
+          irq = 0;
+          break;
+      }
+
+      if (irq != 0)
+      {
+        p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
+        if (p == NULL)
+        {
+          printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+          continue;
+        }
+        p->irq = irq & 0x0F;
+        p->chip_class = AIC_777x;
+#ifdef AIC7XXX_PAGE_ENABLE
+        p->flags |= PAGE_ENABLED;
+#endif
+        p->instance = found;
+        if (aic7xxx_extended)
+        {
+          p->flags |= EXTENDED_TRANSLATION;
+        }
+        aic7xxx_chip_reset(p);
+
+        switch (p->chip_type)
+        {
+          case AIC_7770:
+          case AIC_7771:
+          {
+            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)
+            {
+              p->flags |= USE_DEFAULTS;
+            }
+            break;
+          }
+
+          case AIC_284x:
+            if (!load_seeprom(p, &sxfrctl1))
+            {
+              if (aic7xxx_verbose)
+                printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+            }
+            break;
+
+          default:  /* Won't get here. */
+            break;
+        }
+        printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, 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)
+        {
+          /*
+           * We detected a Rev E board, we allow paging on this board.
+           */
+          printk("Revision >= E\n");
+          outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+        }
+        else
+        {
+          /* Do not allow paging. */
+          p->flags &= ~PAGE_ENABLED;
+          printk("Revision <= C\n");
+        }
+
+        if (aic7xxx_verbose)
+          printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+                 (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+        /*
+         * Set the FIFO threshold and the bus off time.
+         */
+        hostconf = inb(p->base + HOSTCONF);
+        outb(hostconf & DFTHRSH, p->base + BUSSPD);
+        outb((hostconf << 2) & BOFF, p->base + BUSTIME);
 
+        /*
+         * Try to initialize the card and register it with the kernel.
+         */
+        if (aic7xxx_register(template, p))
+        {
+          /*
+           * We successfully found a board and registered it.
+           */
+          found = found + 1;
+        }
+        else
+        {
+          /*
+           * Something went wrong; release and free all resources.
+           */
+          aic7xxx_free(p);
+        }
+      }
       /*
        * Disallow spurious interrupts.
        */
@@ -4759,15 +5917,15 @@ aic7xxx_detect(Scsi_Host_Template *template)
   {
     struct
     {
-      unsigned short vendor_id;
-      unsigned short device_id;
-      aha_type       card_type;
-      aha_chip_type  chip_type;
+      unsigned short      vendor_id;
+      unsigned short      device_id;
+      aha_chip_type       chip_type;
+      aha_chip_class_type chip_class;
     } 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_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, 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},
@@ -4780,14 +5938,14 @@ aic7xxx_detect(Scsi_Host_Template *template)
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
     };
 
-    int error;
+    int error, flags;
     int done = 0;
     unsigned int iobase, mbase;
     unsigned short index = 0;
     unsigned char pci_bus, pci_device_fn;
-    unsigned int  csize_lattime;
-    unsigned int  class_revid;
-    unsigned int  devconfig;
+    unsigned char ultra_enb = 0;
+    unsigned int  devconfig, class_revid;
+    scb_data_type *shared_scb_data = NULL;
     char rev_id[] = {'B', 'C', 'D'};
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
@@ -4804,36 +5962,33 @@ aic7xxx_detect(Scsi_Host_Template *template)
         }
         else  /* Found an Adaptec PCI device. */
         {
-          config.type = aic7xxx_pci_devices[i].card_type;
-          config.chip_type = aic7xxx_pci_devices[i].chip_type;
-          config.chan_num = 0;
-          config.bios = AIC_ENABLED;  /* Assume bios is enabled. */
-          config.flags = 0;
-          config.busrtime = 40;
-          switch (config.type)
+          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)
           {
             case AIC_7850:
             case AIC_7855:
-            case AIC_7860:
-            case AIC_7861:
-              config.bios = AIC_DISABLED;
-              config.flags |= USE_DEFAULTS;
-              config.bus_speed = DFTHRSH_100;
+              flags |= USE_DEFAULTS;
               break;
 
             case AIC_7872:  /* 3940 */
             case AIC_7882:  /* 3940-Ultra */
-              config.chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
+              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 */
-              config.chan_num = number_of_3985s;  /* Has 3 controllers */
+              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;
 
@@ -4850,39 +6005,165 @@ aic7xxx_detect(Scsi_Host_Template *template)
                                             PCI_INTERRUPT_LINE, &irq);
           error += pcibios_read_config_dword(pci_bus, pci_device_fn,
                                             PCI_BASE_ADDRESS_1, &mbase);
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             DEVCONFIG, &devconfig);
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             CLASS_PROGIF_REVID, &class_revid);
+
+          printk("aic7xxx: <%s> at PCI %d\n",
+                 board_names[chip_type], PCI_SLOT(pci_device_fn));
 
           /*
-           * The first bit of PCI_BASE_ADDRESS_0 is always set, so
+           * 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 == NULL)
+          {
+            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;
+#endif
+          p->instance = found;
+
           /*
-           * Read the PCI burst size and latency timer.
+           * Remember how the card was setup in case there is no seeprom.
            */
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             CSIZE_LATTIME, &csize_lattime);
-          printk(KERN_INFO "aic7xxx: BurstLen = %d DWDs, Latency Timer = %d "
-                 "PCLKS\n", (int) (csize_lattime & CACHESIZE),
-                 (csize_lattime >> 8) & 0x000000ff);
+          p->scsi_id = inb(p->base + SCSIID) & OID;
+          if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+          {
+            p->flags |= ULTRA_ENABLED;
+            ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+          }
+         sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
 
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             CLASS_PROGIF_REVID, &class_revid);
-          if ((class_revid & DEVREVID) < 3)
+          aic7xxx_chip_reset(p);
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
+          if (devconfig & RAMPSM)
           {
-            printk(KERN_INFO "aic7xxx: %s Rev %c.\n", board_names[config.type],
-                   rev_id[class_revid & DEVREVID]);
+            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
+                   "access.\n");
+            /*
+             * XXX - Assume 9 bit SRAM and enable parity checking.
+             */
+            devconfig |= EXTSCBPEN;
+
+            /*
+             * 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);
           }
+#endif
 
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             DEVCONFIG, &devconfig);
-          if (error)
+          if ((p->flags & USE_DEFAULTS) == 0)
+          {
+            load_seeprom(p, &sxfrctl1);
+          }
+
+          /*
+           * Take the LED out of diagnostic mode
+           */
+          sblkctl = inb(p->base + SBLKCTL);
+          outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + 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);
+
+          if (p->flags & USE_DEFAULTS)
           {
-            panic("aic7xxx: (aic7xxx_detect) Error %d reading PCI registers.\n",
-                  error);
+            int j;
+            /*
+             * Default setup; should only be used if the adapter does
+             * not have a SEEPROM.
+             */
+            /*
+             * Check the target scratch area to see if someone set us
+             * up already.  We are previously set up if the scratch
+             * area contains something other than all zeroes and ones.
+             */
+            for (j = TARG_SCRATCH; j < 0x60; j++)
+            {
+              if (inb(p->base + j) != 0x00)      /* Check for all zeroes. */
+                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))
+            {
+              p->flags &= ~USE_DEFAULTS;
+              if (aic7xxx_verbose)
+              {
+                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.
+               */
+              sxfrctl1 = STPWEN;
+              p->scsi_id = 7;
+            }
+            outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+                 p->base + 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;
+            }
           }
 
-          printk(KERN_INFO "aic7xxx: devconfig = 0x%x.\n", devconfig);
+          /*
+           * Print some additional information about the adapter.
+           */
+          printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
+                 "IO Mem 0x%x, IRQ %d",
+                 (p->flags & USE_DEFAULTS) ? "dis" : "en",
+                 p->base, p->mbase, p->irq);
+          if ((class_revid & DEVREVID) < 3)
+          {
+            printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+          }
+          printk("\n");
 
           /*
            * I don't think we need to bother with allowing
@@ -4891,58 +6172,57 @@ aic7xxx_detect(Scsi_Host_Template *template)
            */
           aic7xxx_spurious_count = 1;
 
-          config.base = iobase;
-          config.mbase = mbase;
-          config.irq = irq;
-          config.parity = AIC_ENABLED;
-          config.low_term = AIC_UNKNOWN;
-          config.high_term = AIC_UNKNOWN;
           if (aic7xxx_extended)
-            config.flags |= EXTENDED_TRANSLATION;
-#ifdef AIC7XXX_SHARE_SCBs
-          if (devconfig & RAMPSM)
-#else
-          if ((devconfig & RAMPSM) && (config.type != AIC_7873) &&
-              (config.type != AIC_7883))
-#endif
+            p->flags |= EXTENDED_TRANSLATION;
+
+          if (aic7xxx_verbose)
+            printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+                   (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+          /*
+           * 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)
+          {
+            aic7xxx_free(p);
+          }
+          else
           {
+            found = found + 1;
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
             /*
-             * External SRAM present.  The probe will walk the SCBs to see
-             * how much SRAM we have and set the number of SCBs accordingly.
-             * We have to turn off SCBRAMSEL to access the external SCB
-             * SRAM.
+             * Set the shared SCB data once we've successfully probed a
+             * 398x adapter.
              *
-             * It seems that early versions of the aic7870 didn't use these
-             * bits, hence the hack for the 3940 above.  I would guess that
-             * recent 3940s using later aic7870 or aic7880 chips do actually
-             * set RAMPSM.
-             *
-             * The documentation isn't clear, but it sounds like the value
-             * written to devconfig must not have RAMPSM set.  The second
-             * sixteen bits of the register are R/O anyway, so it shouldn't
-             * affect RAMPSM either way.
+             * Note that we can only do this if the use of external
+             * SCB RAM is enabled.
              */
-            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
-                   "access.\n");
-            devconfig &= ~(RAMPSM | SCBRAMSEL);
-            pcibios_write_config_dword(pci_bus, pci_device_fn,
-                                       DEVCONFIG, devconfig);
+            if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+            {
+              if (shared_scb_data == NULL)
+              {
+                shared_scb_data = p->scb_data;
+              }
+            }
+#endif
           }
-          found += aic7xxx_register(template, &config);
 
+          index++;
           /*
            * Disable spurious interrupts.
            */
-          aic7xxx_spurious_count = 0;
-
-          index++;
+          aic7xxx_spurious_count = 0;
         }  /* Found an Adaptec PCI device. */
       }
     }
   }
 #endif CONFIG_PCI
 
-  template->name = aic7xxx_info(NULL);
   return (found);
 }
 
@@ -4958,45 +6238,45 @@ static void
 aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     struct aic7xxx_scb *scb)
 {
-  unsigned int addr; /* must be 32 bits */
   unsigned short mask;
+  struct aic7xxx_hwscb *hscb;
 
   mask = (0x01 << TARGET_INDEX(cmd));
+  hscb = scb->hscb;
+
   /*
    * Setup the control byte if we need negotiation and have not
    * already requested it.
    */
-#ifdef AIC7XXX_TAGGED_QUEUEING
-  if (cmd->device->tagged_queue)
+  if (p->discenable & mask)
   {
-    cmd->tag = scb->tag;
-    cmd->device->current_tag = scb->tag;
-    scb->control |= TAG_ENB;
-    p->device_status[TARGET_INDEX(cmd)].commands_sent++;
-    if (p->device_status[TARGET_INDEX(cmd)].commands_sent == 200)
-    {
-      scb->control |= 0x02;
-      p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
-    }
-#if 0
-    if (p->orderedtag & mask)
+    hscb->control |= DISCENB;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+    if (cmd->device->tagged_queue)
     {
-      scb->control |= 0x02;
-      p->orderedtag = p->orderedtag & ~mask;
+      cmd->tag = hscb->tag;
+      p->device_status[TARGET_INDEX(cmd)].commands_sent++;
+      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
+      {
+        hscb->control |= MSG_SIMPLE_Q_TAG;
+      }
+      else
+      {
+        hscb->control |= MSG_ORDERED_Q_TAG;
+        p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+      }
     }
-#endif
-  }
-#endif
-  if (p->discenable & mask)
-  {
-    scb->control |= DISCENB;
+#endif  /* Tagged queueing */
   }
+
   if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
   {
     p->wdtr_pending |= mask;
-    scb->control |= NEEDWDTR;
+    hscb->control |= MK_MESSAGE;
+    scb->flags |= SCB_MSGOUT_WDTR;
 #if 0
-    printk("aic7xxx: Sending WDTR request to target %d.\n", cmd->target);
+    printk("scsi%d: Sending WDTR request to target %d.\n",
+           p->host_no, cmd->target);
 #endif
   }
   else
@@ -5004,19 +6284,20 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
     {
       p->sdtr_pending |= mask;
-      scb->control |= NEEDSDTR;
+      hscb->control |= MK_MESSAGE;
+      scb->flags |= SCB_MSGOUT_SDTR;
 #if 0
-      printk("aic7xxx: Sending SDTR request to target %d.\n", cmd->target);
+      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
-  scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+  hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
        ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
 
   /*
@@ -5030,9 +6311,8 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
    * XXX - this relies on the host data being stored in a
    *       little-endian format.
    */
-  addr = VIRT_TO_BUS(cmd->cmnd);
-  scb->SCSI_cmd_length = cmd->cmd_len;
-  memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+  hscb->SCSI_cmd_length = cmd->cmd_len;
+  hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
 
   if (cmd->use_sg)
   {
@@ -5052,15 +6332,16 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
       scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
       scb->sg_list[i].length = (unsigned int) sg[i].length;
     }
-    scb->SG_segment_count = cmd->use_sg;
-    addr = VIRT_TO_BUS(scb->sg_list);
-    memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
-    memcpy(scb->data_pointer, &(scb->sg_list[0].address),
-           sizeof(scb->data_pointer));
-    scb->data_count = scb->sg_list[0].length;
+    hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
+    hscb->SG_segment_count = cmd->use_sg;
+    scb->sg_count = hscb->SG_segment_count;
+
+    /* 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 | (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), scb->data_count);
+           cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
 #endif
   }
   else
@@ -5069,28 +6350,23 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
   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 == 0)
+    if (cmd->request_bufflen)
     {
-      /*
-       * In case the higher level SCSI code ever tries to send a zero
-       * length command, ensure the SCB indicates no data.  The driver
-       * will interpret a zero length command as a Bus Device Reset.
-       */
-      scb->SG_segment_count = 0;
-      memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
-      memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
-      scb->data_count = 0;
+      hscb->SG_segment_count = 1;
+      scb->sg_count = 1;
+      scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
+      scb->sg_list[0].length = cmd->request_bufflen;
+      hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
+      hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
+      hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
     }
     else
     {
-      scb->SG_segment_count = 1;
-      scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
-      scb->sg_list[0].length = cmd->request_bufflen;
-      addr = VIRT_TO_BUS(&scb->sg_list[0]);
-      memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
-      scb->data_count = scb->sg_list[0].length;
-      addr = VIRT_TO_BUS(cmd->request_buffer);
-      memcpy(scb->data_pointer, &addr, sizeof(scb->data_pointer));
+      hscb->SG_segment_count = 0;
+      scb->sg_count = 0;
+      hscb->SG_list_pointer = 0;
+      hscb->data_pointer = 0;
+      hscb->data_count = SCB_LIST_NULL << 24;
     }
   }
 }
@@ -5108,7 +6384,6 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
   long processor_flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
-  u_char curscb, intstat;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   if (p->host != cmd->host)
@@ -5140,34 +6415,21 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
        cmd->lun & 0x07);
 #endif
 
-  /*
-   * This is a critical section, since we don't want the interrupt
-   * routine mucking with the host data or the card.  For this reason
-   * it is nice to know that this function can only be called in one
-   * of two ways from scsi.c  First, as part of a routine queue command,
-   * in which case, the irq for our card is disabled before this
-   * function is called.  This doesn't help us if there is more than
-   * one card using more than one IRQ in our system, therefore, we
-   * should disable all interrupts on these grounds alone.  Second,
-   * this can be called as part of the scsi_done routine, in which case
-   * we are in the aic7xxx_isr routine already and interrupts are
-   * disabled, therefore we should saveflags first, then disable the
-   * interrupts, do our work, then restore the CPU flags. If it weren't
-   * for the possibility of more than one card using more than one IRQ
-   * in our system, we wouldn't have to touch the interrupt flags at all.
-   */
-  save_flags(processor_flags);
-  cli();
-
+  if (p->device_status[TARGET_INDEX(cmd)].active_cmds
+      > cmd->device->queue_depth)
+  {
+    printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
+           p->host_no, cmd->target, cmd->channel);
+  }
   scb = aic7xxx_allocate_scb(p);
   if (scb == NULL)
   {
-    panic("aic7xxx: (aic7xxx_free) Couldn't find a free SCB.\n");
+    panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
   }
   else
   {
     scb->cmd = cmd;
-    aic7xxx_position(cmd) = scb->tag;
+    aic7xxx_position(cmd) = scb->hscb->tag;
 #if 0
     debug_scb(scb);
 #endif;
@@ -5179,14 +6441,14 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
     aic7xxx_buildscb(p, cmd, scb);
 
 #if 0
-    if (scb != (p->scb_array[scb->position]))
+    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->position, (unsigned int) scb->cmd,
-          scb->state, (unsigned int) p->free_scb);
+          scb->hscb->tag, (unsigned int) scb->cmd,
+          scb->flags, (unsigned int) p->free_scb);
 #endif
 
     /*
@@ -5201,70 +6463,28 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
     cmd->host_scribble = NULL;
     memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
 
-    if (scb->position != SCB_LIST_NULL)
-    {
-      /* We've got a valid slot, yeah! */
-      if (p->flags & IN_ISR)
-      {
-        scbq_insert_tail(&p->assigned_scbs, scb);
-        scb->state |= SCB_ASSIGNEDQ;
-      }
-      else
-      {
-        /*
-         * Pause the sequencer so we can play with its registers -
-         * wait for it to acknowledge the pause.
-         *
-         * XXX - should the interrupts be left on while doing this?
-         */
-        PAUSE_SEQUENCER(p);
-        intstat = inb(INTSTAT + p->base);
-
-        /*
-         * Save the SCB pointer and put our own pointer in - this
-         * selects one of the four banks of SCB registers. Load
-         * the SCB, then write its pointer into the queue in FIFO
-         * and restore the saved SCB pointer.
-         */
-        curscb = inb(SCBPTR + p->base);
-        outb(scb->position, SCBPTR + p->base);
-        aic7xxx_putscb(p, scb);
-        outb(curscb, SCBPTR + p->base);
-        outb(scb->position, QINFIFO + p->base);
-        scb->state |= SCB_ACTIVE;
+    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-        /*
-         * Guard against unpausing the sequencer if there is an interrupt
-         * waiting to happen.
-         */
-        if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
-        {
-          UNPAUSE_SEQUENCER(p);
-        }
-      }
-    }
-    else
+    save_flags(processor_flags);
+    cli();
+    scbq_insert_tail(&p->waiting_scbs, scb);
+    if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
     {
-      scb->state |= SCB_WAITINGQ;
-      scbq_insert_tail(&p->waiting_scbs, scb);
-      if (!(p->flags & IN_ISR))
-      {
-        aic7xxx_run_waiting_queues(p);
-      }
+      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->position);
+           (long) cmd, (long) scb->cmd, scb->hscb->tag);
 #endif;
-    restore_flags(processor_flags);
   }
   return (0);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_abort_reset
+ *   aic7xxx_bus_device_reset
  *
  * Description:
  *   Abort or reset the current SCSI command(s).  If the scb has not
@@ -5276,204 +6496,257 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 static int
 aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
-  struct aic7xxx_scb  *scb;
+  struct aic7xxx_scb   *scb;
+  struct aic7xxx_hwscb *hscb;
   unsigned char bus_state;
-  int base, result = -1;
+  int result = -1;
   char channel;
 
-  scb = (p->scb_array[aic7xxx_position(cmd)]);
-  base = p->base;
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  hscb = scb->hscb;
+
+  /*
+   * Ensure that the card doesn't do anything behind our back.
+   * Also make sure that we didn't just miss an interrupt that
+   * could affect this abort/reset.
+   */
+  pause_sequencer(p);
+  while (inb(p->base + INTSTAT) & INT_PEND);
+  {
+    aic7xxx_isr(p->irq, (void *) NULL, (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);
+  }
 
-  channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
-  if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS))
+
+  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:
+      /*
+       * We're not in a valid phase, so assume we're idle.
+       */
+      printk("while idle, LASTPHASE = 0x%x, ", bus_state);
+      break;
+  }
+  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));
 
-    if (scb->state & SCB_IN_PROGRESS)
+  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)
     {
       /*
-       * Ensure that the card doesn't do anything
-       * behind our back.
+       * We could be starving this command; try sending and ordered tag
+       * command to the target we come from.
        */
-      PAUSE_SEQUENCER(p);
+      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;
 
-      printk(KERN_WARNING "aic7xxx: (abort_reset) scb state 0x%x, ", scb->state);
-      bus_state = inb(LASTPHASE + p->base);
+    /*
+     * Send an Abort 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
+     * abort message to the timed out target if it is disconnected.
+     * Otherwise, if we have an active target we stuff the message buffer
+     * with an abort message and assert ATN in the hopes that the target
+     * will let go of the bus and go to the mesgout phase.  If this
+     * 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];
 
-      switch (bus_state)
+    if (bus_state != P_BUSFREE)
+    {
+      if (active_scb_index >= p->scb_data->numscbs)
       {
-       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("while idle, LASTPHASE = 0x%x, ", bus_state);
-          /*
-           * We're not in a valid phase, so assume we're idle.
-           */
-          bus_state = 0;
-          break;
+        /*
+         * 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);
       }
-      printk("SCSISIGI = 0x%x\n", inb(p->base + SCSISIGI));
-
-      /*
-       * First, determine if we want to do a bus reset or simply a bus device
-       * reset.  If this is the first time that a transaction has timed out
-       * and the SCB is not paged out, just schedule a bus device reset.
-       * Otherwise, we reset the bus and abort all pending I/Os on that bus.
-       */
-      if (!(scb->state & (SCB_ABORTED | SCB_PAGED_OUT)))
+      else
       {
-#if 0
-       if (scb->control & TAG_ENB)
-       {
+        /* 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)
+        {
           /*
-           * We could be starving this command; try sending and ordered tag
-           * command to the target we come from.
+           * 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.
            */
-          scb->state = scb->state | SCB_ABORTED | SCB_SENTORDEREDTAG;
-          p->orderedtag = p->orderedtag | 0xFF;
           result = SCSI_RESET_PENDING;
-          UNPAUSE_SEQUENCER(p);
-          printk(KERN_WARNING "aic7xxx: (abort_reset) Ordered tag queued.\n");
-       }
-#endif
-       unsigned char active_scb, control;
-       struct aic7xxx_scb *active_scbp;
+          aic7xxx_error(active_scb->cmd) = DID_RESET;
+        }
+        else
+        {
+          aic7xxx_error(scb->cmd) = DID_RESET;
+          result = SCSI_RESET_PENDING;
+        }
+        unpause_sequencer(p, /* unpause_always */ TRUE);
+      }
+    }
+    else
+    {
+      unsigned char hscb_index, linked_next;
+      int disconnected;
 
-       /*
-        * Send a Bus Device Reset Message:
-        * The target we select to send the message to may be entirely
-        * different than the target pointed to by the scb that timed
-        * out.  If the command is in the QINFIFO or the waiting for
-        * selection list, its not tying up the bus and isn't responsible
-        * for the delay so we pick off the active command which should
-        * be the SCB selected by SCBPTR.  If its disconnected or active,
-        * we device reset the target scbp points to.  Although it may
-        * be that this target is not responsible for the delay, it may
-        * may also be that we're timing out on a command that just takes
-        * too much time, so we try the bus device reset there first.
-        */
-       active_scb = inb(SCBPTR + base);
-       active_scbp = (p->scb_array[inb(SCB_TAG + base)]);
-       control = inb(SCB_CONTROL + base);
+      disconnected = FALSE;
+      hscb_index = aic7xxx_find_scb(p, scb);
+      if (hscb_index == SCB_LIST_NULL)
+      {
+        disconnected = TRUE;
+        linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+      }
+      else
+      {
+        outb(hscb_index, p->base + SCBPTR);
+        if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
+        {
+          disconnected = TRUE;
+        }
+        linked_next = inb(p->base + SCB_LINKED_NEXT);
+      }
+      if (disconnected)
+      {
+        /*
+         * Simply set the ABORT_SCB control bit and preserve the
+         * linked next pointer.
+         */
+        scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+        scb->hscb->data_count &= ~0xFF000000;
+        scb->hscb->data_count |= 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;
 
-       /*
-        * Test to see if scbp is disconnected
-        */
-       outb(scb->position, SCBPTR + base);
-       if (inb(SCB_CONTROL + base) & DISCONNECTED)
-       {
-#ifdef AIC7XXX_DEBUG_ABORT
-          printk("aic7xxx: (abort_scb) scb %d is disconnected; "
-                 "bus device reset message queued.\n", scb->position);
-#endif
-          if (p->flags & PAGE_ENABLED)
-          {
-            /* Pull this SCB out of the disconnected list. */
-            u_char prev = inb(SCB_PREV + base);
-            u_char next = inb(SCB_NEXT + base);
-            if (prev == SCB_LIST_NULL)
-            {
-              /* Head of list */
-              outb(next, DISCONNECTED_SCBH + base);
-            }
-            else
-            {
-              outb(prev, SCBPTR + base);
-              outb(next, SCB_NEXT + base);
-              if (next != SCB_LIST_NULL)
-              {
-               outb(next, SCBPTR + base);
-               outb(prev, SCB_PREV + base);
-              }
-              outb(scb->position, SCBPTR + base);
-            }
-          }
-         scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
-          scb->control = scb->control & DISCENB;
-          scb->SCSI_cmd_length = 0;
-         scb->SG_segment_count = 0;
-         memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
-         memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
-         scb->data_count = 0;
-         aic7xxx_putscb(p, scb);
-         aic7xxx_add_waiting_scb(base, scb);
-         outb(active_scb, SCBPTR + base);
-          result = SCSI_RESET_PENDING;
-         UNPAUSE_SEQUENCER(p);
-       }
-       else
-       {
-         /*
-          * Is the active SCB really active?
-          */
-         if ((active_scbp->state & SCB_ACTIVE) && bus_state)
-         {
-            /*
-             * Load the message buffer and assert attention.
-             */
-            active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
-            outb(1, MSG_LEN + base);
-            outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
-            outb(bus_state | ATNO, SCSISIGO + base);
-#ifdef AIC7XXX_DEBUG_ABORT
-            printk("aic7xxx: (abort_scb) asserted ATN - "
-                   "bus device reset in message buffer.\n");
-#endif
-            if (active_scbp != 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.
-               */
-              ;
-            }
-            aic7xxx_error(scb->cmd) = DID_RESET;
-            /*
-             * Restore the active SCB and unpause the sequencer.
-             */
-            outb(active_scb, SCBPTR + base);
-            if (active_scbp != scb)
-            {
-              /*
-               * The mid-level SCSI code requested us to reset a command
-               * different from the one that we actually reset.  Return
-               * a "not running" indication and hope that the SCSI code
-               * will Do the Right Thing (tm).
-               */
-              result = SCSI_RESET_NOT_RUNNING;
-            }
-            else
-            {
-              result = SCSI_RESET_PENDING;
-            }
-            UNPAUSE_SEQUENCER(p);
-         }
-       }
+          scb_control = inb(p->base + SCB_CONTROL);
+          outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + 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.
+         */
+        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;
       }
     }
   }
-  /* Make sure the sequencer is unpaused upon return. */
-  if (result == -1)
-  {
-    UNPAUSE_SEQUENCER(p);
-  }
   return (result);
 }
 
@@ -5491,16 +6764,48 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   struct aic7xxx_scb  *scb = NULL;
   struct aic7xxx_host *p;
   int    base, result;
+  unsigned long processor_flags;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_array[aic7xxx_position(cmd)]);
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   base = p->base;
 
+  save_flags(processor_flags);
+  cli();
+
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: (abort) Aborting scb %d, TCL %d/%d/%d\n",
-         scb->position, TCL_OF_SCB(scb));
+  if (scb != NULL)
+  {
+    printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
+           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+  }
+  else
+  {
+    printk("aic7xxx: Abort called with no SCB for cmd.\n");
+  }
 #endif
 
+  if (p->flags & IN_TIMEOUT)
+  {
+    /*
+     * We've already started a recovery operation.
+     */
+    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+    {
+      restore_flags(processor_flags);
+      return (SCSI_ABORT_PENDING);
+    }
+    else
+    {
+      /*
+       * 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);
+    }
+  }
   if (cmd->serial_number != cmd->serial_number_at_timeout)
   {
     result = SCSI_ABORT_NOT_RUNNING;
@@ -5509,14 +6814,34 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   {
     result = SCSI_ABORT_NOT_RUNNING;
   }
-  else if ((scb->cmd != cmd) || (!(scb->state & SCB_IN_PROGRESS)))
+  else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
   {
     result = SCSI_ABORT_NOT_RUNNING;
   }
   else
   {
-    result = SCSI_ABORT_SNOOZE;
+    /*
+     * 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;
+     }
   }
+  restore_flags(processor_flags);
   return (result);
 }
 
@@ -5536,18 +6861,27 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
 {
   struct aic7xxx_scb *scb = NULL;
   struct aic7xxx_host *p;
-  int    base, found, tindex, min_target, max_target, result = -1;
+  int    base, found, tindex, min_target, max_target;
+  int    result = -1;
   char   channel = 'A';
   unsigned long processor_flags;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_array[aic7xxx_position(cmd)]);
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   base = p->base;
   channel = cmd->channel ? 'B': 'A';
   tindex = (cmd->channel << 4) | cmd->target;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
+#ifdef 0   /* AIC7XXX_DEBUG_ABORT */
+  if (scb != NULL)
+  {
+    printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
+           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+  }
+  else
+  {
+    printk("aic7xxx: Reset called with no SCB for cmd.\n");
+  }
 #endif
 
   /* 
@@ -5562,34 +6896,45 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   if (scb->cmd != cmd)
     scb = NULL;
 
-  if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET)) 
-      && (scb != NULL))
+  if (p->flags & IN_TIMEOUT)
   {
     /*
-     * 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.
+     * We've already started a recovery operation.
      */
-    if ((p->flags & DEVICE_SUCCESS) ||
-        ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
+    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
     {
-      if (cmd->serial_number != cmd->serial_number_at_timeout)
-      {
-        result = SCSI_RESET_NOT_RUNNING;
-      }
-      else
+      restore_flags(processor_flags);
+      return (SCSI_RESET_PENDING);
+    }
+  }
+  else
+  {
+    if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
+        && (scb != NULL))
+    {
+      /*
+       * Attempt a bus device reset if commands have completed successfully
+       * since the last bus device reset, or it has been less than 100ms
+       * since the last reset.
+       */
+      if ((p->flags & DEVICE_SUCCESS) ||
+          ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
       {
-        if (scb == NULL)
+       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->state & SCB_ABORTED)
+          if (scb->flags & SCB_ABORTED)
           {
             result = SCSI_RESET_PENDING;
           }
-          else if (!(scb->state & SCB_IN_PROGRESS))
+          else if (!(scb->flags & SCB_ACTIVE))
           {
             result = SCSI_RESET_NOT_RUNNING;
           }
@@ -5600,20 +6945,23 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
           if ((flags & SCSI_RESET_SYNCHRONOUS) &&
               (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
           {
-            scb->state |= SCB_ABORTED;
+            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 (result == -1)
   {
     /*
@@ -5626,11 +6974,11 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       {
        result = SCSI_RESET_NOT_RUNNING;
       }
-      else if (!(scb->state & SCB_IN_PROGRESS))
+      else if (!(scb->flags & SCB_ACTIVE))
       {
        result = SCSI_RESET_NOT_RUNNING;
       }
-      else if ((scb->state & SCB_ABORTED) &&
+      else if ((scb->flags & SCB_ABORTED) &&
                (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
       {
        result = SCSI_RESET_PENDING;
@@ -5642,8 +6990,9 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       /*
        * The reset channel function assumes that the sequencer is paused.
        */
-      PAUSE_SEQUENCER(p);
+      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
@@ -5689,8 +7038,10 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       }
 
       result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+      p->flags &= ~IN_TIMEOUT;
     }
   }
+  aic7xxx_run_waiting_queues(p);
   restore_flags(processor_flags);
   return (result);
 }
index d4de8fd83487769931ace77b9a354325c28b3ec9..5ba54acfa79983459ee9577128b56ad1889b741a 100644 (file)
        aic7xxx_info,                                           \
        NULL,                                                   \
        aic7xxx_queue,                                          \
-       aic7xxx_abort,                                          \
+       NULL,                                                   \
        aic7xxx_reset,                                          \
        NULL,                                                   \
        aic7xxx_biosparam,                                      \
        -1,                     /* max simultaneous cmds      */\
        -1,                     /* scsi id of host adapter    */\
-       SG_ALL,                 /* max scatter-gather cmds    */\
+       0,                      /* max scatter-gather cmds    */\
        2,                      /* cmds per lun (linked cmds) */\
        0,                      /* number of 7xxx's present   */\
        0,                      /* no memory DMA restrictions */\
@@ -57,7 +57,6 @@ 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 const char *aic7xxx_info(struct Scsi_Host *);
diff --git a/drivers/scsi/aic7xxx.seq b/drivers/scsi/aic7xxx.seq
deleted file mode 100644 (file)
index 98d4b95..0000000
+++ /dev/null
@@ -1,1127 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver for Linux and FreeBSD.
- *
- * Copyright (c) 1994 John Aycock
- *   The University of Calgary Department of Computer Science.
- *
- *Modifications/enhancements:
- *  Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 
- * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
- *
- * This version corresponds to version 1.42 of FreeBSDs aic7xxx.seq.
- *
- *-M*************************************************************************/
-
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 4.0 1996/10/13 08:23:42 deang Exp $"
-
-#ifdef linux
-#include "aic7xxx_reg.h"
-#else
-#if defined(__NetBSD__)
-#include "../../../../dev/ic/aic7xxxreg.h"
-#elif defined(__FreeBSD__)
-#include "../../dev/aic7xxx/aic7xxx_reg.h"
-#endif
-#endif
-
-/*
- * We can't just use ACCUM in the sequencer code because it
- * must be treated specially by the assembler, and it currently
- * looks for the symbol 'A'.  This is the only register defined in
- * the assembler's symbol space.
- */
-A = ACCUM
-
-/* After starting the selection hardware, we check for reconnecting targets
- * as well as for our selection to complete just in case the reselection wins
- * bus arbitration.  The problem with this is that we must keep track of the
- * SCB that we've already pulled from the QINFIFO and started the selection
- * on just in case the reselection wins so that we can retry the selection at
- * a later time.  This problem cannot be resolved by holding a single entry
- * in scratch ram since a reconnecting target can request sense and this will
- * create yet another SCB waiting for selection.  The solution used here is to 
- * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
- * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB offsets, 
- * SCB_LIST_NULL is 0xff which is out of range.  The kernel driver must
- * add an entry to this list every time a request sense occurs.  The sequencer
- * will 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     DFCNTRL
-       clr     SCSISIGO                /* De-assert BSY */
-/*
- * We jump to start after every bus free.
- */
-start:
-       and     FLAGS,0x0f              /* clear target specific flags */
-       mvi     SCSISEQ,ENRSELI         /* Always allow reselection */
-       clr     SCSIRATE                /*
-                                        * We don't know the target we will
-                                        * connect to, so default to narrow
-                                        * transfers to avoid parity problems.
-                                        */
-poll_for_work:
-       /*
-        * Are we a twin channel device?
-        * For fairness, we check the other bus first,
-        * since we just finished a transaction on the
-        * current channel.
-        */
-       test    FLAGS,TWIN_BUS  jz start2
-       xor     SBLKCTL,SELBUSB                 /* Toggle to the other bus */
-       test    SSTAT0,SELDI    jnz reselect
-       xor     SBLKCTL,SELBUSB                 /* Toggle to the original bus */
-start2:
-       test    SSTAT0,SELDI    jnz reselect
-       cmp     WAITING_SCBH,SCB_LIST_NULL jne start_waiting
-       mov     A, QCNTMASK
-       test    QINCNT,A        jz poll_for_work
-
-/*
- * We have at least one queued SCB now and we don't have any 
- * SCBs in the list of SCBs awaiting selection.  Set the SCB
- * pointer from the FIFO so we see the right bank of SCB 
- * registers.
- */
-       mov     SCBPTR,QINFIFO
-
-/*
- * 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.  It may be beneficial to make findscb a more general procedure
- * to see if the added cost of the search is negligible.  This code also 
- * assumes that the kernel driver will clear the active flags on board 
- * initialization, board reset, and a target SELTO.  Tagged commands
- * don't set the active bits since you can queue more than one command
- * at a time.  We do, however, look to see if there are any non-tagged
- * I/Os in progress, and requeue the command if there are.  Tagged and
- * non-tagged commands cannot be mixed to a single target.
- */
-
-test_busy:
-       mov     FUNCTION1,SCB_TCL
-       mov     A,FUNCTION1
-       test    SCB_TCL,0x88    jz test_a       /* Id < 8 && A channel */
-
-       test    ACTIVE_B,A      jnz requeue
-       test    SCB_CONTROL,TAG_ENB     jnz start_scb
-       /* Mark the current target as busy */
-       or      ACTIVE_B,A
-       jmp     start_scb
-
-/* Place the currently active SCB back on the queue for later processing */
-requeue:
-       mov     QINFIFO, SCBPTR
-       jmp     poll_for_work
-
-/*
- * Pull the first entry off of the waiting for selection list
- * We don't have to "test_busy" because only transactions that
- * have passed that test can be in the waiting_scb list.
- */
-start_waiting:
-       mov     SCBPTR,WAITING_SCBH
-       jmp     start_scb2
-
-test_a:
-       test    ACTIVE_A,A jnz requeue
-       test    SCB_CONTROL,TAG_ENB jnz start_scb
-       /* Mark the current target as busy */
-       or      ACTIVE_A,A
-
-start_scb:
-       mov     SCB_NEXT,WAITING_SCBH
-       mov     WAITING_SCBH, SCBPTR
-start_scb2:
-       and     SINDEX,0xf7,SBLKCTL     /* Clear the channel select bit */
-       and     A,0x08,SCB_TCL          /* Get new channel bit */
-       or      SINDEX,A
-       mov     SBLKCTL,SINDEX          /* select channel */
-       mov     SCB_TCL call initialize_scsiid
-
-/*
- * Enable selection phase as an initiator, and do automatic ATN
- * after the selection.  We do this now so that we can overlap the
- * rest of our work to set up this target with the arbitration and
- * selection bus phases.
- */
-start_selection:
-       mvi     SCSISEQ,0x58            /* ENSELO|ENAUTOATNO|ENRSELI */
-
-/*
- * 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.
- */
-       test    SCB_CMDLEN,0xff jnz mk_identify /* 0 Length Command? */
-
-/*
- * The kernel has sent us an SCB with no command attached.  This implies
- * that the kernel wants to send a message of some sort to this target,
- * so we interrupt the driver, allow it to fill the message buffer, and
- * then go back into the arbitration loop
- */
-       mvi     INTSTAT,AWAITING_MSG
-       jmp     wait_for_selection
-
-mk_identify:
-       and     A,DISCENB,SCB_CONTROL   /* mask off disconnect privledge */
-
-       and     MSG0,0x7,SCB_TCL        /* lun */
-       or      MSG0,A                  /* or in disconnect privledge */
-       or      MSG0,MSG_IDENTIFY
-       mvi     MSG_LEN, 1
-
-       test    SCB_CONTROL,0xb0 jz  !message   /* WDTR, SDTR or TAG?? */
-/*
- * 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:
-       mvi     DINDEX, MSG1
-       test    SCB_CONTROL,TAG_ENB jz mk_tag_done
-       and     DINDIR,0x23,SCB_CONTROL
-       mov     DINDIR,SCB_TAG
-
-       add     MSG_LEN,COMP_MSG0,DINDEX        /* update message length */
-
-mk_tag_done:
-
-       test    SCB_CONTROL,0x90 jz !message    /* NEEDWDTR|NEEDSDTR */
-       mov     DINDEX  call mk_dtr     /* build DTR message if needed */
-
-!message:
-wait_for_selection:
-       test    SSTAT0,SELDO    jnz select 
-       test    SSTAT0,SELDI    jz wait_for_selection
-
-/*
- * 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 */
-       mov     SELID           call initialize_scsiid
-       or      FLAGS,RESELECTED
-       jmp     select2
-
-/*
- * After the selection, remove this SCB from the "waiting for selection"
- * list.  This is achieved by simply moving our "next" pointer into
- * 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:
-       mov     WAITING_SCBH,SCB_NEXT
-       or      FLAGS,SELECTED
-select2:
-/*
- * Set CLRCHN here before the target has entered a data transfer mode -
- * with synchronous SCSI, if you do it later, you blow away some
- * data in the SCSI FIFO that the target has already sent to you.
- */
-       or      SXFRCTL0,CLRCHN
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- */
-       call    ndx_dtr
-       mov     SCSIRATE,SINDIR
-
-/*
- * Initialize Ultra mode setting.
- */
-       mov     FUNCTION1,SCSIID
-       mov     A,FUNCTION1
-       and     SINDEX,0xdf,SXFRCTL0            /* default to Ultra disabled */
-       test    SCSIID, 0x80     jnz ultra_b    /* Target ID > 7 */
-       test    SBLKCTL, SELBUSB jnz ultra_b    /* Second channel device */
-       test    ULTRA_ENB,A      jz  set_sxfrctl0
-       or      SINDEX, ULTRAEN  jmp set_sxfrctl0
-ultra_b:
-       test    ULTRA_ENB_B,A    jz  set_sxfrctl0
-       or      SINDEX, ULTRAEN
-
-set_sxfrctl0:
-       mov     SXFRCTL0,SINDEX
-
-       mvi     SCSISEQ,ENAUTOATNP              /*
-                                                * ATN on parity errors
-                                                * for "in" phases
-                                                */
-       mvi     CLRSINT1,CLRBUSFREE
-       mvi     CLRSINT0,0x60                   /* CLRSELDI|CLRSELDO */
-/*
- * 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.
- *
- */
-ITloop:
-       test    SSTAT1,BUSFREE  jnz p_busfree
-       test    SSTAT1,REQINIT  jz ITloop
-
-       and     A,PHASE_MASK,SCSISIGI
-       mov     LASTPHASE,A
-       mov     SCSISIGO,A
-
-       cmp     ALLZEROS,A      je p_dataout
-       cmp     A,P_DATAIN      je p_datain
-       cmp     A,P_COMMAND     je p_command
-       cmp     A,P_MESGOUT     je p_mesgout
-       cmp     A,P_STATUS      je p_status
-       cmp     A,P_MESGIN      je p_mesgin
-
-       mvi     INTSTAT,BAD_PHASE       /* unknown phase - signal driver */
-       jmp     ITloop                  /* Try reading the bus again. */
-
-p_dataout:
-       mvi     DMAPARAMS,0x7d                  /*
-                                                * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
-                                                * DIRECTION|FIFORESET
-                                                */
-       jmp     data_phase_init
-
-/*
- * If we re-enter the data phase after going through another phase, the
- * STCNT may have been cleared, so restore it from the residual field.
- */
-data_phase_reinit:
-       mov     STCNT0,SCB_RESID_DCNT0
-       mov     STCNT1,SCB_RESID_DCNT1
-       mov     STCNT2,SCB_RESID_DCNT2
-       jmp     data_phase_loop
-
-p_datain:
-       mvi     DMAPARAMS,0x79          /*
-                                        * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
-                                        * !DIRECTION|FIFORESET
-                                        */
-data_phase_init:
-       call    assert
-
-       test    FLAGS, DPHASE   jnz data_phase_reinit
-       call    sg_scb2ram
-       or      FLAGS, DPHASE           /* We have seen a data phase */
-
-data_phase_loop:
-/* Guard against overruns */
-       test    SG_COUNT, 0xff jnz data_phase_inbounds
-/*
- * Turn on 'Bit Bucket' mode, set the transfer count to
- * 16meg and let the target run until it changes phase.
- * When the transfer completes, notify the host that we
- * had an overrun.
- */
-       or      SXFRCTL1,BITBUCKET
-       mvi     STCNT0,0xff
-       mvi     STCNT1,0xff
-       mvi     STCNT2,0xff
-
-data_phase_inbounds:
-/* If we are the last SG block, don't set wideodd. */
-       cmp     SG_COUNT,0x01 jne data_phase_wideodd
-       and     DMAPARAMS, 0xbf         /* Turn off WIDEODD */
-data_phase_wideodd:
-       mov     DMAPARAMS  call dma
-
-/* Go tell the host about any overruns */
-       test    SXFRCTL1,BITBUCKET jnz data_phase_overrun
-
-/* Exit if we had an underrun */
-       test    SSTAT0,SDONE    jz data_phase_finish /* underrun STCNT != 0 */
-
-/*
- * Advance the scatter-gather pointers if needed 
- */
-sg_advance:
-       dec     SG_COUNT        /* one less segment to go */
-
-       test    SG_COUNT, 0xff  jz data_phase_finish /* Are we done? */
-
-       clr     A                       /* add sizeof(struct scatter) */
-       add     SG_NEXT0,SG_SIZEOF,SG_NEXT0
-       adc     SG_NEXT1,A,SG_NEXT1
-
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes a little-endian host data storage.
- */
-sg_load:
-       clr     HCNT2
-       clr     HCNT1
-       mvi     HCNT0,SG_SIZEOF
-
-       mov     HADDR0,SG_NEXT0
-       mov     HADDR1,SG_NEXT1
-       mov     HADDR2,SG_NEXT2
-       mov     HADDR3,SG_NEXT3
-
-       or      DFCNTRL,0xd                     /* HDMAEN|DIRECTION|FIFORESET */
-
-/*
- * Wait for DMA from host memory to data FIFO to complete, then disable
- * DMA and wait for it to acknowledge that it's off.
- */
-dma_finish:
-       test    DFSTATUS,HDONE  jz dma_finish
-       /* Turn off DMA preserving WIDEODD */
-       and     DFCNTRL,WIDEODD
-dma_finish2:
-       test    DFCNTRL,HDMAENACK jnz dma_finish2
-
-/*
- * Copy data from FIFO into SCB data pointer and data count.  In
- * both FreeBSD and Linux, the scatter list entry is 8 bytes.
- * 
- * struct ahc_dma_seg {
- *       physaddr addr;                  four bytes, little-endian order
- *       long    len;                    four bytes, little endian order
- * };
- */
-
-       mov     HADDR0,DFDAT
-       mov     HADDR1,DFDAT
-       mov     HADDR2,DFDAT
-       mov     HADDR3,DFDAT
-       mov     HCNT0,DFDAT
-       mov     HCNT1,DFDAT
-       mov     HCNT2,DFDAT
-
-/* Load STCNT as well.  It is a mirror of HCNT */
-       mov     STCNT0,HCNT0
-       mov     STCNT1,HCNT1
-       mov     STCNT2,HCNT2
-        test    SSTAT1,PHASEMIS  jz data_phase_loop
-
-data_phase_finish:
-/*
- * After a DMA finishes, save the SG and STCNT residuals back into the SCB
- * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
- * were transferred on the SCSI (as opposed to the host) bus.
- */
-       mov     SCB_RESID_DCNT0,STCNT0
-       mov     SCB_RESID_DCNT1,STCNT1
-       mov     SCB_RESID_DCNT2,STCNT2
-       mov     SCB_RESID_SGCNT, SG_COUNT
-       jmp     ITloop
-
-data_phase_overrun:
-/*
- * Turn off BITBUCKET mode and notify the host
- */
-       and     SXFRCTL1,0x7f           /* ~BITBUCKET */
-       mvi     INTSTAT,DATA_OVERRUN
-       jmp     ITloop
-
-/*
- * Command phase.  Set up the DMA registers and let 'er rip.
- */
-p_command:
-       call    assert
-
-/*
- * Load HADDR and HCNT.
- */
-       mov     HADDR0, SCB_CMDPTR0
-       mov     HADDR1, SCB_CMDPTR1
-       mov     HADDR2, SCB_CMDPTR2
-       mov     HADDR3, SCB_CMDPTR3
-       mov     HCNT0, SCB_CMDLEN
-       clr     HCNT1
-       clr     HCNT2
-
-       mov     STCNT0, HCNT0
-       mov     STCNT1, HCNT1
-       mov     STCNT2, HCNT2
-
-       mvi     0x3d            call dma        # SCSIEN|SDMAEN|HDMAEN|
-                                               #   DIRECTION|FIFORESET
-       jmp     ITloop
-
-/*
- * Status phase.  Wait for the data byte to appear, then read it
- * and store it into the SCB.
- */
-p_status:
-       mvi     SCB_TARGET_STATUS       call inb_first
-       jmp     mesgin_done
-
-/*
- * 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.
- */
-p_mesgout:
-       test    MSG_LEN, 0xff   jnz  p_mesgout_start
-       mvi     MSG_NOP         call mk_mesg    /* build NOP message */
-
-p_mesgout_start:
-/*
- * Set up automatic PIO transfer from MSG0.  Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
- */
-       mvi     SINDEX,MSG0
-       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.
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
- */
-p_mesgout_loop:
-       test    SSTAT1,PHASEMIS jnz p_mesgout_phasemis
-       test    SSTAT0,SPIORDY  jz p_mesgout_loop
-       test    SSTAT1,PHASEMIS jnz p_mesgout_phasemis
-       cmp     DINDEX,1        jne p_mesgout_outb      /* last byte? */
-       mvi     CLRSINT1,CLRATNO                        /* drop ATN */
-p_mesgout_outb:
-       dec     DINDEX
-       or      CLRSINT0, CLRSPIORDY
-       mov     SCSIDATL,SINDIR
-       
-p_mesgout4:
-       test    DINDEX,0xff     jnz p_mesgout_loop
-
-/*
- * 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_snoop:
-       test    SSTAT1,BUSFREE  jnz p_mesgout_done
-       test    SSTAT1,REQINIT  jz p_mesgout_snoop
-
-       test    SSTAT1,PHASEMIS jnz p_mesgout_done
-
-       or      SCSISIGO,ATNO                   /* turn on ATNO */
-
-       jmp     ITloop
-
-p_mesgout_phasemis:
-       mvi     CLRSINT1,CLRATNO        /* Be sure to turn ATNO off */
-p_mesgout_done:
-       clr     MSG_LEN                 /* no active msg */
-       jmp     ITloop
-
-/*
- * Message in phase.  Bytes are read using Automatic PIO mode.
- */
-p_mesgin:
-       mvi     A               call inb_first  /* read the 1st message byte */
-       mov     REJBYTE,A                       /* save it for the driver */
-
-       test    A,MSG_IDENTIFY          jnz mesgin_identify
-       cmp     A,MSG_DISCONNECT        je mesgin_disconnect
-       cmp     A,MSG_SDPTRS            je mesgin_sdptrs
-       cmp     ALLZEROS,A              je mesgin_complete
-       cmp     A,MSG_RDPTRS            je mesgin_rdptrs
-       cmp     A,MSG_EXTENDED          je mesgin_extended
-       cmp     A,MSG_REJECT            je mesgin_reject
-
-rej_mesgin:
-/*
- * We have no idea what this message in is, and there's no way
- * to pass it up to the kernel, so we issue a message reject and
- * hope for the best.  Since we're now using manual PIO mode to
- * read in the message, there should no longer be a race condition
- * present when we assert ATN.  In any case, rejection should be a
- * rare occurrence - signal the driver when it happens.
- */
-       or      SCSISIGO,ATNO                   /* turn on ATNO */
-       mvi     INTSTAT,SEND_REJECT             /* let driver know */
-
-       mvi     MSG_REJECT      call mk_mesg
-
-mesgin_done:
-       call    inb_last                        /*ack & turn auto PIO back on*/
-       jmp     ITloop
-
-
-mesgin_complete:
-/*
- * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT,
- * and trigger a completion interrupt.  Check status for non zero return
- * and interrupt driver if needed.  This allows the driver to interpret
- * errors only when they occur instead of always uploading the scb.  If
- * the status is SCSI_CHECK, the driver will download a new scb requesting
- * sense to replace the old one, modify the "waiting for selection" SCB list
- * and set RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE the
- * sequencer imediately jumps to main loop where it will run down the waiting
- * SCB list and process the sense request.  If the kernel driver does not
- * wish to request sense, it need only clear RETURN_1, and the command is
- * allowed to complete.  We don't bother to post to the QOUTFIFO in the
- * error case since it would require extra work in the kernel driver to
- * ensure that the entry was removed before the command complete code tried
- * processing it.
- *
- * First check for residuals
- */
-       test    SCB_RESID_SGCNT,0xff    jz check_status
-/*
- * If we have a residual count, interrupt and tell the host.  Other
- * alternatives are to pause the sequencer on all command completes (yuck),
- * dma the resid directly to the host (slick, we may have space to do it now)
- * or have the sequencer pause itself when it encounters a non-zero resid 
- * (unnecessary pause just to flag the command -yuck-, but takes one instruction
- * and since it shouldn't happen that often is good enough for our purposes).  
- */
-resid:
-       mvi     INTSTAT,RESIDUAL
-
-check_status:
-       test    SCB_TARGET_STATUS,0xff  jz status_ok    /* Good Status? */
-       mvi     INTSTAT,BAD_STATUS                      /* let driver know */
-       cmp     RETURN_1, SEND_SENSE    jne status_ok
-       jmp     mesgin_done
-
-status_ok:
-/* First, mark this target as free. */
-       test    SCB_CONTROL,TAG_ENB jnz test_immediate  /*
-                                                        * Tagged commands
-                                                        * don't busy the
-                                                        * target.
-                                                        */
-       mov     FUNCTION1,SCB_TCL
-       mov     A,FUNCTION1
-       test    SCB_TCL,0x88 jz clear_a
-       xor     ACTIVE_B,A
-       jmp     test_immediate
-
-clear_a:
-       xor     ACTIVE_A,A
-
-test_immediate:
-       test    SCB_CMDLEN,0xff jnz complete  /* Immediate message complete */
-/*
- * Pause the sequencer until the driver gets around to handling the command
- * complete.  This is so that any action that might require careful timing
- * with the completion of this command can occur.
- */
-       mvi     INTSTAT,IMMEDDONE
-       jmp     start
-complete:
-       mov     QOUTFIFO,SCB_TAG
-       mvi     INTSTAT,CMDCMPLT
-       jmp     mesgin_done
-
-
-/*
- * Is it an extended message?  We only support the synchronous and wide data
- * transfer request messages, which will probably be in response to
- * WDTR or SDTR message outs from us.  If it's not SDTR or WDTR, reject it -
- * apparently this can be done after any message in byte, according
- * to the SCSI-2 spec.
- */
-mesgin_extended:
-       mvi     ARG_1           call inb_next   /* extended message length */
-       mvi     REJBYTE_EXT     call inb_next   /* extended message code */
-
-       cmp     REJBYTE_EXT,MSG_SDTR    je p_mesginSDTR
-       cmp     REJBYTE_EXT,MSG_WDTR    je p_mesginWDTR
-       jmp     rej_mesgin
-
-p_mesginWDTR:
-       cmp     ARG_1,2         jne rej_mesgin  /* extended mesg length=2 */
-       mvi     ARG_1           call inb_next   /* Width of bus */
-       mvi     INTSTAT,WDTR_MSG                /* let driver know */
-       test    RETURN_1,0xff jz mesgin_done    /* Do we need to send WDTR? */
-       cmp     RETURN_1,SEND_REJ je rej_mesgin /*
-                                                * Bus width was too large 
-                                                * Reject it.
-                                                */
-
-/* We didn't initiate the wide negotiation, so we must respond to the request */
-       and     RETURN_1,0x7f                   /* Clear the SEND_WDTR Flag */
-       mvi     DINDEX,MSG0
-       mvi     MSG0    call mk_wdtr            /* build WDTR message */
-       or      SCSISIGO,ATNO                   /* turn on ATNO */
-       jmp     mesgin_done
-
-p_mesginSDTR:
-       cmp     ARG_1,3         jne rej_mesgin  /* extended mesg length=3 */
-       mvi     ARG_1           call inb_next   /* xfer period */
-       mvi     A               call inb_next   /* REQ/ACK offset */
-       mvi     INTSTAT,SDTR_MSG                /* call driver to convert */
-
-       test    RETURN_1,0xff   jz mesgin_done  /* Do we need to mk_sdtr/rej */
-       cmp     RETURN_1,SEND_REJ je rej_mesgin /*
-                                                * Requested SDTR too small
-                                                * Reject it.
-                                                */
-       clr     ARG_1                           /* Use the scratch ram rate */
-       mvi     DINDEX, MSG0
-       mvi     MSG0     call mk_sdtr
-       or      SCSISIGO,ATNO                   /* turn on ATNO */
-       jmp     mesgin_done
-
-/*
- * Is it a disconnect message?  Set a flag in the SCB to remind us
- * and await the bus going free.
- */
-mesgin_disconnect:
-       or      SCB_CONTROL,DISCONNECTED
-       test    FLAGS, PAGESCBS jz mesgin_done
-/*
- * Link this SCB into the DISCONNECTED list.  This list holds the
- * candidates for paging out an SCB if one is needed for a new command.
- * Modifying the disconnected list is a critical(pause dissabled) section.
- */
-       mvi     SCB_PREV, SCB_LIST_NULL
-       mvi     SEQCTL,0x50                     /* PAUSEDIS|FASTMODE */
-       mov     SCB_NEXT, DISCONNECTED_SCBH
-       mov     DISCONNECTED_SCBH, SCBPTR
-       cmp     SCB_NEXT,SCB_LIST_NULL je linkdone
-       mov     SCBPTR,SCB_NEXT
-       mov     SCB_PREV,DISCONNECTED_SCBH
-       mov     SCBPTR,DISCONNECTED_SCBH
-linkdone:
-       mvi     SEQCTL,0x10                     /* !PAUSEDIS|FASTMODE */
-       jmp     mesgin_done
-
-/*
- * Save data pointers message?  Copy working values into the SCB,
- * usually in preparation for a disconnect.
- */
-mesgin_sdptrs:
-       call    sg_ram2scb
-       jmp     mesgin_done
-
-/*
- * Restore pointers message?  Data pointers are recopied from the
- * SCB anytime we enter a data phase for the first time, so all
- * we need to do is clear the DPHASE flag and let the data phase
- * code do the rest.
- */
-mesgin_rdptrs:
-       and     FLAGS,0xef                      /*
-                                                * !DPHASE we'll reload them
-                                                * the next time through
-                                                */
-       jmp     mesgin_done
-
-/*
- * Identify message?  For a reconnecting target, this tells us the lun
- * that the reconnection is for - find the correct SCB and switch to it,
- * clearing the "disconnected" bit so we don't "find" it by accident later.
- */
-mesgin_identify:
-       test    A,0x78  jnz rej_mesgin  /*!DiscPriv|!LUNTAR|!Reserved*/
-
-       and     A,0x07                  /* lun in lower three bits */
-       or      SAVED_TCL,A,SELID          
-       and     SAVED_TCL,0xf7
-       and     A,SELBUSB,SBLKCTL       /* B Channel?? */
-       or      SAVED_TCL,A
-       call    inb_last                /* ACK */
-
-/*
- * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
- * If we get one, we use the tag returned to switch to find the proper
- * SCB.  With SCB paging, this requires using findSCB 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.
- */
-       mvi     ARG_1,SCB_LIST_NULL     /* Default to no-tag */
-snoop_tag_loop:
-       test    SSTAT1,BUSFREE  jnz use_findSCB
-       test    SSTAT1,REQINIT  jz snoop_tag_loop
-       test    SSTAT1,PHASEMIS jnz use_findSCB
-       mvi     A               call inb_first
-       cmp     A,MSG_SIMPLE_TAG jne use_findSCB
-get_tag:
-       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 incoming tag and there is
- * no carry.
- */
-       mov     A,COMP_SCBCOUNT 
-       add     SINDEX,A,ARG_1
-       jc      abort_tag
-
-/*
- * Ensure that the SCB the tag points to is for a SCB transaction
- * to the reconnecting target.
- */
-       test    FLAGS, PAGESCBS jz index_by_tag
-       call    inb_last                        /* Ack Tag */
-use_findSCB:
-       mov     ALLZEROS        call findSCB      /* Have to search */
-setup_SCB:
-       and     SCB_CONTROL,0xfb          /* clear disconnect bit in SCB */
-       or      FLAGS,IDENTIFY_SEEN       /* make note of IDENTIFY */
-       jmp     ITloop
-index_by_tag:
-       mov     SCBPTR,ARG_1
-       mov     A,SAVED_TCL
-       cmp     SCB_TCL,A               jne abort_tag
-       test    SCB_CONTROL,TAG_ENB     jz  abort_tag
-       call    inb_last                        /* Ack Successful tag */
-       jmp     setup_SCB
-
-abort_tag:
-       or      SCSISIGO,ATNO                   /* turn on ATNO */
-       mvi     INTSTAT,ABORT_TAG               /* let driver know */
-       mvi     MSG_ABORT_TAG   call mk_mesg    /* ABORT TAG message */
-       jmp     mesgin_done
-
-/*
- * Message reject?  Let the kernel driver handle this.  If we have an 
- * outstanding WDTR or SDTR negotiation, assume that it's a response from 
- * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
- * it since we have no clue what it pertains to.
- */
-mesgin_reject:
-       mvi     INTSTAT, REJECT_MSG
-       jmp     mesgin_done
-
-/*
- * [ ADD MORE MESSAGE HANDLING HERE ]
- */
-
-/*
- * Bus free phase.  It might be useful to interrupt the device
- * driver if we aren't expecting this.  For now, make sure that
- * ATN isn't being asserted and look for a new command.
- */
-p_busfree:
-       mvi     CLRSINT1,CLRATNO
-       clr     LASTPHASE
-
-/*
- * if this is an immediate command, perform a pseudo command complete to
- * notify the driver.
- */
-       test    SCB_CMDLEN,0xff jz status_ok
-       jmp     start
-
-/*
- * Locking the driver out, build a one-byte message passed in SINDEX
- * if there is no active message already.  SINDEX is returned intact.
- */
-mk_mesg:
-       mvi     SEQCTL,0x50                     /* 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,0x10                     /* !PAUSEDIS|FASTMODE */
-       mvi     INTSTAT,MSG_BUFFER_BUSY
-
-mk_mesg1:
-       mvi     MSG_LEN,1               /* length = 1 */
-       mov     MSG0,SINDEX             /* 1-byte message */
-       mvi     SEQCTL,0x10     ret     /* !PAUSEDIS|FASTMODE */
-
-/*
- * Functions to read data in Automatic PIO mode.
- *
- * According to Adaptec's documentation, an ACK is not sent on input from
- * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
- * latched (the usual way), then read the data byte directly off the bus
- * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
- * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
- * spec guarantees that the target will hold the data byte on the bus until
- * we send our ACK.
- *
- * The assumption here is that these are called in a particular sequence,
- * and that REQ is already set when inb_first is called.  inb_{first,next}
- * use the same calling convention as inb.
- */
-
-inb_next:
-       or      CLRSINT0, CLRSPIORDY
-       mov     NONE,SCSIDATL                   /*dummy read from latch to ACK*/
-inb_next_wait:
-       test    SSTAT1,PHASEMIS jnz mesgin_phasemis
-       test    SSTAT0,SPIORDY  jz inb_next_wait /* wait for next byte */
-inb_first:
-       mov     DINDEX,SINDEX
-       test    SSTAT1,PHASEMIS jnz mesgin_phasemis
-       mov     DINDIR,SCSIBUSL ret             /*read byte directly from bus*/
-inb_last:
-       mov     NONE,SCSIDATL ret               /*dummy read from latch to ACK*/
-
-mesgin_phasemis:
-/*
- * We expected to receive another byte, but the target changed phase
- */
-       mvi     INTSTAT, MSGIN_PHASEMIS
-       jmp     ITloop
-
-/*
- * DMA data transfer.  HADDR and HCNT must be loaded first, and
- * SINDEX should contain the value to load DFCNTRL with - 0x3d for
- * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
- * during initialization.
- */
-dma:
-       mov     DFCNTRL,SINDEX
-dma1:
-       test    SSTAT0,DMADONE  jnz dma3
-       test    SSTAT1,PHASEMIS jz dma1         /* ie. underrun */
-
-/*
- * We will be "done" DMAing when the transfer count goes to zero, or
- * the target changes the phase (in light of this, it makes sense that
- * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
- * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
- * magically on STCNT=0 or a phase change, so just wait for FIFO empty
- * status.
- */
-dma3:
-       test    SINDEX,DIRECTION        jnz dma5
-dma4:
-       test    DFSTATUS,FIFOEMP        jz dma4
-
-/*
- * Now shut the DMA enables off and make sure that the DMA enables are 
- * actually off first lest we get an ILLSADDR.
- */
-dma5:
-       /* disable DMA, but maintain WIDEODD */
-       and     DFCNTRL,WIDEODD
-dma6:
-       test    DFCNTRL,0x38    jnz dma6  /* SCSIENACK|SDMAENACK|HDMAENACK */
-
-       ret
-
-/*
- * Common SCSI initialization for selection and reselection.  Expects
- * the target SCSI ID to be in the upper four bits of SINDEX, and A's
- * contents are stomped on return.
- */
-initialize_scsiid:
-       and     SINDEX,0xf0             /* Get target ID */
-       and     A,0x0f,SCSIID
-       or      SINDEX,A
-       mov     SCSIID,SINDEX ret
-
-/*
- * Assert that if we've been reselected, then we've seen an IDENTIFY
- * message.
- */
-assert:
-       test    FLAGS,RESELECTED        jz return       /* reselected? */
-       test    FLAGS,IDENTIFY_SEEN     jnz return      /* seen IDENTIFY? */
-
-       mvi     INTSTAT,NO_IDENT        ret     /* no - cause a kernel panic */
-
-/*
- * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag
- * value in ARG_1.  If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged
- * SCB.  Have the kernel print a warning message if it can't be found, and
- * generate an ABORT/ABORT_TAG message to the target.  SINDEX should be
- * cleared on call.
- */
-findSCB:
-       mov     A,SAVED_TCL
-       mov     SCBPTR,SINDEX                   /* switch to next SCB */
-       mvi     SEQCTL,0x50                     /* PAUSEDIS|FASTMODE */
-       cmp     SCB_TCL,A       jne findSCB1 /* target ID/channel/lun match? */
-       test    SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
-       test    SCB_CONTROL,TAG_ENB jnz findTaggedSCB
-       cmp     ARG_1,SCB_LIST_NULL je foundSCB
-       jmp     findSCB1
-findTaggedSCB:
-       mov     A, ARG_1                        /* Tag passed in ARG_1 */
-       cmp     SCB_TAG,A       jne findSCB1    /* Found it? */
-foundSCB:
-       test    FLAGS,PAGESCBS  jz foundSCB_ret
-/* Remove this SCB from the disconnection list */
-       cmp     SCB_NEXT,SCB_LIST_NULL je unlink_prev
-       mov     SAVED_LINKPTR, SCB_PREV
-       mov     SCBPTR, SCB_NEXT
-       mov     SCB_PREV, SAVED_LINKPTR
-       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     SCBPTR, SCB_PREV
-       mov     SCB_NEXT, SAVED_LINKPTR
-       mov     SCBPTR, SINDEX
-       mvi     SEQCTL,0x10     ret             /* !PAUSEDIS|FASTMODE */
-rHead:
-       mov     DISCONNECTED_SCBH,SCB_NEXT
-foundSCB_ret:
-       mvi     SEQCTL,0x10     ret             /* !PAUSEDIS|FASTMODE */
-
-findSCB1:
-       mvi     SEQCTL,0x10                     /* !PAUSEDIS|FASTMODE */
-       inc     SINDEX
-       mov     A,SCBCOUNT
-       cmp     SINDEX,A        jne findSCB
-
-       mvi     INTSTAT,NO_MATCH                /* not found - signal kernel */
-       cmp     RETURN_1,SCB_PAGEDIN je return
-       or      SCSISIGO,ATNO                   /* assert ATNO */
-       cmp     ARG_1,SCB_LIST_NULL jne find_abort_tag
-       mvi     MSG_ABORT       call mk_mesg
-       jmp     ITloop
-find_abort_tag:
-       mvi     MSG_ABORT_TAG   call mk_mesg
-       jmp     ITloop
-
-/*
- * Make a working copy of the scatter-gather parameters from the SCB.
- */
-sg_scb2ram:
-       mov     HADDR0, SCB_DATAPTR0
-       mov     HADDR1, SCB_DATAPTR1
-       mov     HADDR2, SCB_DATAPTR2
-       mov     HADDR3, SCB_DATAPTR3
-       mov     HCNT0, SCB_DATACNT0
-       mov     HCNT1, SCB_DATACNT1
-       mov     HCNT2, SCB_DATACNT2
-
-       mov     STCNT0, HCNT0
-       mov     STCNT1, HCNT1
-       mov     STCNT2, HCNT2
-
-       mov     SG_COUNT,SCB_SGCOUNT
-
-       mov     SG_NEXT0, SCB_SGPTR0
-       mov     SG_NEXT1, SCB_SGPTR1
-       mov     SG_NEXT2, SCB_SGPTR2
-       mov     SG_NEXT3, SCB_SGPTR3 ret
-
-/*
- * Copying RAM values back to SCB, for Save Data Pointers message, but
- * only if we've actually been into a data phase to change them.  This
- * protects against bogus data in scratch ram and the residual counts
- * since they are only initialized when we go into data_in or data_out.
- */
-sg_ram2scb:
-       test    FLAGS, DPHASE   jz return
-       mov     SCB_SGCOUNT,SG_COUNT
-
-       mov     SCB_SGPTR0,SG_NEXT0
-       mov     SCB_SGPTR1,SG_NEXT1
-       mov     SCB_SGPTR2,SG_NEXT2
-       mov     SCB_SGPTR3,SG_NEXT3
-       
-       mov     SCB_DATAPTR0,SHADDR0
-       mov     SCB_DATAPTR1,SHADDR1
-       mov     SCB_DATAPTR2,SHADDR2
-       mov     SCB_DATAPTR3,SHADDR3
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer
- */
-       mov     SCB_DATACNT0,SCB_RESID_DCNT0
-       mov     SCB_DATACNT1,SCB_RESID_DCNT1
-       mov     SCB_DATACNT2,SCB_RESID_DCNT2 ret
-
-/*
- * Add the array base TARG_SCRATCH to the target offset (the target address
- * is in SCSIID), and return the result in SINDEX.  The accumulator
- * contains the 3->8 decoding of the target ID on return.
- */
-ndx_dtr:
-       shr     A,SCSIID,4
-       test    SBLKCTL,SELBUSB jz ndx_dtr_2
-       or      A,0x08          /* Channel B entries add 8 */
-ndx_dtr_2:
-       add     SINDEX,TARG_SCRATCH,A ret
-
-/*
- * If we need to negotiate transfer parameters, build the WDTR or SDTR message
- * starting at the address passed in SINDEX.  DINDEX is modified on return.
- * The SCSI-II spec requires that Wide negotiation occur first and you can
- * only negotiate one or the other at a time otherwise in the event of a message
- * reject, you wouldn't be able to tell which message was the culprit.
- */
-mk_dtr:
-       test    SCB_CONTROL,NEEDWDTR jnz  mk_wdtr_16bit
-       mvi     ARG_1, MAXOFFSET        /* Force an offset of 15 or 8 if WIDE */
-
-mk_sdtr:
-       mvi     DINDIR,1                /* extended message */
-       mvi     DINDIR,3                /* extended message length = 3 */
-       mvi     DINDIR,1                /* SDTR code */
-       call    sdtr_to_rate
-       mov     DINDIR,RETURN_1         /* REQ/ACK transfer period */
-       cmp     ARG_1, MAXOFFSET je mk_sdtr_max_offset
-       and     DINDIR,0x0f,SINDIR      /* Sync Offset */
-
-mk_sdtr_done:
-       add     MSG_LEN,COMP_MSG0,DINDEX ret    /* update message length */
-
-mk_sdtr_max_offset:
-/*
- * We're initiating sync negotiation, so request the max offset we can (15 or 8)
- */
-       /* Talking to a WIDE device? */
-       test    SCSIRATE, WIDEXFER      jnz wmax_offset 
-       mvi     DINDIR, MAX_OFFSET_8BIT
-       jmp     mk_sdtr_done
-
-wmax_offset:
-       mvi     DINDIR, MAX_OFFSET_16BIT
-       jmp     mk_sdtr_done
-
-mk_wdtr_16bit:
-       mvi     ARG_1,BUS_16_BIT
-mk_wdtr:
-       mvi     DINDIR,1                /* extended message */
-       mvi     DINDIR,2                /* extended message length = 2 */
-       mvi     DINDIR,3                /* WDTR code */
-       mov     DINDIR,ARG_1            /* bus width */
-
-       add     MSG_LEN,COMP_MSG0,DINDEX ret    /* update message length */
-       
-sdtr_to_rate:
-       call    ndx_dtr                 /* index scratch space for target */
-       shr     A,SINDIR,0x4
-       dec     SINDEX                  /* Preserve SINDEX */
-       and     A,0x7
-       clr     RETURN_1
-sdtr_to_rate_loop:
-       test    A,0x0f  jz sdtr_to_rate_done
-       add     RETURN_1,0x19
-       dec     A       
-       jmp     sdtr_to_rate_loop
-sdtr_to_rate_done:
-       shr     RETURN_1,0x2
-       add     RETURN_1,0x19
-       test    SXFRCTL0,ULTRAEN jz return
-       shr     RETURN_1,0x1
-return:
-       ret
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
new file mode 100644 (file)
index 0000000..fcde1ca
--- /dev/null
@@ -0,0 +1,1120 @@
+/*
+ * Aic7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     $Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $
+ */
+
+/*
+ * This file is processed by the aic7xxx_asm utility for use in assembling
+ * firmware for the aic7xxx family of SCSI host adapters as well as to generate
+ * a C header file for use in the kernel portion of the Aic7xxx driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+register SCSISEQ {
+       address                 0x000
+       access_mode RW
+       bit     TEMODE          0x80
+       bit     ENSELO          0x40
+       bit     ENSELI          0x20
+       bit     ENRSELI         0x10
+       bit     ENAUTOATNO      0x08
+       bit     ENAUTOATNI      0x04
+       bit     ENAUTOATNP      0x02
+       bit     SCSIRSTO        0x01
+}
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL0 {
+       address                 0x001
+       access_mode RW
+       bit     DFON            0x80
+       bit     DFPEXP          0x40
+       bit     FAST20          0x20
+       bit     CLRSTCNT        0x10
+       bit     SPIOEN          0x08
+       bit     SCAMEN          0x04
+       bit     CLRCHN          0x02
+}
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL1 {
+       address                 0x002
+       access_mode RW
+       bit     BITBUCKET       0x80
+       bit     SWRAPEN         0x40
+       bit     ENSPCHK         0x20
+       mask    STIMESEL        0x18
+       bit     ENSTIMER        0x04
+       bit     ACTNEGEN        0x02
+       bit     STPWEN          0x01    /* Powered Termination */
+}
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+register SCSISIGI {
+       address                 0x003
+       access_mode RO
+       bit     CDI             0x80
+       bit     IOI             0x40
+       bit     MSGI            0x20
+       bit     ATNI            0x10
+       bit     SELI            0x08
+       bit     BSYI            0x04
+       bit     REQI            0x02
+       bit     ACKI            0x01
+/*
+ * Possible phases in SCSISIGI
+ */
+       mask    PHASE_MASK      CDI|IOI|MSGI
+       mask    P_DATAOUT       0x00
+       mask    P_DATAIN        IOI
+       mask    P_COMMAND       CDI
+       mask    P_MESGOUT       CDI|MSGI
+       mask    P_STATUS        CDI|IOI
+       mask    P_MESGIN        CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Control Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus.  Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+register SCSISIGO {
+       address                 0x003
+       access_mode WO
+       bit     CDO             0x80
+       bit     IOO             0x40
+       bit     MSGO            0x20
+       bit     ATNO            0x10
+       bit     SELO            0x08
+       bit     BSYO            0x04
+       bit     REQO            0x02
+       bit     ACKO            0x01
+/*
+ * Possible phases to write into SCSISIG0
+ */
+       mask    PHASE_MASK      CDI|IOI|MSGI
+       mask    P_DATAOUT       0x00
+       mask    P_DATAIN        IOI
+       mask    P_COMMAND       CDI
+       mask    P_MESGOUT       CDI|MSGI
+       mask    P_STATUS        CDI|IOI
+       mask    P_MESGIN        CDI|IOI|MSGI
+}
+
+/* 
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+register SCSIRATE {
+       address                 0x004
+       access_mode RW
+       bit     WIDEXFER        0x80            /* Wide transfer control */
+       mask    SXFR            0x70            /* Sync transfer rate */
+       mask    SOFS            0x0f            /* Sync offset */
+}
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+register SCSIID        {
+       address                 0x005
+       access_mode RW
+       mask    TID             0xf0            /* Target ID mask */
+       mask    OID             0x0f            /* Our ID mask */
+}
+
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latches used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode.  SCSIDATH can be used for the
+ * upper byte of a 16bit wide asynchronouse data phase transfer.
+ */
+register SCSIDATL {
+       address                 0x006
+       access_mode RW
+}
+
+register SCSIDATH {
+       address                 0x007
+       access_mode RW
+}
+
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transferred
+ * across the SCSI bus.  The counter is decremented only once
+ * the data has been safely transferred.  SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */ 
+register STCNT {
+       address                 0x008
+       size    3
+       access_mode RW
+}
+
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+register CLRSINT0 {
+       address                 0x00b
+       access_mode WO
+       bit     CLRSELDO        0x40
+       bit     CLRSELDI        0x20
+       bit     CLRSELINGO      0x10
+       bit     CLRSWRAP        0x08
+       bit     CLRSPIORDY      0x02
+}
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+register SSTAT0        {
+       address                 0x00b
+       access_mode RO
+       bit     TARGET          0x80            /* Board acting as target */
+       bit     SELDO           0x40            /* Selection Done */
+       bit     SELDI           0x20            /* Board has been selected */
+       bit     SELINGO         0x10            /* Selection In Progress */
+       bit     SWRAP           0x08            /* 24bit counter wrap */
+       bit     SDONE           0x04            /* STCNT = 0x000000 */
+       bit     SPIORDY         0x02            /* SCSI PIO Ready */
+       bit     DMADONE         0x01            /* DMA transfer completed */
+}
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+register CLRSINT1 {
+       address                 0x00c
+       access_mode WO
+       bit     CLRSELTIMEO     0x80
+       bit     CLRATNO         0x40
+       bit     CLRSCSIRSTI     0x20
+       bit     CLRBUSFREE      0x08
+       bit     CLRSCSIPERR     0x04
+       bit     CLRPHASECHG     0x02
+       bit     CLRREQINIT      0x01
+}
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+register SSTAT1        {
+       address                 0x00c
+       access_mode RO
+       bit     SELTO           0x80
+       bit     ATNTARG         0x40
+       bit     SCSIRSTI        0x20
+       bit     PHASEMIS        0x10
+       bit     BUSFREE         0x08
+       bit     SCSIPERR        0x04
+       bit     PHASECHG        0x02
+       bit     REQINIT         0x01
+}
+
+/*
+ * SCSI Status 2 (pp. 3-25,26)
+ */
+register SSTAT2 {
+       address                 0x00d
+       access_mode RO
+       bit     OVERRUN         0x80
+       mask    SFCNT           0x1f
+}
+
+/*
+ * SCSI Status 3 (p. 3-26)
+ */
+register SSTAT3 {
+       address                 0x00e
+       access_mode RO
+       mask    SCSICNT         0xf0
+       mask    OFFCNT          0x0f
+}
+
+/*
+ * SCSI Test Control (p. 3-27)
+ */
+register SCSITEST {
+       address                 0x00f
+       access_mode RW
+       bit     RQAKCNT         0x04
+       bit     CNTRTEST        0x02
+       bit     CMODE           0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (p. 3-28)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE0 to interrupt via the IRQ pin.
+ */
+register SIMODE0 {
+       address                 0x010
+       access_mode RW
+       bit     ENSELDO         0x40
+       bit     ENSELDI         0x20
+       bit     ENSELINGO       0x10
+       bit     ENSWRAP         0x08
+       bit     ENSDONE         0x04
+       bit     ENSPIORDY       0x02
+       bit     ENDMADONE       0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+register SIMODE1 {
+       address                 0x011
+       access_mode RW
+       bit     ENSELTIMO       0x80
+       bit     ENATNTARG       0x40
+       bit     ENSCSIRST       0x20
+       bit     ENPHASEMIS      0x10
+       bit     ENBUSFREE       0x08
+       bit     ENSCSIPERR      0x04
+       bit     ENPHASECHG      0x02
+       bit     ENREQINIT       0x01
+}
+
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+register SCSIBUSL {
+       address                 0x012
+       access_mode RO
+}
+
+register SCSIBUSH {
+       address                 0x013
+       access_mode RO
+}
+
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transferred on the SCSI bus.  They are counted up in the same
+ * manner as STCNT is counted down.  SHADDR should always be used
+ * to determine the address of the last byte transferred since HADDR
+ * can be skewed by write ahead.
+ */
+register SHADDR {
+       address                 0x014
+       size    4
+       access_mode RO
+}
+
+/*
+ * Selection Timeout Timer (p. 3-30)
+ */
+register SELTIMER {
+       address                 0x018
+       access_mode RW
+       bit     STAGE6          0x20
+       bit     STAGE5          0x10
+       bit     STAGE4          0x08
+       bit     STAGE3          0x04
+       bit     STAGE2          0x02
+       bit     STAGE1          0x01
+}
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+register SELID {
+       address                 0x019
+       access_mode RW
+       mask    SELID_MASK      0xf0
+       bit     ONEBIT          0x08
+}
+
+/*
+ * 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
+ * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+register SBLKCTL {
+       address                 0x01f
+       access_mode RW
+       bit     DIAGLEDEN       0x80    /* Aic78X0 only */
+       bit     DIAGLEDON       0x40    /* Aic78X0 only */
+       bit     AUTOFLUSHDIS    0x20
+       bit     SELBUSB         0x08
+       bit     SELWIDE         0x02
+}
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+register SEQCTL {
+       address                 0x060
+       access_mode RW
+       bit     PERRORDIS       0x80
+       bit     PAUSEDIS        0x40
+       bit     FAILDIS         0x20
+       bit     FASTMODE        0x10
+       bit     BRKADRINTEN     0x08
+       bit     STEP            0x04
+       bit     SEQRESET        0x02
+       bit     LOADRAM         0x01
+}
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
+ * four bytes in sucessesion.  The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+register SEQRAM {
+       address                 0x061
+       access_mode RW
+}
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+register SEQADDR0 {
+       address                 0x062
+       access_mode RW
+}
+
+register SEQADDR1 {
+       address                 0x063
+       access_mode RW
+       mask    SEQADDR1_MASK   0x01
+}
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+register ACCUM {
+       address                 0x064
+       access_mode RW
+       accumulator
+}
+
+register SINDEX        {
+       address                 0x065
+       access_mode RW
+       sindex
+}
+
+register DINDEX {
+       address                 0x066
+       access_mode RW
+}
+
+register ALLONES {
+       address                 0x069
+       access_mode RO
+       allones
+}
+
+register ALLZEROS {
+       address                 0x06a
+       access_mode RO
+       allzeros
+}
+
+register NONE {
+       address                 0x06a
+       access_mode WO
+       none
+}
+
+register FLAGS {
+       address                 0x06b
+       access_mode RO
+       bit     ZERO            0x02
+       bit     CARRY           0x01
+}
+
+register SINDIR        {
+       address                 0x06c
+       access_mode RO
+}
+
+register DINDIR         {
+       address                 0x06d
+       access_mode WO
+}
+
+register FUNCTION1 {
+       address                 0x06e
+       access_mode RW
+}
+
+register STACK {
+       address                 0x06f
+       access_mode RO
+}
+
+/*
+ * Board Control (p. 3-43)
+ */
+register BCTL {
+       address                 0x084
+       access_mode RW
+       bit     ACE             0x08
+       bit     ENABLE          0x01
+}
+
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+register DSCOMMAND {
+       address                 0x084
+       access_mode RW
+       bit     CACHETHEN       0x80    /* Cache Threshold enable */
+       bit     DPARCKEN        0x40    /* Data Parity Check Enable */
+       bit     MPARCKEN        0x20    /* Memory Parity Check Enable */
+       bit     EXTREQLCK       0x10    /* External Request Lock */
+}
+
+/*
+ * Bus On/Off Time (p. 3-44)
+ */
+register BUSTIME {
+       address                 0x085
+       access_mode RW
+       mask    BOFF            0xf0
+       mask    BON             0x0f
+}
+
+/*
+ * Bus Speed (p. 3-45)
+ */
+register BUSSPD {
+       address                 0x086
+       access_mode RW
+       mask    DFTHRSH         0xc0
+       mask    STBOFF          0x38
+       mask    STBON           0x07
+       mask    DFTHRSH_100     0xc0
+}
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overall host control of the device.
+ */
+register HCNTRL {
+       address                 0x087
+       access_mode RW
+       bit     POWRDN          0x40
+       bit     SWINT           0x10
+       bit     IRQMS           0x08
+       bit     PAUSE           0x04
+       bit     INTEN           0x02
+       bit     CHIPRST         0x01
+       bit     CHIPRSTACK      0x01
+}
+
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transferred across the host bus.
+ */
+register HADDR {
+       address                 0x088
+       size    4
+       access_mode RW
+}
+
+register HCNT {
+       address                 0x08c
+       size    3
+       access_mode RW
+}
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+register SCBPTR {
+       address                 0x090
+       access_mode RW
+}
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+register INTSTAT {
+       address                 0x091
+       access_mode RW
+       bit     BRKADRINT 0x08
+       bit     SCSIINT   0x04
+       bit     CMDCMPLT  0x02
+       bit     SEQINT    0x01
+       mask    BAD_PHASE       SEQINT          /* unknown scsi bus phase */
+       mask    SEND_REJECT     0x10|SEQINT     /* sending a message reject */
+       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    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
+                                                */
+       mask    MSGIN_PHASEMIS  0xd0|SEQINT     /*
+                                                * Target changed phase on us
+                                                * when we were expecting
+                                                * another msgin byte.
+                                                */
+       mask    DATA_OVERRUN    0xe0|SEQINT     /*
+                                                * Target attempted to write
+                                                * beyond the bounds of its
+                                                * command.
+                                                */
+
+       mask    SEQINT_MASK     0xf0|SEQINT     /* SEQINT Status Codes */
+       mask    INT_PEND  (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
+}
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors.  You usually cannot recover from
+ * these without a full board reset.
+ */
+register ERROR {
+       address                 0x092
+       access_mode RO
+       bit     PARERR          0x08
+       bit     ILLOPCODE       0x04
+       bit     ILLSADDR        0x02
+       bit     ILLHADDR        0x01
+}
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+register CLRINT {
+       address                 0x092
+       access_mode WO
+       bit     CLRBRKADRINT    0x08
+       bit     CLRSCSIINT      0x04
+       bit     CLRCMDINT       0x02
+       bit     CLRSEQINT       0x01
+}
+
+register DFCNTRL {
+       address                 0x093
+       access_mode RW
+       bit     WIDEODD         0x40
+       bit     SCSIEN          0x20
+       bit     SDMAEN          0x10
+       bit     SDMAENACK       0x10
+       bit     HDMAEN          0x08
+       bit     HDMAENACK       0x08
+       bit     DIRECTION       0x04
+       bit     FIFOFLUSH       0x02
+       bit     FIFORESET       0x01
+}
+
+register DFSTATUS {
+       address                 0x094
+       access_mode RO
+       bit     DWORDEMP        0x20
+       bit     MREQPEND        0x10
+       bit     HDONE           0x08
+       bit     DFTHRESH        0x04
+       bit     FIFOFULL        0x02
+       bit     FIFOEMP         0x01
+}
+
+register DFDAT {
+       address                 0x099
+       access_mode RW
+}
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+register SCBCNT {
+       address                 0x09a
+       access_mode RW
+       bit     SCBAUTO         0x80
+       mask    SCBCNT_MASK     0x1f
+}
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+register QINFIFO {
+       address                 0x09b
+       access_mode RW
+}
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+register QINCNT        {
+       address                 0x09c
+       access_mode RO
+}
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+register QOUTFIFO {
+       address                 0x09d
+       access_mode WO
+}
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+register QOUTCNT {
+       address                 0x09e
+       access_mode RO
+}
+
+/*
+ * SCB Definition (p. 5-4)
+ */
+scb {
+       address                 0x0a0
+       SCB_CONTROL {
+               size    1
+               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
+       }
+       SCB_TCL {
+               size    1
+               bit     SELBUSB         0x08
+               mask    TID             0xf0
+               mask    LID             0x07
+       }
+       SCB_TARGET_STATUS {
+               size    1
+       }
+       SCB_SGCOUNT {
+               size    1
+       }
+       SCB_SGPTR {
+               size    4
+       }
+       SCB_RESID_SGCNT {
+               size    1
+       }
+       SCB_RESID_DCNT  {
+               size    3
+       }
+       SCB_DATAPTR {
+               size    4
+       }
+       SCB_DATACNT {
+               size    3
+       }
+       SCB_LINKED_NEXT {
+               size    1
+       }
+       SCB_CMDPTR {
+               size    4
+       }
+       SCB_CMDLEN {
+               size    1
+       }
+       SCB_TAG {
+               size    1
+       }
+       SCB_NEXT {
+               size    1
+       }
+       SCB_PREV {
+               size    1
+       }
+       SCB_BUSYTARGETS {
+               size    4
+       }
+}
+
+const  SG_SIZEOF       0x08            /* sizeof(struct ahc_dma) */
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+register SEECTL_2840 {
+       address                 0x0c0
+       access_mode RW
+       bit     CS_2840         0x04
+       bit     CK_2840         0x02
+       bit     DO_2840         0x01
+}
+
+register STATUS_2840 {
+       address                 0x0c1
+       access_mode RW
+       bit     EEPROM_TF       0x80
+       mask    BIOS_SEL        0x60
+       mask    ADSEL           0x1e
+       bit     DI_2840         0x01
+}
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+register DSPCISTATUS {
+       address                 0x086
+}
+
+register BRDCTL        {
+       address                 0x01d
+       bit     BRDDAT7         0x80
+       bit     BRDDAT6         0x40
+       bit     BRDDAT5         0x20
+       bit     BRDSTB          0x10
+       bit     BRDCS           0x08
+       bit     BRDRW           0x04
+       bit     BRDCTL1         0x02
+       bit     BRDCTL0         0x01
+}
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  
+ *
+ * After successful arbitration for the memory port, the SEECS bit of 
+ * the SEECTL register is connected to the chip select.  The SEECK, 
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in 
+ * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
+ * gives us an 800 nsec timer.  After a write to the SEECTL register, 
+ * the SEERDY goes high 800 nsec later.  The one exception to this is 
+ * when we first request access to the memory port.  The SEERDY goes 
+ * high to signify that access has been granted and, for this case, has 
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to 
+ * read the serial EEPROM.
+ */
+register SEECTL {
+       address                 0x01e
+       bit     EXTARBACK       0x80
+       bit     EXTARBREQ       0x40
+       bit     SEEMS           0x20
+       bit     SEERDY          0x10
+       bit     SEECS           0x08
+       bit     SEECK           0x04
+       bit     SEEDO           0x02
+       bit     SEEDI           0x01
+}
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, writing the synchronous negotiation results
+ * on top of the BIOS values, so we re-use those for our per-target
+ * scratchspace (actually a value that can be copied directly into
+ * SCSIRATE).  The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space.  This should work regardless of
+ * whether the bios has been installed.
+ */
+
+scratch_ram {
+       address                 0x020
+
+       /*
+        * 1 byte per target starting at this address for configuration values
+        */
+       TARG_SCRATCH {
+               size            16
+       }
+       ULTRA_ENB {
+               size            2
+       }
+       /*
+        * Bit vector of targets that have disconnection disabled.
+        */
+       DISC_DSB {
+               size            2
+       }
+       /*
+        * Length of pending message
+        */
+       MSG_LEN {
+               size            1
+       }
+       /* We reserve 8bytes to store outgoing messages */
+       MSG_OUT {
+               size            8
+       }
+       /* Parameters for DMA Logic */
+       DMAPARAMS {
+               size            1
+               bit     WIDEODD         0x40
+               bit     SCSIEN          0x20
+               bit     SDMAEN          0x10
+               bit     SDMAENACK       0x10
+               bit     HDMAEN          0x08
+               bit     HDMAENACK       0x08
+               bit     DIRECTION       0x04
+               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     DPHASE          0x10
+               bit     PAGESCBS        0x04
+               bit     WIDE_BUS        0x02
+               bit     TWIN_BUS        0x01
+       }
+       /*
+        * Temporary storage for the
+        * target/channel/lun of a
+        * reconnecting target
+        */
+       SAVED_TCL {
+               size            1
+       }
+       SG_COUNT {
+               size            1
+       }
+       /* 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 {
+               size            1
+               bit     CDI             0x80
+               bit     IOI             0x40
+               bit     MSGI            0x20
+               mask    PHASE_MASK      CDI|IOI|MSGI
+               mask    P_DATAOUT       0x00
+               mask    P_DATAIN        IOI
+               mask    P_COMMAND       CDI
+               mask    P_MESGOUT       CDI|MSGI
+               mask    P_STATUS        CDI|IOI
+               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.
+        */
+       MSGIN_EXT_BYTES {
+               size            3
+       }
+       /*
+        * head of list of SCBs that are
+        * disconnected.  Used for SCB
+        * paging.
+        */
+       DISCONNECTED_SCBH {
+               size            1
+       }
+       /*
+        * head of list of SCBs that are
+        * not in use.  Used for SCB paging.
+        */
+       FREE_SCBH {
+               size            1
+       }
+       HSCB_ADDR {
+               size            4
+       }
+       CUR_SCBID {
+               size            1
+       }
+       ARG_1 {
+               size            1
+               mask    SEND_MSG        0x80
+               mask    SEND_SENSE      0x40
+               mask    SEND_REJ        0x20
+               alias   RETURN_1
+       }
+       /*
+        * These are reserved registers in the card's scratch ram.  Some of
+        * the values are specified in the AHA2742 technical reference manual
+        * and are initialized by the BIOS at boot time.
+        */
+       SCSICONF {
+               address         0x05a
+               size            1
+               bit     RESET_SCSI      0x40
+       }
+       HOSTCONF {
+               address         0x05d
+               size            1
+       }
+       HA_274_BIOSCTRL {
+               address         0x05f
+               size            1
+               mask    BIOSMODE                0x30
+               mask    BIOSDISABLED            0x30    
+               bit     CHANNEL_B_PRIMARY       0x08
+       }
+}
+
+const SCB_LIST_NULL    0xff
+
+
+/* WDTR Message values */
+const BUS_8_BIT                0x00
+const BUS_16_BIT               0x01
+const BUS_32_BIT               0x02
+const MAX_OFFSET_8BIT          0x0f
+const MAX_OFFSET_16BIT 0x08
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
new file mode 100644 (file)
index 0000000..a5722f1
--- /dev/null
@@ -0,0 +1,1147 @@
+/*
+ * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     $Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
+ */
+
+#include <aic7xxx.reg>
+#include <scsi_message.h>
+
+/*
+ * A few words on the waiting SCB list:
+ * After starting the selection hardware, we check for reconnecting targets
+ * as well as for our selection to complete just in case the reselection wins
+ * bus arbitration.  The problem with this is that we must keep track of the
+ * SCB that we've already pulled from the QINFIFO and started the selection
+ * on just in case the reselection wins so that we can retry the selection at
+ * a later time.  This problem cannot be resolved by holding a single entry
+ * in scratch ram since a reconnecting target can request sense and this will
+ * create yet another SCB waiting for selection.  The solution used here is to 
+ * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
+ * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
+ * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
+ * this list everytime a request sense occurs or after completing a non-tagged
+ * command for which a second SCB has been queued.  The sequencer will
+ * 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 */
+       mvi     SCSISEQ, ENRSELI|ENAUTOATNP;
+       call    clear_target_state;
+poll_for_work:
+       test    SSTAT0,SELDO    jnz select;
+       test    SSTAT0,SELDI    jnz reselect;
+       test    SCSISEQ, ENSELO jnz poll_for_work;
+.if ( TWIN_CHANNEL )
+       /*
+        * Twin channel devices cannot handle things like SELTO
+        * interrupts on the "background" channel.  So, if we
+        * are selecting, keep polling the current channel util
+        * 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    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;
+
+/*
+ * We have at least one queued SCB now and we don't have any 
+ * SCBs in the list of SCBs awaiting selection.  If we have
+ * any SCBs available for use, pull the tag from the QINFIFO
+ * and get to work on it.
+ */
+.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;
+.if !( SCB_PAGING )
+       /* In the non-paging case, the SCBID == hardware SCB index */
+       mov     SCBPTR, CUR_SCBID;
+.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;
+
+start_scb:
+       /*
+        * Place us on the waiting list in case our selection
+        * doesn't win during bus arbitration.
+        */
+       mov     SCB_NEXT,WAITING_SCBH;
+       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.
+        */
+       mov     SCBPTR, WAITING_SCBH;
+       call    start_selection;
+       jmp     poll_for_work;
+
+start_selection:
+.if ( TWIN_CHANNEL )
+       and     SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */
+       and     A,SELBUSB,SCB_TCL;      /* Get new channel bit */
+       or      SINDEX,A;
+       mov     SBLKCTL,SINDEX;         /* select channel */
+.endif
+initialize_scsiid:
+       and     A, TID, SCB_TCL;        /* Get target ID */
+       and     SCSIID, OID;            /* Clear old target */
+       or      SCSIID, A;
+       mvi     SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+/*
+ * 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 */
+       mvi     CLRSINT0, CLRSELDI;
+       /* XXX test for and handle ONE BIT condition */
+       and     SAVED_TCL, SELID_MASK, SELID;
+       or      SEQ_FLAGS,RESELECTED;
+       jmp     select2;
+
+/*
+ * After the selection, remove this SCB from the "waiting SCB"
+ * list.  This is achieved by simply moving our "next" pointer into
+ * 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:
+       /* Turn off the selection hardware */
+       mvi     SCSISEQ, ENRSELI|ENAUTOATNP;    /*
+                                                * ATN on parity errors
+                                                * for "in" phases
+                                                */
+       mvi     CLRSINT0, CLRSELDO;
+       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
+                                                * bus free, so interrupt
+                                                * the kernel driver if it
+                                                * happens.
+                                                */
+/*
+ * 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.
+ */
+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;
+
+
+/*
+ * 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.
+ *
+ */
+ITloop:
+       test    SSTAT1,REQINIT          jz ITloop;
+       test    SSTAT1, SCSIPERR        jnz ITloop;
+
+       and     A,PHASE_MASK,SCSISIGI;
+       mov     LASTPHASE,A;
+       mov     SCSISIGO,A;
+
+       cmp     ALLZEROS,A      je p_dataout;
+       cmp     A,P_DATAIN      je p_datain;
+       cmp     A,P_COMMAND     je p_command;
+       cmp     A,P_MESGOUT     je p_mesgout;
+       cmp     A,P_STATUS      je p_status;
+       cmp     A,P_MESGIN      je p_mesgin;
+
+       mvi     INTSTAT,BAD_PHASE;      /* unknown phase - signal driver */
+       jmp     ITloop;                 /* Try reading the bus again. */
+
+await_busfree:
+       and     SIMODE1, ~ENBUSFREE;
+       call    clear_target_state;
+       mov     NONE, SCSIDATL;         /* Ack the last byte */
+       test    SSTAT1,REQINIT|BUSFREE  jz .;
+       test    SSTAT1, BUSFREE jnz poll_for_work;
+       mvi     INTSTAT, BAD_PHASE;
+       
+clear_target_state:
+       clr     DFCNTRL;
+       clr     SCSIRATE;               /*
+                                        * We don't know the target we will
+                                        * connect to, so default to narrow
+                                        * transfers to avoid parity problems.
+                                        */
+       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;
+
+/*
+ * If we re-enter the data phase after going through another phase, the
+ * STCNT may have been cleared, so restore it from the residual field.
+ */
+data_phase_reinit:
+       mvi     DINDEX, STCNT;
+       mvi     SCB_RESID_DCNT  call bcopy_3;
+       jmp     data_phase_loop;
+
+p_datain:
+       mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+data_phase_init:
+       call    assert;                 /*
+                                        * Ensure entering a data
+                                        * phase is okay - seen identify, etc.
+                                        */
+
+       test    SEQ_FLAGS, DPHASE       jnz data_phase_reinit;
+
+       /*
+        * Initialize the DMA address and counter from the SCB.
+        * Also set SG_COUNT and SG_NEXT in memory since we cannot
+        * modify the values in the SCB itself until we see a
+        * save data pointers message.
+        */
+       mvi     DINDEX, HADDR;
+       mvi     SCB_DATAPTR     call bcopy_7;
+
+       call    set_stcnt_from_hcnt;
+
+       mov     SG_COUNT,SCB_SGCOUNT;
+
+       mvi     DINDEX, SG_NEXT;
+       mvi     SCB_SGPTR       call bcopy_4;
+
+data_phase_loop:
+/* Guard against overruns */
+       test    SG_COUNT, 0xff jnz data_phase_inbounds;
+/*
+ * Turn on 'Bit Bucket' mode, set the transfer count to
+ * 16meg and let the target run until it changes phase.
+ * When the transfer completes, notify the host that we
+ * had an overrun.
+ */
+       or      SXFRCTL1,BITBUCKET;
+       mvi     HCNT[0], 0xff;
+       mvi     HCNT[1], 0xff;
+       mvi     HCNT[2], 0xff;
+       call    set_stcnt_from_hcnt;
+
+data_phase_inbounds:
+/* If we are the last SG block, ensure wideodd is off. */
+       cmp     SG_COUNT,0x01 jne data_phase_wideodd;
+       and     DMAPARAMS, ~WIDEODD;
+data_phase_wideodd:
+       mov     DMAPARAMS  call dma;
+
+/* Go tell the host about any overruns */
+       test    SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+
+/* Exit if we had an underrun.  dma clears SINDEX in this case. */
+       test    SINDEX,0xff     jz data_phase_finish;
+
+/*
+ * Advance the scatter-gather pointers if needed 
+ */
+sg_advance:
+       dec     SG_COUNT;       /* one less segment to go */
+
+       test    SG_COUNT, 0xff  jz data_phase_finish; /* Are we done? */
+
+       clr     A;                      /* add sizeof(struct scatter) */
+       add     SG_NEXT[0],SG_SIZEOF;
+       adc     SG_NEXT[1],A;
+
+/*
+ * Load a struct scatter and set up the data address and length.
+ * If the working value of the SG count is nonzero, then
+ * we need to load a new set of values.
+ *
+ * This, like all DMA's, assumes little-endian host data storage.
+ */
+sg_load:
+       mvi     DINDEX, HADDR;
+       mvi     SG_NEXT call bcopy_4;
+
+       mvi     HCNT[0],SG_SIZEOF;
+       clr     HCNT[1];
+       clr     HCNT[2];
+
+       or      DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+       call    dma_finish;
+
+/*
+ * Copy data from FIFO into SCB data pointer and data count.  This assumes
+ * that the SG segments are of the form:
+ *
+ * struct ahc_dma_seg {
+ *     u_int32_t       addr;           four bytes, little-endian order
+ *     u_int32_t       len;            four bytes, little endian order
+ * };
+ */
+       mvi     HADDR   call dfdat_in_7;
+
+/* Load STCNT as well.  It is a mirror of HCNT */
+       call    set_stcnt_from_hcnt;
+       test    SSTAT1,PHASEMIS jz data_phase_loop;
+
+data_phase_finish:
+/*
+ * After a DMA finishes, save the SG and STCNT residuals back into the SCB
+ * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
+ * were transferred on the SCSI (as opposed to the host) bus.
+ */
+       mov     SCB_RESID_DCNT[0],STCNT[0];
+       mov     SCB_RESID_DCNT[1],STCNT[1];
+       mov     SCB_RESID_DCNT[2],STCNT[2];
+       mov     SCB_RESID_SGCNT, SG_COUNT;
+
+       /* We have seen a data phase */
+       or      SEQ_FLAGS, DPHASE;
+
+       jmp     ITloop;
+
+data_phase_overrun:
+/*
+ * Turn off BITBUCKET mode and notify the host
+ */
+       and     SXFRCTL1, ~BITBUCKET;
+       mvi     INTSTAT,DATA_OVERRUN;
+       jmp     ITloop;
+
+/*
+ * Command phase.  Set up the DMA registers and let 'er rip.
+ */
+p_command:
+       call    assert;
+
+/*
+ * Load HADDR and HCNT.
+ */
+       mvi     DINDEX, HADDR;
+       mvi     SCB_CMDPTR      call bcopy_5;
+       clr     HCNT[1];
+       clr     HCNT[2];
+
+       call    set_stcnt_from_hcnt;
+
+       mvi     (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+       jmp     ITloop;
+
+/*
+ * Status phase.  Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
+p_status:
+       call    assert;
+
+       mov     SCB_TARGET_STATUS, SCSIDATL;
+       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.
+ */
+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.
+ */
+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;
+/*
+ * 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;
+
+p_mesgout_done:
+       mvi     CLRSINT1,CLRATNO;       /* Be sure to turn ATNO off */
+       clr     MSG_LEN;                /* no active msg */
+       jmp     ITloop;
+
+/*
+ * Message in phase.  Bytes are read using Automatic PIO mode.
+ */
+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;
+       cmp     A,MSG_SAVEDATAPOINTER   je mesgin_sdptrs;
+       cmp     ALLZEROS,A              je mesgin_complete;
+       cmp     A,MSG_RESTOREPOINTERS   je mesgin_rdptrs;
+       cmp     A,MSG_EXTENDED          je mesgin_extended;
+       cmp     A,MSG_MESSAGE_REJECT    je mesgin_reject;
+       cmp     A,MSG_NOOP              je mesgin_done;
+
+rej_mesgin:
+/*
+ * We have no idea what this message in is, so we issue a message reject
+ * and hope for the best.  In any case, rejection should be a rare
+ * occurrence - signal the driver when it happens.
+ */
+       mvi     INTSTAT,SEND_REJECT;            /* let driver know */
+
+       mvi     MSG_MESSAGE_REJECT      call mk_mesg;
+
+mesgin_done:
+       mov     NONE,SCSIDATL;          /*dummy read from latch to ACK*/
+       jmp     ITloop;
+
+
+mesgin_complete:
+/*
+ * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
+ * and trigger a completion interrupt.  Before doing so, check to see if there
+ * is a residual or the status byte is something other than NO_ERROR (0).  In
+ * either of these conditions, we upload the SCB back to the host so it can
+ * 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
+ * sense, it will fill the kernel SCB with a request sense command and set
+ * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
+ * the SCB, and process it as the next command by adding it to the waiting list.
+ * If the kernel driver does not wish to request sense, it need only clear
+ * RETURN_1, and the command is allowed to complete normally.  We don't bother
+ * to post to the QOUTFIFO in the error cases since it would require extra
+ * work in the kernel driver to ensure that the entry was removed before the
+ * command complete code tried processing it.
+ */
+
+/*
+ * First check for residuals
+ */
+       test    SCB_RESID_SGCNT,0xff    jnz upload_scb;
+       test    SCB_TARGET_STATUS,0xff  jz status_ok;   /* 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? */
+       mvi     INTSTAT,BAD_STATUS;                     /* let driver know */
+       cmp     RETURN_1, SEND_SENSE    jne status_ok;
+       /* 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 */
+       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;
+add_to_waiting_list:
+       mov     SCB_NEXT,WAITING_SCBH;
+       mov     WAITING_SCBH, SCBPTR;
+       /*
+        * Prepare our selection hardware before the busfree so we have a
+        * high probability of winning arbitration.
+        */
+       call    start_selection;
+       jmp     await_busfree;
+add_to_free_list:
+       call    add_scb_to_free_list;
+       jmp     await_busfree;
+
+/*
+ * Is it an extended message?  Copy the message to our message buffer and
+ * notify the host.  The host will tell us whether to reject this message,
+ * respond to it with the message that the host placed in our message buffer,
+ * 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;
+
+/*
+ * Is it a disconnect message?  Set a flag in the SCB to remind us
+ * and await the bus going free.
+ */
+mesgin_disconnect:
+       or      SCB_CONTROL,DISCONNECTED;
+.if ( SCB_PAGING )
+       call    add_scb_to_disc_list;
+.endif
+       jmp     await_busfree;
+
+/*
+ * Save data pointers message:
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them.  This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ */
+mesgin_sdptrs:
+       test    SEQ_FLAGS, DPHASE       jz mesgin_done;
+       mov     SCB_SGCOUNT,SG_COUNT;
+
+       /* The SCB SGPTR becomes the next one we'll download */
+       mvi     DINDEX, SCB_SGPTR;
+       mvi     SG_NEXT call bcopy_4;
+       
+       /* The SCB DATAPTR0 becomes the current SHADDR */
+       mvi     DINDEX, SCB_DATAPTR;
+       mvi     SHADDR          call bcopy_4;
+
+/*
+ * Use the residual number since STCNT is corrupted by any message transfer.
+ */
+       mvi     SCB_RESID_DCNT  call    bcopy_3;
+
+       jmp     mesgin_done;
+
+/*
+ * Restore pointers message?  Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.
+ */
+mesgin_rdptrs:
+       and     SEQ_FLAGS, ~DPHASE;             /*
+                                                * We'll reload them
+                                                * the next time through
+                                                * the dataphase.
+                                                */
+       jmp     mesgin_done;
+
+/*
+ * Identify message?  For a reconnecting target, this tells us the lun
+ * that the reconnection is for - find the correct SCB and switch to it,
+ * clearing the "disconnected" bit so we don't "find" it by accident later.
+ */
+mesgin_identify:
+       test    A,0x78  jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/
+       and     A,0x07;                 /* lun in lower three bits */
+       or      SAVED_TCL,A;            /* SAVED_TCL should be complete now */
+       mov     SAVED_TCL call index_untagged_scb;
+       mov     ARG_1, SINDIR;
+.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;
+.endif
+/*
+ * 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
+ * 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.
+ */
+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;
+       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;
+.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;
+.endif
+setup_SCB:
+       and     SCB_CONTROL,~DISCONNECTED;
+       or      SEQ_FLAGS,IDENTIFY_SEEN;          /* make note of IDENTIFY */
+       jmp     mesgin_done;
+
+not_found:
+       mvi     INTSTAT, NO_MATCH;
+       mvi     MSG_BUS_DEV_RESET       call mk_mesg;
+       jmp     mesgin_done;
+
+/*
+ * Message reject?  Let the kernel driver handle this.  If we have an 
+ * outstanding WDTR or SDTR negotiation, assume that it's a response from 
+ * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
+ * it since we have no clue what it pertains to.
+ */
+mesgin_reject:
+       mvi     INTSTAT, REJECT_MSG;
+       jmp     mesgin_done;
+
+/*
+ * [ ADD MORE MESSAGE HANDLING HERE ]
+ */
+
+/*
+ * Locking the driver out, build a one-byte message passed in SINDEX
+ * 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;
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * According to Adaptec's documentation, an ACK is not sent on input from
+ * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+ * latched (the usual way), then read the data byte directly off the bus
+ * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+ * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+ * spec guarantees that the target will hold the data byte on the bus until
+ * we send our ACK.
+ *
+ * The assumption here is that these are called in a particular sequence,
+ * and that REQ is already set when inb_first is called.  inb_{first,next}
+ * use the same calling convention as inb.
+ */
+
+inb_next:
+       mov     NONE,SCSIDATL;          /*dummy read from latch to ACK*/
+inb_next_wait:
+       /*
+        * If there is a parity error, wait for the kernel to
+        * see the interrupt and prepare our message response
+        * before continuing.
+        */
+       test    SSTAT1, REQINIT jz inb_next_wait;
+       test    SSTAT1, SCSIPERR jnz inb_next_wait;
+       and     LASTPHASE, PHASE_MASK, SCSISIGI;
+       cmp     LASTPHASE, P_MESGIN jne mesgin_phasemis;
+inb_first:
+       mov     DINDEX,SINDEX;
+       mov     DINDIR,SCSIBUSL ret;            /*read byte directly from bus*/
+inb_last:
+       mov     NONE,SCSIDATL ret;              /*dummy read from latch to ACK*/
+
+mesgin_phasemis:
+/*
+ * We expected to receive another byte, but the target changed phase
+ */
+       mvi     INTSTAT, MSGIN_PHASEMIS;
+       jmp     ITloop;
+
+/*
+ * DMA data transfer.  HADDR and HCNT must be loaded first, and
+ * SINDEX should contain the value to load DFCNTRL with - 0x3d for
+ * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
+ * during initialization.
+ */
+dma:
+       mov     DFCNTRL,SINDEX;
+dma_loop:
+       test    SSTAT0,DMADONE  jnz dma_dmadone;
+       test    SSTAT1,PHASEMIS jz dma_loop;    /* ie. underrun */
+dma_phasemis:
+       test    SSTAT0,SDONE    jnz dma_checkfifo;
+       mov     SINDEX,ALLZEROS;                /* Notify caller of phasemiss */
+
+/*
+ * We will be "done" DMAing when the transfer count goes to zero, or
+ * the target changes the phase (in light of this, it makes sense that
+ * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
+ * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
+ * magically on STCNT=0 or a phase change, so just wait for FIFO empty
+ * status.
+ */
+dma_checkfifo:
+       test    DFCNTRL,DIRECTION       jnz dma_fifoempty;
+dma_fifoflush:
+       test    DFSTATUS,FIFOEMP        jz dma_fifoflush;
+
+dma_fifoempty:
+       /* Don't clobber an inprogress host data transfer */
+       test    DFSTATUS, MREQPEND      jnz dma_fifoempty;
+/*
+ * Now shut the DMA enables off and make sure that the DMA enables are 
+ * actually off first lest we get an ILLSADDR.
+ */
+dma_dmadone:
+       and     DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+dma_halt:
+       test    DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 
+return:
+       ret;
+
+/*
+ * Assert that if we've been reselected, then we've seen an IDENTIFY
+ * 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.
+ */
+findSCB:
+       mov     SCBPTR,SINDEX;                  /* switch to next SCB */
+       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*/
+findSCB_loop:
+       inc     SINDEX;
+       mov     A,SCBCOUNT;
+       cmp     SINDEX,A        jne findSCB;
+/*
+ * 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.
+ */
+       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     SCBPTR, SCB_NEXT;
+       mov     SCB_PREV, SAVED_LINKPTR;
+       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     SCBPTR, SCB_PREV;
+       mov     SCB_NEXT, SAVED_LINKPTR;
+       mov     SCBPTR, SINDEX ret;
+rHead:
+       mov     DISCONNECTED_SCBH,SCB_NEXT ret;
+.else
+       ret;
+.endif
+
+set_stcnt_from_hcnt:
+       mov     STCNT[0], HCNT[0];
+       mov     STCNT[1], HCNT[1];
+       mov     STCNT[2], HCNT[2] ret;
+
+bcopy_7:
+       mov     DINDIR, SINDIR;
+       mov     DINDIR, SINDIR;
+bcopy_5:
+       mov     DINDIR, SINDIR;
+bcopy_4:
+       mov     DINDIR, SINDIR;
+bcopy_3:
+       mov     DINDIR, SINDIR;
+       mov     DINDIR, SINDIR;
+       mov     DINDIR, SINDIR 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 */
+       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 */
+copy_scb_tofifo:
+       mvi     SINDEX, SCB_CONTROL;
+       add     A, 28, SINDEX;
+copy_scb_tofifo_loop:
+       mov     DFDAT,SINDIR;
+       mov     DFDAT,SINDIR;
+       mov     DFDAT,SINDIR;
+       mov     DFDAT,SINDIR;
+       mov     DFDAT,SINDIR;
+       mov     DFDAT,SINDIR;
+       mov     DFDAT,SINDIR;
+       cmp     SINDEX, A jne copy_scb_tofifo_loop;
+       or      DFCNTRL, HDMAEN|FIFOFLUSH;
+dma_scb_fromhost:
+       call    dma_finish;
+       /* If we were putting the SCB, we are done */
+       test    DMAPARAMS, DIRECTION    jz      return;
+       mvi     SCB_CONTROL  call dfdat_in_7;
+       call    dfdat_in_7_continued;
+       call    dfdat_in_7_continued;
+       jmp     dfdat_in_7_continued;
+dfdat_in_7:
+       mov     DINDEX,SINDEX;
+dfdat_in_7_continued:
+       mov     DINDIR,DFDAT;
+       mov     DINDIR,DFDAT;
+       mov     DINDIR,DFDAT;
+       mov     DINDIR,DFDAT;
+       mov     DINDIR,DFDAT;
+       mov     DINDIR,DFDAT;
+       mov     DINDIR,DFDAT ret;
+
+/*
+ * Wait for DMA from host memory to data FIFO to complete, then disable
+ * DMA and wait for it to acknowledge that it's off.
+ */
+dma_finish:
+       test    DFSTATUS,HDONE  jz dma_finish;
+       /* Turn off DMA */
+       and     DFCNTRL, ~HDMAEN;
+       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:
+       mov     SCB_NEXT, FREE_SCBH;
+       mvi     SCB_TAG, SCB_LIST_NULL;
+       mov     FREE_SCBH, SCBPTR ret;
+
+.if ( SCB_PAGING )
+get_free_or_disc_scb:
+       cmp     FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
+       cmp     DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
+return_error:
+       mvi     SINDEX, SCB_LIST_NULL   ret;
+dequeue_disc_scb:
+       mov     SCBPTR, DISCONNECTED_SCBH;
+/*
+ * If we have a residual, then we are in the middle of some I/O
+ * and we have to send this SCB back up to the kernel so that the
+ * saved data pointers and residual information isn't lost.
+ */
+       test    SCB_CONTROL, MUST_DMAUP_SCB jz . + 3;
+       and     SCB_CONTROL, ~MUST_DMAUP_SCB;
+       jmp     dma_up_scb;
+       test    SCB_RESID_SGCNT,0xff    jnz dma_up_scb;
+       cmp     SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
+dma_up_scb:
+       mvi     DMAPARAMS, FIFORESET;
+       mov     SCB_TAG         call dma_scb;
+unlink_disc_scb:
+       /* jmp instead of call since we want to return anyway */
+       mov     SCBPTR  jmp rem_scb_from_disc_list;
+dequeue_free_scb:
+       mov     SCBPTR, FREE_SCBH;
+       mov     FREE_SCBH, SCB_NEXT ret;
+
+add_scb_to_disc_list:
+/*
+ * Link this SCB into the DISCONNECTED list.  This list holds the
+ * candidates for paging out an SCB if one is needed for a new command.
+ * Modifying the disconnected list is a critical(pause dissabled) section.
+ */
+       mvi     SCB_PREV, SCB_LIST_NULL;
+       mov     SCB_NEXT, DISCONNECTED_SCBH;
+       mov     DISCONNECTED_SCBH, SCBPTR;
+       cmp     SCB_NEXT,SCB_LIST_NULL je return;
+       mov     SCBPTR,SCB_NEXT;
+       mov     SCB_PREV,DISCONNECTED_SCBH;
+       mov     SCBPTR,DISCONNECTED_SCBH ret;
+.endif
diff --git a/drivers/scsi/aic7xxx/scsi_message.h b/drivers/scsi/aic7xxx/scsi_message.h
new file mode 100644 (file)
index 0000000..267a015
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 */
+#define MSG_SAVEDATAPOINTER    0x02 /* O/O */
+#define MSG_RESTOREPOINTERS    0x03 /* O/O */
+#define MSG_DISCONNECT         0x04 /* O/O */
+#define MSG_INITIATOR_DET_ERR  0x05 /* M/M */
+#define MSG_ABORT              0x06 /* O/M */
+#define MSG_MESSAGE_REJECT     0x07 /* M/M */
+#define MSG_NOOP               0x08 /* M/M */
+#define MSG_PARITY_ERROR       0x09 /* M/M */
+#define MSG_LINK_CMD_COMPLETE  0x0a /* O/O */
+#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */
+#define MSG_BUS_DEV_RESET      0x0c /* O/M */
+#define MSG_ABORT_TAG          0x0d /* O/O */
+#define MSG_CLEAR_QUEUE                0x0e /* O/O */
+#define MSG_INIT_RECOVERY      0x0f /* O/O */
+#define MSG_REL_RECOVERY       0x10 /* O/O */
+#define MSG_TERM_IO_PROC       0x11 /* O/O */
+
+/* Messages (2 byte) */
+#define MSG_SIMPLE_Q_TAG       0x20 /* O/O */
+#define MSG_HEAD_OF_Q_TAG      0x21 /* O/O */
+#define MSG_ORDERED_Q_TAG      0x22 /* O/O */
+#define MSG_IGN_WIDE_RESIDUE   0x23 /* O/O */
+
+/* Identify message */              /* M/M */  
+#define MSG_IDENTIFYFLAG       0x80 
+#define MSG_IDENTIFY(lun, disc)        (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
+#define MSG_ISIDENTIFY(m)      ((m) & MSG_IDENTIFYFLAG)
+
+/* Extended messages (opcode and length) */
+#define MSG_EXT_SDTR           0x01
+#define MSG_EXT_SDTR_LEN       0x03
+
+#define MSG_EXT_WDTR           0x03
+#define MSG_EXT_WDTR_LEN       0x02
diff --git a/drivers/scsi/aic7xxx/sequencer.h b/drivers/scsi/aic7xxx/sequencer.h
new file mode 100644 (file)
index 0000000..7112c2e
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * 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 $
+ */
+
+#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;
+};
+
+struct ins_format2 {
+       u_int8_t shift_control;
+       u_int8_t source;
+       u_int8_t destination;
+       u_int8_t 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;
+#define ADDR_HIGH_BIT 0x01
+};
+
+struct instruction {
+       union {
+               struct ins_format1 format1;
+               struct ins_format2 format2;
+               struct ins_format3 format3;
+               u_int8_t           bytes[4];
+       } format;
+       u_int   srcline;
+       struct symbol *patch_label;
+       struct {
+               struct instruction *stqe_next; /* next element */
+       } links;
+};
+
+#define        AIC_OP_OR       0x0
+#define        AIC_OP_AND      0x1
+#define AIC_OP_XOR     0x2
+#define        AIC_OP_ADD      0x3
+#define        AIC_OP_ADC      0x4
+#define        AIC_OP_ROL      0x5
+
+#define        AIC_OP_JMP      0x8
+#define AIC_OP_JC      0x9
+#define AIC_OP_JNC     0xa
+#define AIC_OP_CALL    0xb
+#define        AIC_OP_JNE      0xc
+#define        AIC_OP_JNZ      0xd
+#define        AIC_OP_JE       0xe
+#define        AIC_OP_JZ       0xf
+
+/* Pseudo Ops */
+#define        AIC_OP_SHL      0x10
+#define        AIC_OP_SHR      0x20
+#define        AIC_OP_ROR      0x30
diff --git a/drivers/scsi/aic7xxx_asm.c b/drivers/scsi/aic7xxx_asm.c
deleted file mode 100644 (file)
index 544edf0..0000000
+++ /dev/null
@@ -1,734 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx sequencer code assembler.
- *
- * Copyright (c) 1994 John Aycock
- *   The University of Calgary Department of Computer Science.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Comments are started by `#' and continue to the end of the line; lines
- * may be of the form:
- *      <label>*
- *      <label>*  <undef-sym> = <value>
- *      <label>*  <opcode> <operand>*
- *
- * A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
- * are token separators.
- *-M*************************************************************************/
-static const char id[] = "$Id: aic7xxx_asm.c,v 3.0 1996/04/16 08:52:23 deang Exp $";
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#define MEMORY         448
-#define MAXLINE                1024
-#define MAXTOKEN       32
-#define ADOTOUT                "a.out"
-#define NOVALUE                -1
-
-#ifndef TRUE
-#  define TRUE 1
-#endif
-#ifndef FALSE
-#  define FALSE 0
-#endif
-#define MAX_ARGS       16
-static const char *cpp[] = {
-  "/lib/cpp -P - -",
-  "/usr/lib/cpp -P - -",
-  "/usr/bin/cpp -P - -",
-  "/usr/bin/gcc -E -P -",
-  "/usr/bin/cc -E -P -"
-};
-
-#define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
-
-/*
- * AIC-7770/AIC-7870 register definitions
- */
-#define R_SINDEX       0x65
-#define R_ALLONES      0x69
-#define R_ALLZEROS     0x6a
-#define R_NONE         0x6a
-
-int debug;
-int lineno, LC;
-char *filename;
-unsigned char M[MEMORY][4];
-
-void 
-error(const char *s)
-{
-       fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
-       exit(EXIT_FAILURE);
-}
-
-void *
-Malloc(size_t size)
-{
-       void *p = malloc(size);
-       if (!p)
-               error("out of memory");
-       return(p);
-}
-
-void *
-Realloc(void *ptr, size_t size)
-{
-       void *p = realloc(ptr, size);
-       if (!p)
-               error("out of memory");
-       return(p);
-}
-
-char *
-Strdup(char *s)
-{
-       char *p = (char *)Malloc(strlen(s) + 1);
-       strcpy(p, s);
-       return(p);
-}
-
-typedef struct sym_t {
-       struct sym_t    *next;          /* MUST BE FIRST */
-       char            *name;
-       int             value;
-       int             npatch; 
-       int             *patch;
-} sym_t;
-
-sym_t *head;
-
-void
-define(char *name, int value)
-{
-       sym_t *p, *q;
-
-       for (p = head, q = (sym_t *)&head; p; p = p->next) {
-               if (!strcmp(p->name, name))
-                       error("redefined symbol");
-               q = p;
-       }
-
-       p = q->next = (sym_t *)Malloc(sizeof(sym_t));
-       p->next = NULL;
-       p->name = Strdup(name);
-       p->value = value;
-       p->npatch = 0;
-       p->patch = NULL;
-
-       if (debug) {
-               fprintf(stderr, "\"%s\" ", p->name);
-               if (p->value != NOVALUE)
-                       fprintf(stderr, "defined as 0x%x\n", p->value);
-               else
-                       fprintf(stderr, "undefined\n");
-       }
-}
-
-sym_t *
-lookup(char *name)
-{
-       sym_t *p;
-
-       for (p = head; p; p = p->next)
-               if (!strcmp(p->name, name))
-                       return(p);
-       return(NULL);
-}
-
-void 
-patch(sym_t *p, int location)
-{
-       p->npatch += 1;
-       p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
-
-       p->patch[p->npatch - 1] = location;
-}
-
-void backpatch(void)
-{
-       int i;
-       sym_t *p;
-
-       for (p = head; p; p = p->next) {
-
-               if (p->value == NOVALUE) {
-                       fprintf(stderr,
-                               "%s: undefined symbol \"%s\"\n",
-                               filename, p->name);
-                       exit(EXIT_FAILURE);
-               }
-
-               if (p->npatch) {
-                       if (debug)
-                               fprintf(stderr,
-                                       "\"%s\" (0x%x) patched at",
-                                       p->name, p->value);
-
-                       for (i = 0; i < p->npatch; i++) {
-                               M[p->patch[i]][0] &= ~1;
-                               M[p->patch[i]][0] |= ((p->value >> 8) & 1);
-                               M[p->patch[i]][1] = p->value & 0xff;
-
-                               if (debug)
-                                       fprintf(stderr, " 0x%x", p->patch[i]);
-                       }
-
-                       if (debug)
-                               fputc('\n', stderr);
-               }
-       }
-}
-
-/*
- *  Output words in byte-reversed order (least significant first)
- *  since the sequencer RAM is loaded that way.
- */
-void
-output(FILE *fp)
-{
-       int i;
-
-       for (i = 0; i < LC; i++)
-               fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
-                       M[i][3],
-                       M[i][2],
-                       M[i][1],
-                       M[i][0]);
-       printf("%d out of %d instructions used.\n", LC, MEMORY);
-}
-
-char **
-getl(int *n)
-{
-       int i;
-       char *p, *quote;
-       static char buf[MAXLINE];
-       static char *a[MAXTOKEN];
-
-       i = 0;
-
-       while (fgets(buf, sizeof(buf), stdin)) {
-
-               lineno += 1;
-
-               if (buf[strlen(buf)-1] != '\n')
-                       error("line too long");
-
-               p = strchr(buf, '#');
-               if (p)
-                       *p = '\0';
-               p = buf;
-rescan:
-               quote = strchr(p, '\"');
-               if (quote)
-                       *quote = '\0';
-               for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
-                       if (i < MAXTOKEN-1)
-                               a[i++] = p;
-                       else
-                               error("too many tokens");
-               if (quote) {
-                       quote++; 
-                       p = strchr(quote, '\"');
-                       if (!p)
-                               error("unterminated string constant");
-                       else if (i < MAXTOKEN-1) {
-                               a[i++] = quote;
-                               *p = '\0';
-                               p++;
-                       }
-                       else
-                               error("too many tokens");
-                       goto rescan;
-               }               
-               if (i) {
-                       *n = i;
-                       return(a);
-               }
-       }
-       return(NULL);
-}
-
-#define A      0x8000          /* `A'ccumulator ok */
-#define I      0x4000          /* use as immediate value */
-#define SL     0x2000          /* shift left */
-#define SR     0x1000          /* shift right */
-#define RL     0x0800          /* rotate left */
-#define RR     0x0400          /* rotate right */
-#define LO     0x8000          /* lookup: ori-{jmp,jc,jnc,call} */
-#define LA     0x4000          /* lookup: and-{jz,jnz} */
-#define LX     0x2000          /* lookup: xor-{je,jne} */
-#define NA     -1              /* not applicable */
-
-struct {
-       const char *name;
-       int n;                  /* number of operands, including opcode */
-       unsigned int op;        /* immediate or L?|pos_from_0 */
-       unsigned int dest;      /* NA, pos_from_0, or I|immediate */
-       unsigned int src;       /* NA, pos_from_0, or I|immediate */
-       unsigned int imm;       /* pos_from_0, A|pos_from_0, or I|immediate */
-       unsigned int addr;      /* NA or pos_from_0 */
-       int fmt;                /* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- *               N  OP    DEST         SRC             IMM     ADDR    FMT
- */
-       { "mov",  3, 1,    1,           2,              I|0xff, NA,     1 },
-       { "mov",  4, LO|2, NA,          1,              I|0,    3,      3 },
-       { "mvi",  3, 0,    1,           I|R_ALLZEROS,   A|2,    NA,     1 },
-       { "mvi",  4, LO|2, NA,          I|R_ALLZEROS,   1,      3,      3 },
-       { "not",  2, 2,    1,           1,              I|0xff, NA,     1 },
-       { "and",  3, 1,    1,           1,              A|2,    NA,     1 },
-       { "and",  4, 1,    1,           3,              A|2,    NA,     1 },
-       { "or",   3, 0,    1,           1,              A|2,    NA,     1 },
-       { "or",   4, 0,    1,           3,              A|2,    NA,     1 },
-       { "or",   5, LO|3, NA,          1,              2,      4,      3 },
-       { "xor",  3, 2,    1,           1,              A|2,    NA,     1 },
-       { "xor",  4, 2,    1,           3,              A|2,    NA,     1 },
-       { "nop",  1, 1,    I|R_NONE,    I|R_ALLZEROS,   I|0xff, NA,     1 },
-       { "inc",  2, 3,    1,           1,              I|1,    NA,     1 },
-       { "inc",  3, 3,    1,           2,              I|1,    NA,     1 },
-       { "dec",  2, 3,    1,           1,              I|0xff, NA,     1 },
-       { "dec",  3, 3,    1,           2,              I|0xff, NA,     1 },
-       { "jmp",  2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
-       { "jc",   2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
-       { "jnc",  2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
-       { "call", 2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
-       { "test", 5, LA|3,   NA,        1,              A|2,    4,      3 },
-       { "cmp",  5, LX|3,   NA,        1,              A|2,    4,      3 },
-       { "ret",  1, 1,  I|R_NONE,      I|R_ALLZEROS,   I|0xff, NA,     1 },
-       { "ret",  1, 1,  I|R_NONE,      I|R_ALLZEROS,   I|0xff, NA,     1 },
-       { "clc",  1, 3,  I|R_NONE,      I|R_ALLZEROS,   I|1,    NA,     1 },
-       { "clc",  4, 3,  2,             I|R_ALLZEROS,   A|3,    NA,     1 },
-       { "stc",  2, 3,  1,             I|R_ALLONES,    I|1,    NA,     1 },
-       { "add",  3, 3,  1,             1,              A|2,    NA,     1 },
-       { "add",  4, 3,  1,             3,              A|2,    NA,     1 },
-       { "adc",  3, 4,  1,             1,              A|2,    NA,     1 },
-       { "adc",  4, 4,  1,             3,              A|2,    NA,     1 },
-       { "shl",  3, 5,  1,             1,              SL|2,   NA,     2 },
-       { "shl",  4, 5,  1,             2,              SL|3,   NA,     2 },
-       { "shr",  3, 5,  1,             1,              SR|2,   NA,     2 },
-       { "shr",  4, 5,  1,             2,              SR|3,   NA,     2 },
-       { "rol",  3, 5,  1,             1,              RL|2,   NA,     2 },
-       { "rol",  4, 5,  1,             2,              RL|3,   NA,     2 },
-       { "ror",  3, 5,  1,             1,              RR|2,   NA,     2 },
-       { "ror",  4, 5,  1,             2,              RR|3,   NA,     2 },
-       /*
-        *  Extensions (note also that mvi allows A)
-        */
-       { "clr",  2, 1,  1,     I|R_ALLZEROS,           I|0xff, NA,     1 },
-       { 0,      0, 0,  0,     0,                      0,      0,      0 }
-};
-
-int 
-eval_operand(char **a, int spec)
-{
-       int i;
-       unsigned int want = spec & (LO|LA|LX);
-
-       static struct {
-               unsigned int what;
-               const char *name;
-               int value;
-       } jmptab[] = {
-               { LO,   "jmp",          8  },
-               { LO,   "jc",           9  },
-               { LO,   "jnc",          10 },
-               { LO,   "call",         11 },
-               { LA,   "jz",           15 },
-               { LA,   "jnz",          13 },
-               { LX,   "je",           14 },
-               { LX,   "jne",          12 },
-       };
-
-       spec &= ~(LO|LA|LX);
-
-       for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
-               if (jmptab[i].what == want &&
-                   !strcmp(jmptab[i].name, a[spec]))
-               {
-                       return(jmptab[i].value);
-               }
-
-       if (want)
-               error("invalid jump");
-
-       return(spec);           /* "case 0" - no flags set */
-}
-
-int
-eval_sdi(char **a, int spec)
-{
-       sym_t *p;
-       unsigned val;
-
-       if (spec == NA)
-               return(NA);
-
-       switch (spec & (A|I|SL|SR|RL|RR)) {
-           case SL:
-           case SR:
-           case RL:
-           case RR:
-               if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
-                       val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
-               else {
-                       p = lookup(a[spec &~ (SL|SR|RL|RR)]);
-                       if (!p)
-                               error("undefined symbol used");
-                       val = p->value;
-               }
-
-               switch (spec & (SL|SR|RL|RR)) {         /* blech */
-                   case SL:
-                       if (val > 7)
-                               return(0xf0);
-                       return(((val % 8) << 4) |
-                              (val % 8));
-                   case SR:
-                       if (val > 7)
-                               return(0xf0);
-                       return(((val % 8) << 4) |
-                              (1 << 3) |
-                              ((8 - (val % 8)) % 8));
-                   case RL:
-                       return(val % 8);
-                   case RR:
-                       return((8 - (val % 8)) % 8);
-               }
-           case I:
-               return(spec &~ I);
-           case A:
-               /*
-                *  An immediate field of zero selects
-                *  the accumulator.  Vigorously object
-                *  if zero is given otherwise - it's
-                *  most likely an error.
-                */
-               spec &= ~A;
-               if (!strcmp("A", a[spec]))
-                       return(0);
-               if (isdigit(*a[spec]) &&
-                   strtol(a[spec], NULL, 0) == 0)
-               {
-                       error("immediate value of zero selects accumulator");
-               }
-               /* falls through */
-           case 0:
-               if (isdigit(*a[spec]))
-                       return(strtol(a[spec], NULL, 0));
-               p = lookup(a[spec]);
-               if (p)
-                       return(p->value);
-               error("undefined symbol used");
-       }
-
-       return(NA);             /* shut the compiler up */
-}
-
-int
-eval_addr(char **a, int spec)
-{
-       sym_t *p;
-
-       if (spec == NA)
-               return(NA);
-       if (isdigit(*a[spec]))
-               return(strtol(a[spec], NULL, 0));
-
-       p = lookup(a[spec]);
-
-       if (p) {
-               if (p->value != NOVALUE)
-                       return(p->value);
-               patch(p, LC);
-       } else {
-               define(a[spec], NOVALUE);
-               p = lookup(a[spec]);
-               patch(p, LC);
-       }
-
-       return(NA);             /* will be patched in later */
-}
-
-int
-crack(char **a, int n)
-{
-       int i;
-       int I_imm, I_addr;
-       int I_op, I_dest, I_src, I_ret;
-
-       /*
-        *  Check for "ret" at the end of the line; remove
-        *  it unless it's "ret" alone - we still want to
-        *  look it up in the table.
-        */
-       I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
-       if (I_ret && n > 1)
-               n -= 1;
-
-       for (i = 0; instr[i].name; i++) {
-               /*
-                *  Look for match in table given constraints,
-                *  currently just the name and the number of
-                *  operands.
-                */
-               if (!strcmp(instr[i].name, *a) && instr[i].n == n)
-                       break;
-       }
-       if (!instr[i].name)
-               error("unknown opcode or wrong number of operands");
-
-       I_op    = eval_operand(a, instr[i].op);
-       I_src   = eval_sdi(a, instr[i].src);
-       I_imm   = eval_sdi(a, instr[i].imm);
-       I_dest  = eval_sdi(a, instr[i].dest);
-       I_addr  = eval_addr(a, instr[i].addr);
-
-       if( LC >= MEMORY )
-               error("Memory exhausted!\n");
-
-       switch (instr[i].fmt) {
-           case 1:
-           case 2:
-               M[LC][0] = (I_op << 1) | I_ret;
-               M[LC][1] = I_dest;
-               M[LC][2] = I_src;
-               M[LC][3] = I_imm;
-               break;
-           case 3:
-               if (I_ret)
-                       error("illegal use of \"ret\"");
-               M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
-               M[LC][1] = I_addr & 0xff;
-               M[LC][2] = I_src;
-               M[LC][3] = I_imm;
-               break;
-       }
-
-       return (1);             /* no two-byte instructions yet */
-}
-
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
-void
-assemble(FILE *ofile)
-{
-       int n;
-       char **a;
-       sym_t *p;
-
-       while ((a = getl(&n))) {
-
-               while (a[0][strlen(*a)-1] == ':') {
-                       a[0][strlen(*a)-1] = '\0';
-                       p = lookup(*a);
-                       if (p)
-                               p->value = LC;
-                       else
-                               define(*a, LC);
-                       a += 1;
-                       n -= 1;
-               }
-
-               if (!n)                 /* line was all labels */
-                       continue;
-
-               if (n == 3 && !strcmp("VERSION", *a))
-                       fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
-               else {
-                       if (n == 3 && !strcmp("=", a[1]))
-                               define(*a, strtol(a[2], NULL, 0));
-                       else
-                               LC += crack(a, n);
-               }
-       }
-
-       backpatch();
-       output(ofile);
-
-       if (debug)
-               output(stderr);
-}
-
-int
-main(int argc, char **argv)
-{
-       int c;
-       int pid;
-       int ifile;
-       int status;
-       FILE *ofile;
-       char *ofilename;
-       int fd[2];
-
-       ofile = NULL;
-       ofilename = NULL;
-       while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
-               switch (c) {
-                   case 'd':
-                       debug = !0;
-                       break;
-                   case 'D':
-                   {
-                       char *p;
-                       if ((p = strchr(optarg, '=')) != NULL) {
-                               *p = '\0';
-                               define(optarg, strtol(p + 1, NULL, 0));
-                       }
-                       else
-                               define(optarg, 1);
-                       break;
-                   }
-                   case 'o':
-                       ofilename = optarg;
-                       if ((ofile = fopen(ofilename, "w")) == NULL) {
-                               perror(optarg);
-                               exit(EXIT_FAILURE);
-                       }
-                       break;
-                   case 'h':
-                       printf("usage: %s [-d] [-Dname] [-ooutput] input\n", 
-                               *argv);
-                       exit(EXIT_SUCCESS);
-                       break;
-                   case 'v':
-                       printf("%s\n", id);
-                       exit(EXIT_SUCCESS);
-                       break;
-                   default:
-                       exit(EXIT_FAILURE);
-                       break;
-               }
-       }
-
-       if (argc - optind != 1) {
-               fprintf(stderr, "%s: must have one input file\n", *argv);
-               exit(EXIT_FAILURE);
-       }
-       filename = argv[optind];
-
-       
-       if ((ifile = open(filename, O_RDONLY)) < 0) {
-               perror(filename);
-               exit(EXIT_FAILURE);
-       }
-
-       if (!ofilename) {
-               ofilename = ADOTOUT;
-               if ((ofile = fopen(ofilename, "w")) < 0) {
-                       perror(ofilename);
-                       exit(EXIT_FAILURE);
-               }
-       }
-
-       if (pipe(fd) < 0) {
-               perror("pipe failed");
-               exit(1);
-       }
-
-       if ((pid = fork()) < 0 ) {
-               perror("fork failed");
-               exit(1);
-       }
-       else if (pid > 0) {             /* Parent */
-               close(fd[1]);           /* Close write end */
-               if (fd[0] != STDIN_FILENO) {
-                       if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
-                               perror("dup2 error on stdin");
-                               exit(EXIT_FAILURE);
-                       }
-                       close(fd[0]);
-               }
-               assemble(ofile);
-               if (wait(&status) < 0) {
-                       perror("wait error");
-               }
-
-               if (status != 0) {
-                       unlink(ofilename);
-               }
-               exit(status);
-       } else {                                /* Child */
-                int i, arg_cnt, found;
-               char *args[MAX_ARGS];
-               char *buf;
-
-                arg_cnt = 0;
-                found = FALSE;
-                for (i = 0; (!found && (i < NUMBER(cpp))); i++) {
-                       char *bp;
-
-                       buf = strdup(cpp[i]);
-
-                       for (bp = strtok(buf, " \t\n"), arg_cnt = 0;
-                             bp != NULL;
-                             bp = strtok(NULL, " \t\n"), arg_cnt++) {
-                               if (arg_cnt == 0) {
-                                       if (access(bp, X_OK) == 0) {
-                                               found = TRUE;
-                                       }
-                               }
-
-                               args[arg_cnt] = bp;
-                       }
-
-                        if (!found) {
-                               free(buf);
-                        }
-                }
-               args[arg_cnt] = NULL;
-
-                if (found) {
-                       close(fd[0]);           /* Close Read end */
-                       if (fd[1] != STDOUT_FILENO) {
-                               if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
-                                       perror("dup2 error on stdout");
-                                       exit(EXIT_FAILURE);
-                               }
-                               close(fd[1]);
-                       }
-                       if (ifile != STDIN_FILENO) {
-                               if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
-                                       perror("dup2 error on stdin");
-                                       exit(EXIT_FAILURE);
-                               }
-                               close(ifile);
-                       }
-
-                       if (execvp(args[0], args) < 0) {
-                               perror("execvp() error");
-                               exit(EXIT_FAILURE);
-                       }
-               } else {
-                       fprintf(stderr, "%s: Cannot find CPP command.\n", argv[0]);
-                       exit(EXIT_FAILURE);
-               }
-       }
-       return(EXIT_SUCCESS);
-}
index a968c324f929cb264b23cc8e76a1cc880eb29ec1..1092d4862c6bc73e3301b9fc6dbb868375830915 100644 (file)
@@ -24,7 +24,7 @@
  *
  *  Dean W. Gehnert, deang@teleport.com, 05/01/96
  *
- *  $Id: aic7xxx_proc.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
  *-M*************************************************************************/
 
 #define BLS buffer + len + size
@@ -77,16 +77,18 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
   struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
   static u8 buff[512];
-  int   i; 
+  int   i;
+  int   found = FALSE;
   int   size = 0;
   int   len = 0;
   off_t begin = 0;
   off_t pos = 0;
   static char *bus_names[] = { "Single", "Twin", "Wide" };
-  static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-787x", "AIC-788x" };
+  static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
+      "AIC-787x", "AIC-788x" };
 
   HBAptr = NULL;
-  for (i = 0; i < NUMBER(aic7xxx_boards); i++)
+  for (i=0; i < NUMBER(aic7xxx_boards); i++)
   {
     if ((HBAptr = aic7xxx_boards[i]) != NULL)
     {
@@ -95,16 +97,23 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
         break;
       }
 
-      while ((HBAptr->hostdata != NULL) &&
+      while ((HBAptr->hostdata != NULL) && !found &&
           ((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
       {
         if (HBAptr->host_no == hostno)
         {
-          break; break;
+          found = TRUE;
         }
       }
 
-      HBAptr = NULL;
+      if (!found)
+      {
+        HBAptr = NULL;
+      }
+      else
+      {
+        break;
+      }
     }
   }
 
@@ -129,8 +138,10 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
 
   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));
+  size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
+#if 0
   size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
+#endif
   len += size; pos = begin + len; size = 0;
 
   size += sprintf(BLS, "\n");
@@ -141,11 +152,6 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
 #ifdef AIC7XXX_CMDS_PER_LUN
   size += sprintf(BLS, "  AIC7XXX_CMDS_PER_LUN   : %d\n", AIC7XXX_CMDS_PER_LUN);
 #endif
-#ifdef AIC7XXX_TWIN_SUPPORT
-  size += sprintf(BLS, "  AIC7XXX_TWIN_SUPPORT   : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_TWIN_SUPPORT   : Disabled\n");
-#endif
 #ifdef AIC7XXX_TAGGED_QUEUEING
   size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Enabled\n");
 #else
@@ -165,16 +171,18 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
 
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
-  size += sprintf(BLS, "          SCSI Adapter: %s\n", board_names[p->type]);
+  size += sprintf(BLS, "          SCSI Adapter: %s\n",
+      board_names[p->chip_type]);
   size += sprintf(BLS, "                        (%s chipset)\n",
-      chip_names[p->chip_type]);
+      chip_names[p->chip_class]);
   size += sprintf(BLS, "              Host Bus: %s\n", bus_names[p->bus_type]);
   size += sprintf(BLS, "               Base IO: %#.4x\n", p->base);
+  size += sprintf(BLS, "        Base IO Memory: 0x%x\n", p->mbase);
   size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
   size += sprintf(BLS, "                  SCBs: Used %d, HW %d, Page %d\n",
-      p->scb_link->numscbs, p->maxhscbs, p->maxscbs);
+      p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
   size += sprintf(BLS, "            Interrupts: %d", p->isr_count);
-  if (p->chip_type == AIC_777x)
+  if (p->chip_class == AIC_777x)
   {
     size += sprintf(BLS, " %s\n",
         (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
index d26a0c20e6749ee694a76dc1703639b8c437e03c..f3b8c349ced4e6264b4eb411923a8bbb45dcf6e1 100644 (file)
-/*+M*************************************************************************
- * Adaptec AIC7xxx register and scratch ram definitions.
- *
- * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This version corresponds to version 1.12 of FreeBSDs aic7xxx_reg.h
- *
- * $Id: aic7xxx_reg.h,v 4.0 1996/10/13 08:23:42 deang Exp $
- *-M*************************************************************************/
-
 /*
- * This header is shared by the sequencer code and the kernel level driver.
- *
- * All page numbers refer to the Adaptec AIC-7770 Data Book available from
- * Adaptec's Technical Documents Department 1-800-934-2766
- */
+  * DO NOT EDIT - This file is automatically generated.
+  */
+
+#define        SCSISEQ                         0x00
+#define                TEMODE                  0x80
+#define                ENSELO                  0x40
+#define                ENSELI                  0x20
+#define                ENRSELI                 0x10
+#define                ENAUTOATNO              0x08
+#define                ENAUTOATNI              0x04
+#define                ENAUTOATNP              0x02
+#define                SCSIRSTO                0x01
+
+#define        SXFRCTL0                        0x01
+#define                DFON                    0x80
+#define                DFPEXP                  0x40
+#define                FAST20                  0x20
+#define                CLRSTCNT                0x10
+#define                SPIOEN                  0x08
+#define                SCAMEN                  0x04
+#define                CLRCHN                  0x02
+
+#define        SXFRCTL1                        0x02
+#define                BITBUCKET               0x80
+#define                SWRAPEN                 0x40
+#define                ENSPCHK                 0x20
+#define                STIMESEL                0x18
+#define                ENSTIMER                0x04
+#define                ACTNEGEN                0x02
+#define                STPWEN                  0x01
+
+#define        SCSISIGO                        0x03
+#define                CDO                     0x80
+#define                IOO                     0x40
+#define                MSGO                    0x20
+#define                ATNO                    0x10
+#define                SELO                    0x08
+#define                BSYO                    0x04
+#define                REQO                    0x02
+#define                ACKO                    0x01
+
+#define        SCSISIGI                        0x03
+#define                ATNI                    0x10
+#define                SELI                    0x08
+#define                BSYI                    0x04
+#define                REQI                    0x02
+#define                ACKI                    0x01
+
+#define        SCSIRATE                        0x04
+#define                WIDEXFER                0x80
+#define                SXFR                    0x70
+#define                SOFS                    0x0f
+
+#define        SCSIID                          0x05
+#define                OID                     0x0f
+
+#define        SCSIDATL                        0x06
+
+#define        SCSIDATH                        0x07
+
+#define        STCNT                           0x08
+
+#define        CLRSINT0                        0x0b
+#define                CLRSELDO                0x40
+#define                CLRSELDI                0x20
+#define                CLRSELINGO              0x10
+#define                CLRSWRAP                0x08
+#define                CLRSPIORDY              0x02
+
+#define        SSTAT0                          0x0b
+#define                TARGET                  0x80
+#define                SELDO                   0x40
+#define                SELDI                   0x20
+#define                SELINGO                 0x10
+#define                SWRAP                   0x08
+#define                SDONE                   0x04
+#define                SPIORDY                 0x02
+#define                DMADONE                 0x01
+
+#define        CLRSINT1                        0x0c
+#define                CLRSELTIMEO             0x80
+#define                CLRATNO                 0x40
+#define                CLRSCSIRSTI             0x20
+#define                CLRBUSFREE              0x08
+#define                CLRSCSIPERR             0x04
+#define                CLRPHASECHG             0x02
+#define                CLRREQINIT              0x01
+
+#define        SSTAT1                          0x0c
+#define                SELTO                   0x80
+#define                ATNTARG                 0x40
+#define                SCSIRSTI                0x20
+#define                PHASEMIS                0x10
+#define                BUSFREE                 0x08
+#define                SCSIPERR                0x04
+#define                PHASECHG                0x02
+#define                REQINIT                 0x01
+
+#define        SSTAT2                          0x0d
+#define                OVERRUN                 0x80
+#define                SFCNT                   0x1f
+
+#define        SSTAT3                          0x0e
+#define                SCSICNT                 0xf0
+#define                OFFCNT                  0x0f
+
+#define        SCSITEST                        0x0f
+#define                RQAKCNT                 0x04
+#define                CNTRTEST                0x02
+#define                CMODE                   0x01
+
+#define        SIMODE0                         0x10
+#define                ENSELDO                 0x40
+#define                ENSELDI                 0x20
+#define                ENSELINGO               0x10
+#define                ENSWRAP                 0x08
+#define                ENSDONE                 0x04
+#define                ENSPIORDY               0x02
+#define                ENDMADONE               0x01
+
+#define        SIMODE1                         0x11
+#define                ENSELTIMO               0x80
+#define                ENATNTARG               0x40
+#define                ENSCSIRST               0x20
+#define                ENPHASEMIS              0x10
+#define                ENBUSFREE               0x08
+#define                ENSCSIPERR              0x04
+#define                ENPHASECHG              0x02
+#define                ENREQINIT               0x01
+
+#define        SCSIBUSL                        0x12
+
+#define        SCSIBUSH                        0x13
+
+#define        SHADDR                          0x14
+
+#define        SELTIMER                        0x18
+#define                STAGE6                  0x20
+#define                STAGE5                  0x10
+#define                STAGE4                  0x08
+#define                STAGE3                  0x04
+#define                STAGE2                  0x02
+#define                STAGE1                  0x01
+
+#define        SELID                           0x19
+#define                SELID_MASK              0xf0
+#define                ONEBIT                  0x08
+
+#define        BRDCTL                          0x1d
+#define                BRDDAT7                 0x80
+#define                BRDDAT6                 0x40
+#define                BRDDAT5                 0x20
+#define                BRDSTB                  0x10
+#define                BRDCS                   0x08
+#define                BRDRW                   0x04
+#define                BRDCTL1                 0x02
+#define                BRDCTL0                 0x01
+
+#define        SEECTL                          0x1e
+#define                EXTARBACK               0x80
+#define                EXTARBREQ               0x40
+#define                SEEMS                   0x20
+#define                SEERDY                  0x10
+#define                SEECS                   0x08
+#define                SEECK                   0x04
+#define                SEEDO                   0x02
+#define                SEEDI                   0x01
+
+#define        SBLKCTL                         0x1f
+#define                DIAGLEDEN               0x80
+#define                DIAGLEDON               0x40
+#define                AUTOFLUSHDIS            0x20
+#define                SELWIDE                 0x02
+
+#define        SRAM_BASE                       0x20
+
+#define        TARG_SCRATCH                    0x20
+
+#define        ULTRA_ENB                       0x30
+
+#define        DISC_DSB                        0x32
+
+#define        MSG_LEN                         0x34
+
+#define        MSG_OUT                         0x35
+
+#define        DMAPARAMS                       0x3d
+#define                WIDEODD                 0x40
+#define                SCSIEN                  0x20
+#define                SDMAENACK               0x10
+#define                SDMAEN                  0x10
+#define                HDMAEN                  0x08
+#define                HDMAENACK               0x08
+#define                DIRECTION               0x04
+#define                FIFOFLUSH               0x02
+#define                FIFORESET               0x01
 
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-#define SCSISEQ                        0x000
-#define                TEMODEO         0x80
-#define                ENSELO          0x40
-#define                ENSELI          0x20
-#define                ENRSELI         0x10
-#define                ENAUTOATNO      0x08
-#define                ENAUTOATNI      0x04
-#define                ENAUTOATNP      0x02
-#define                SCSIRSTO        0x01
+#define        SCBCOUNT                        0x3e
 
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-#define        SXFRCTL0                0x001
-#define                DFON            0x80
-#define                DFPEXP          0x40
-#define                ULTRAEN         0x20
-#define                CLRSTCNT        0x10
-#define                SPIOEN          0x08
-#define                SCAMEN          0x04
-#define                CLRCHN          0x02
-/*  UNUSED                     0x01 */
+#define        COMP_SCBCOUNT                   0x3f
 
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-#define        SXFRCTL1                0x002
-#define                BITBUCKET       0x80
-#define                SWRAPEN         0x40
-#define                ENSPCHK         0x20
-#define                STIMESEL        0x18
-#define                ENSTIMER        0x04
-#define                ACTNEGEN        0x02
-#define                STPWEN          0x01    /* Powered Termination */
+#define        QCNTMASK                        0x40
 
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-#define SCSISIGI               0x003
-#define                CDI             0x80
-#define                IOI             0x40
-#define                MSGI            0x20
-#define                ATNI            0x10
-#define                SELI            0x08
-#define                BSYI            0x04
-#define                REQI            0x02
-#define                ACKI            0x01
+#define        SEQ_FLAGS                       0x41
+#define                RESELECTED              0x80
+#define                IDENTIFY_SEEN           0x40
+#define                TAGGED_SCB              0x20
+#define                DPHASE                  0x10
+#define                PAGESCBS                0x04
+#define                WIDE_BUS                0x02
+#define                TWIN_BUS                0x01
 
-/*
- * Possible phases in SCSISIGI
- */
-#define                PHASE_MASK      0xe0
-#define                P_DATAOUT       0x00
-#define                P_DATAIN        0x40
-#define                P_COMMAND       0x80
-#define                P_MESGOUT       0xa0
-#define                P_STATUS        0xc0
-#define                P_MESGIN        0xe0
-/*
- * SCSI Control Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus.  Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-#define SCSISIGO               0x003
-#define                CDO             0x80
-#define                IOO             0x40
-#define                MSGO            0x20
-#define                ATNO            0x10
-#define                SELO            0x08
-#define                BSYO            0x04
-#define                REQO            0x02
-#define                ACKO            0x01
-
-/* 
- * SCSI Rate Control (p. 3-17).
- * Contents of this register determine the Synchronous SCSI data transfer
- * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
- * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
- * greater than 0 enables synchronous transfers.
- */
-#define SCSIRATE               0x004
-#define                WIDEXFER        0x80            /* Wide transfer control */
-#define                SXFR            0x70            /* Sync transfer rate */
-#define                SOFS            0x0f            /* Sync offset */
+#define        SAVED_TCL                       0x42
 
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel.
- */
-#define SCSIID                 0x005
-#define                TID             0xf0            /* Target ID mask */
-#define                OID             0x0f            /* Our ID mask */
+#define        SG_COUNT                        0x43
 
-/*
- * SCSI Latched Data (p. 3-19).
- * Read/Write latches used to transfer data on the SCSI bus during
- * Automatic or Manual PIO mode.  SCSIDATH can be used for the
- * upper byte of a 16bit wide asynchronous data phase transfer.
- */
-#define SCSIDATL               0x006
-#define SCSIDATH               0x007
+#define        SG_NEXT                         0x44
 
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transfered
- * across the SCSI bus.  The counter is decremented only once
- * the data has been safely transfered.  SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */ 
-#define STCNT                  0x008
-#define STCNT0                 0x008
-#define STCNT1                 0x009
-#define STCNT2                 0x00a
+#define        WAITING_SCBH                    0x48
 
-/*
- * Clear SCSI Interrupt 0 (p. 3-20)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
- */
-#define        CLRSINT0                0x00b
-#define                CLRSELDO        0x40
-#define                CLRSELDI        0x20
-#define                CLRSELINGO      0x10
-#define                CLRSWRAP        0x08
-/*  UNUSED                     0x04 */
-#define                CLRSPIORDY      0x02
-/*  UNUSED                     0x01 */
+#define        SAVED_LINKPTR                   0x49
 
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-#define SSTAT0                 0x00b
-#define                TARGET          0x80            /* Board acting as target */
-#define                SELDO           0x40            /* Selection Done */
-#define                SELDI           0x20            /* Board has been selected */
-#define                SELINGO         0x10            /* Selection In Progress */
-#define                SWRAP           0x08            /* 24bit counter wrap */
-#define                SDONE           0x04            /* STCNT = 0x000000 */
-#define                SPIORDY         0x02            /* SCSI PIO Ready */
-#define                DMADONE         0x01            /* DMA transfer completed */
+#define        SAVED_SCBPTR                    0x4a
 
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-#define CLRSINT1               0x00c
-#define                CLRSELTIMEO     0x80
-#define                CLRATNO         0x40
-#define                CLRSCSIRSTI     0x20
-/*  UNUSED                     0x10 */
-#define                CLRBUSFREE      0x08
-#define                CLRSCSIPERR     0x04
-#define                CLRPHASECHG     0x02
-#define                CLRREQINIT      0x01
+#define        REJBYTE                         0x4b
 
-/*
- * SCSI Status 1 (p. 3-24)
- */
-#define SSTAT1                 0x00c
-#define                SELTO           0x80
-#define                ATNTARG         0x40
-#define                SCSIRSTI        0x20
-#define                PHASEMIS        0x10
-#define                BUSFREE         0x08
-#define                SCSIPERR        0x04
-#define                PHASECHG        0x02
-#define                REQINIT         0x01
+#define        LASTPHASE                       0x4c
+#define                P_MESGIN                0xe0
+#define                PHASE_MASK              0xe0
+#define                P_STATUS                0xc0
+#define                P_MESGOUT               0xa0
+#define                P_COMMAND               0x80
+#define                CDI                     0x80
+#define                IOI                     0x40
+#define                P_DATAIN                0x40
+#define                MSGI                    0x20
+#define                P_BUSFREE               0x01
+#define                P_DATAOUT               0x00
 
-/*
- * SCSI Interrupt Mode 1 (pp. 3-28,29)
- * Setting any bit will enable the corresponding function
- * in SIMODE1 to interrupt via the IRQ pin.
- */
-#define        SIMODE1                 0x011
-#define                ENSELTIMO       0x80
-#define                ENATNTARG       0x40
-#define                ENSCSIRST       0x20
-#define                ENPHASEMIS      0x10
-#define                ENBUSFREE       0x08
-#define                ENSCSIPERR      0x04
-#define                ENPHASECHG      0x02
-#define                ENREQINIT       0x01
+#define        MSGIN_EXT_LEN                   0x4d
 
-/*
- * SCSI Data Bus (High) (p. 3-29)
- * This register reads data on the SCSI Data bus directly.
- */
-#define        SCSIBUSL                0x012
-#define        SCSIBUSH                0x013
+#define        MSGIN_EXT_OPCODE                0x4e
 
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transfered on the SCSI bus.  They are counted up in the same
- * manner as STCNT is counted down.  SHADDR should always be used
- * to determine the address of the last byte transfered since HADDR
- * can be skewed by write ahead.
- */
-#define        SHADDR                  0x014
-#define        SHADDR0                 0x014
-#define        SHADDR1                 0x015
-#define        SHADDR2                 0x016
-#define        SHADDR3                 0x017
+#define        MSGIN_EXT_BYTES                 0x4f
 
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-#define SELID                  0x019
-#define                SELID_MASK      0xf0
-#define                ONEBIT          0x08
-/*  UNUSED                     0x07 */
+#define        DISCONNECTED_SCBH               0x52
 
-/*
- * 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
- * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-#define SBLKCTL                        0x01f
-#define                DIAGLEDEN       0x80    /* Aic78X0 only */
-#define                DIAGLEDON       0x40    /* Aic78X0 only */
-#define                AUTOFLUSHDIS    0x20
-/*  UNUSED                     0x10 */
-#define                SELBUS_MASK     0x0a
-#define                SELBUSB         0x08
-/*  UNUSED                     0x04 */
-#define                SELWIDE         0x02
-/*  UNUSED                     0x01 */
-#define                SELNARROW       0x00
+#define        FREE_SCBH                       0x53
 
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-#define SEQCTL                 0x060
-#define                PERRORDIS       0x80
-#define                PAUSEDIS        0x40
-#define                FAILDIS         0x20
-#define        FASTMODE        0x10
-#define                BRKADRINTEN     0x08
-#define                STEP            0x04
-#define                SEQRESET        0x02
-#define                LOADRAM         0x01
+#define        HSCB_ADDR                       0x54
 
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
- * four bytes in succession.  The SEQADDRs will increment after the most
- * significant byte is written
- */
-#define SEQRAM                 0x061
+#define        CUR_SCBID                       0x58
 
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-#define SEQADDR0               0x062
-#define SEQADDR1               0x063
-#define        SEQADDR1_MASK   0x01
+#define        ARG_1                           0x59
+#define        RETURN_1                        0x59
+#define                SEND_MSG                0x80
+#define                SEND_SENSE              0x40
+#define                SEND_REJ                0x20
 
-/*
- * Accumulator
- * We cheat by passing arguments in the Accumulator up to the kernel driver
- */
-#define ACCUM                  0x064
-
-#define SINDEX                 0x065
-#define DINDEX                 0x066
-#define ALLZEROS               0x06a
-#define NONE                   0x06a
-#define SINDIR                 0x06c
-#define DINDIR                 0x06d
-#define FUNCTION1              0x06e
+#define        SCSICONF                        0x5a
+#define                RESET_SCSI              0x40
 
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transfered across the host bus.
- */
-#define HADDR                  0x088
-#define HADDR0                 0x088
-#define HADDR1                 0x089
-#define HADDR2                 0x08a
-#define HADDR3                 0x08b
-
-#define HCNT                   0x08c
-#define HCNT0                  0x08c
-#define HCNT1                  0x08d
-#define HCNT2                  0x08e
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-#define SCBPTR                 0x090
+#define        HOSTCONF                        0x5d
 
-/*
- * Board Control (p. 3-43)
- */
-#define BCTL                   0x084
-/*   RSVD                      0xf0 */
-#define                ACE             0x08    /* Support for external processors */
-/*   RSVD                      0x06 */
-#define                ENABLE          0x01
+#define        HA_274_BIOSCTRL                 0x5f
+#define                BIOSMODE                0x30
+#define                BIOSDISABLED            0x30
+#define                CHANNEL_B_PRIMARY       0x08
 
-/*
- * On the aic78X0 chips, Board Control is replaced by the DSCommand
- * register (p. 4-64)
- */
-#define        DSCOMMAND               0x084
-#define                CACHETHEN       0x80    /* Cache Threshold enable */
-#define                DPARCKEN        0x40    /* Data Parity Check Enable */
-#define                MPARCKEN        0x20    /* Memory Parity Check Enable */
-#define                EXTREQLCK       0x10    /* External Request Lock */
+#define        SEQCTL                          0x60
+#define                PERRORDIS               0x80
+#define                PAUSEDIS                0x40
+#define                FAILDIS                 0x20
+#define                FASTMODE                0x10
+#define                BRKADRINTEN             0x08
+#define                STEP                    0x04
+#define                SEQRESET                0x02
+#define                LOADRAM                 0x01
 
-/*
- * Bus On/Off Time (p. 3-44)
- */
-#define BUSTIME                        0x085
-#define                BOFF            0xf0
-#define                BON             0x0f
+#define        SEQRAM                          0x61
 
-/*
- * Bus Speed (p. 3-45)
- */
-#define        BUSSPD                  0x086
-#define                DFTHRSH         0xc0
-#define                STBOFF          0x38
-#define                STBON           0x07
-#define                DFTHRSH_100     0xc0
+#define        SEQADDR0                        0x62
 
-/*
- * Host Control (p. 3-47) R/W
- * Overall host control of the device.
- */
-#define HCNTRL                 0x087
-/*    UNUSED                   0x80 */
-#define                POWRDN          0x40
-/*    UNUSED                   0x20 */
-#define                SWINT           0x10
-#define                IRQMS           0x08
-#define                PAUSE           0x04
-#define                INTEN           0x02
-#define                CHIPRST         0x01
-#define                CHIPRSTACK      0x01
+#define        SEQADDR1                        0x63
+#define                SEQADDR1_MASK           0x01
 
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-#define INTSTAT                        0x091
-#define                SEQINT_MASK     0xf1            /* SEQINT Status Codes */
-#define                        BAD_PHASE       0x01    /* unknown scsi bus phase */
-#define                        SEND_REJECT     0x11    /* sending a message reject */
-#define                        NO_IDENT        0x21    /* no IDENTIFY after reconnect*/
-#define                        NO_MATCH        0x31    /* no cmd match for reconnect */
-#define                        SDTR_MSG        0x41    /* SDTR message received */
-#define                        WDTR_MSG        0x51    /* WDTR message received */
-#define                        REJECT_MSG      0x61    /* Reject message received */
-#define                        BAD_STATUS      0x71    /* Bad status from target */
-#define                        RESIDUAL        0x81    /* Residual byte count != 0 */
-#define                        ABORT_TAG       0x91    /* Sent an ABORT_TAG message */
-#define                        AWAITING_MSG    0xa1    /*
-                                                * Kernel requested to specify
-                                                 * a message to this target
-                                                 * (command was null), so tell
-                                                 * it that it can fill the
-                                                 * message buffer.
-                                                 */
-#define                        IMMEDDONE       0xb1    /*
-                                                * An immediate command has
-                                                * completed
-                                                */
-#define                        MSG_BUFFER_BUSY 0xc1    /*
-                                                * Sequencer wants to use the
-                                                * message buffer, but it
-                                                * already contains a message
-                                                */
-#define                        MSGIN_PHASEMIS  0xd1    /*
-                                                * Target changed phase on us
-                                                * when we were expecting
-                                                * another msgin byte.
-                                                */
-#define                        DATA_OVERRUN    0xe1    /*
-                                                * Target attempted to write
-                                                * beyond the bounds of its
-                                                * command.
-                                                */
-#define        BRKADRINT 0x08
-#define                SCSIINT   0x04
-#define                CMDCMPLT  0x02
-#define                SEQINT    0x01
-#define                INT_PEND  (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
+#define        ACCUM                           0x64
 
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors.  You usually cannot recover from
- * these without a full board reset.
- */
-#define ERROR                  0x092
-/*    UNUSED                   0xf0 */
-#define                PARERR          0x08
-#define                ILLOPCODE       0x04
-#define                ILLSADDR        0x02
-#define                ILLHADDR        0x01
+#define        SINDEX                          0x65
 
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-#define CLRINT                 0x092
-#define                CLRBRKADRINT    0x08
-#define                CLRSCSIINT      0x04
-#define                CLRCMDINT       0x02
-#define                CLRSEQINT       0x01
-
-#define        DFCNTRL                 0x093
-#define                WIDEODD         0x40
-#define                SCSIEN          0x20
-#define                SDMAEN          0x10
-#define                SDMAENACK       0x10
-#define                HDMAEN          0x08
-#define                HDMAENACK       0x08
-#define                DIRECTION       0x04
-#define                FIFOFLUSH       0x02
-#define                FIFORESET       0x01
-
-#define        DFSTATUS                0x094
-#define                HDONE           0x08
-#define                FIFOEMP         0x01
-
-#define        DFDAT                   0x099
+#define        DINDEX                          0x66
 
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-#define SCBCNT                 0x09a
-#define                SCBAUTO         0x80
-#define                SCBCNT_MASK     0x1f
+#define        ALLONES                         0x69
 
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the sequencer has yet to start)
- */
-#define QINFIFO                        0x09b
+#define        ALLZEROS                        0x6a
 
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-#define QINCNT                 0x09c
+#define        NONE                            0x6a
 
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-#define QOUTFIFO               0x09d
+#define        FLAGS                           0x6b
+#define                ZERO                    0x02
+#define                CARRY                   0x01
 
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-#define QOUTCNT                        0x09e
+#define        SINDIR                          0x6c
 
-/*
- * SCB Definition (p. 5-4)
- * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
- * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
- * whether or not to DMA an SCB from host ram. This flag prevents the
- * "re-fetching" of transactions that are requeued because the target is
- * busy with another command. We also use bits 6 & 7 to indicate whether
- * or not to initiate SDTR or WDTR respectively when starting this command.
- */
-#define SCBARRAY               0x0a0
-#define        SCB_CONTROL             0x0a0
-#define                NEEDWDTR        0x80
-#define                DISCENB         0x40
-#define                TAG_ENB         0x20
-#define                NEEDSDTR        0x10
-#define                DISCONNECTED    0x04
-#define                SCB_TAG_TYPE    0x03
-#define        SCB_TCL                 0x0a1
-#define        SCB_TARGET_STATUS       0x0a2
-#define        SCB_SGCOUNT             0x0a3
-#define        SCB_SGPTR               0x0a4
-#define                SCB_SGPTR0      0x0a4
-#define                SCB_SGPTR1      0x0a5
-#define                SCB_SGPTR2      0x0a6
-#define                SCB_SGPTR3      0x0a7
-#define        SCB_RESID_SGCNT         0x0a8
-#define SCB_RESID_DCNT         0x0a9
-#define                SCB_RESID_DCNT0 0x0a9
-#define                SCB_RESID_DCNT1 0x0aa
-#define                SCB_RESID_DCNT2 0x0ab
-#define SCB_DATAPTR            0x0ac
-#define                SCB_DATAPTR0    0x0ac
-#define                SCB_DATAPTR1    0x0ad
-#define                SCB_DATAPTR2    0x0ae
-#define                SCB_DATAPTR3    0x0af
-#define        SCB_DATACNT             0x0b0
-#define                SCB_DATACNT0    0x0b0
-#define                SCB_DATACNT1    0x0b1
-#define                SCB_DATACNT2    0x0b2
-/* UNUSED - QUAD PADDING       0x0b3 */
-#define SCB_CMDPTR             0x0b4
-#define                SCB_CMDPTR0     0x0b4
-#define                SCB_CMDPTR1     0x0b5
-#define                SCB_CMDPTR2     0x0b6
-#define                SCB_CMDPTR3     0x0b7
-#define        SCB_CMDLEN              0x0b8
-#define SCB_TAG                        0x0b9
-#define        SCB_NEXT                0x0ba
-#define        SCB_PREV                0x0bb
-
-#define        SG_SIZEOF               0x08            /* sizeof(struct ahc_dma) */
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-#define        SEECTL_2840             0x0c0
-/*     UNUSED                  0xf8 */
-#define                CS_2840         0x04
-#define                CK_2840         0x02
-#define                DO_2840         0x01
-
-#define        STATUS_2840             0x0c1
-#define                EEPROM_TF       0x80
-#define                BIOS_SEL        0x60
-#define                ADSEL           0x1e
-#define                DI_2840         0x01
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-#define DSPCISTATUS            0x086
+#define        DINDIR                          0x6d
 
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device.  In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device.  When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM.  When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.  
- *
- * After successful arbitration for the memory port, the SEECS bit of 
- * the SEECTL register is connected to the chip select.  The SEECK, 
- * SEEDO, and SEEDI are connected to the clock, data out, and data in 
- * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
- * gives us an 800 nsec timer.  After a write to the SEECTL register, 
- * the SEERDY goes high 800 nsec later.  The one exception to this is 
- * when we first request access to the memory port.  The SEERDY goes 
- * high to signify that access has been granted and, for this case, has 
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to 
- * read the serial EEPROM.
- */
-#define SEECTL                 0x01e
-#define                EXTARBACK       0x80
-#define                EXTARBREQ       0x40
-#define                SEEMS           0x20
-#define                SEERDY          0x10
-#define                SEECS           0x08
-#define                SEECK           0x04
-#define                SEEDO           0x02
-#define                SEEDI           0x01
-
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the sequencer code.
- *
- * The host adapter card (at least the BIOS) uses 20-2f for SCSI
- * device information, 32-33 and 5a-5f as well. As it turns out, the
- * BIOS trashes 20-2f, writing the synchronous negotiation results
- * on top of the BIOS values, so we re-use those for our per-target
- * scratchspace (actually a value that can be copied directly into
- * SCSIRATE).  The kernel driver will enable synchronous negotiation
- * for all targets that have a value other than 0 in the lower four
- * bits of the target scratch space.  This should work regardless of
- * whether the bios has been installed.
- */
+#define        FUNCTION1                       0x6e
 
-/*
- * 1 byte per target starting at this address for configuration values
- */
-#define TARG_SCRATCH           0x020
+#define        STACK                           0x6f
 
-/*
- * The sequencer will stick the frist byte of any rejected message here so
- * we can see what is getting thrown away.  Extended messages put the
- * extended message type in REJBYTE_EXT.
- */
-#define REJBYTE                        0x030
-#define REJBYTE_EXT            0x031
+#define        BCTL                            0x84
+#define                ACE                     0x08
+#define                ENABLE                  0x01
 
-/*
- * Bit vector of targets that have disconnection disabled.
- */
-#define        DISC_DSB                0x032
-#define                DISC_DSB_A      0x032
-#define                DISC_DSB_B      0x033
+#define        DSCOMMAND                       0x84
+#define                CACHETHEN               0x80
+#define                DPARCKEN                0x40
+#define                MPARCKEN                0x20
+#define                EXTREQLCK               0x10
 
-/*
- * Length of pending message
- */
-#define MSG_LEN                        0x034
-
-/* We reserve 8bytes to store outgoing messages */
-#define MSG0                   0x035
-#define                COMP_MSG0       0xcb      /* 2's complement of MSG0 */
-#define MSG1                   0x036
-#define MSG2                   0x037
-#define MSG3                   0x038
-#define MSG4                   0x039
-#define MSG5                   0x03a
-#define MSG6                   0x03b
-#define MSG7                   0x03c
+#define        BUSTIME                         0x85
+#define                BOFF                    0xf0
+#define                BON                     0x0f
 
-/*
- * These are offsets into the card's scratch ram.  Some of the values are
- * specified in the AHA2742 technical reference manual and are initialized
- * by the BIOS at boot time.
- */
-#define LASTPHASE              0x03d
-#define ARG_1                  0x03e
-#define                MAXOFFSET       0x01
-#define RETURN_1               0x03f
-#define                SEND_WDTR       0x80
-#define                SEND_SDTR       0x60
-#define                SEND_SENSE      0x40
-#define                SEND_REJ        0x20
-#define                SCB_PAGEDIN     0x10
-
-#define SIGSTATE               0x040
-
-#define DMAPARAMS              0x041   /* Parameters for DMA Logic */
-
-#define        SG_COUNT                0x042
-#define        SG_NEXT                 0x043   /* working value of SG pointer */
-#define                SG_NEXT0        0x043
-#define                SG_NEXT1        0x044
-#define                SG_NEXT2        0x045
-#define                SG_NEXT3        0x046
-
-#define        SCBCOUNT                0x047   /*
-                                        * Number of SCBs supported by
-                                        * this card.
-                                        */
-#define        COMP_SCBCOUNT           0x048   /*
-                                        * Two's compliment of SCBCOUNT
-                                        */
-#define QCNTMASK               0x049   /*
-                                        * Mask of bits to test against
-                                        * when looking at the Queue Count
-                                        * registers.  Works around a bug
-                                        * on aic7850 chips. 
-                                        */
-#define FLAGS                  0x04a
-#define                SINGLE_BUS      0x00
-#define                TWIN_BUS        0x01
-#define                WIDE_BUS        0x02
-#define                PAGESCBS        0x04
-#define                DPHASE          0x10
-#define                SELECTED        0x20
-#define                IDENTIFY_SEEN   0x40
-#define                RESELECTED      0x80
-
-#define        SAVED_TCL               0x04b   /*
-                                        * Temporary storage for the
-                                        * target/channel/lun of a
-                                        * reconnecting target
-                                        */
-#define        ACTIVE_A                0x04c
-#define        ACTIVE_B                0x04d
-#define WAITING_SCBH           0x04e   /*
-                                        * head of list of SCBs awaiting
-                                        * selection
-                                        */
-#define DISCONNECTED_SCBH      0x04f   /*
-                                        * head of list of SCBs that are
-                                        * disconnected.  Used for SCB
-                                        * paging.
-                                        */
-#define                SCB_LIST_NULL   0xff
-
-#define SAVED_LINKPTR          0x050
-#define SAVED_SCBPTR           0x051
-#define ULTRA_ENB              0x052
-#define ULTRA_ENB_B            0x053
-
-#define SCSICONF               0x05a
-#define                RESET_SCSI      0x40
-
-#define HOSTCONF               0x05d
-
-#define HA_274_BIOSCTRL                0x05f
-#define BIOSMODE               0x30
-#define BIOSDISABLED           0x30
-#define CHANNEL_B_PRIMARY      0x08
-
-/* Message codes */
-#define MSG_EXTENDED           0x01
-#define                MSG_SDTR        0x01
-#define                MSG_WDTR        0x03
-#define MSG_SDPTRS             0x02
-#define MSG_RDPTRS             0x03
-#define MSG_DISCONNECT         0x04
-#define MSG_INITIATOR_DET_ERROR        0x05
-#define MSG_ABORT              0x06
-#define        MSG_REJECT              0x07
-#define MSG_NOP                        0x08
-#define MSG_MSG_PARITY_ERROR   0x09
-#define MSG_BUS_DEVICE_RESET   0x0c
-#define MSG_ABORT_TAG          0x0d
-#define MSG_SIMPLE_TAG         0x20
-#define MSG_IDENTIFY           0x80
-
-/* WDTR Message values */
-#define        BUS_8_BIT               0x00
-#define BUS_16_BIT             0x01
-#define BUS_32_BIT             0x02
-
-#define MAX_OFFSET_8BIT                0x0f
-#define MAX_OFFSET_16BIT       0x08
+#define        BUSSPD                          0x86
+#define                DFTHRSH_100             0xc0
+#define                DFTHRSH                 0xc0
+#define                STBOFF                  0x38
+#define                STBON                   0x07
+
+#define        DSPCISTATUS                     0x86
+
+#define        HCNTRL                          0x87
+#define                POWRDN                  0x40
+#define                SWINT                   0x10
+#define                IRQMS                   0x08
+#define                PAUSE                   0x04
+#define                INTEN                   0x02
+#define                CHIPRST                 0x01
+#define                CHIPRSTACK              0x01
+
+#define        HADDR                           0x88
+
+#define        HCNT                            0x8c
+
+#define        SCBPTR                          0x90
+
+#define        INTSTAT                         0x91
+#define                SEQINT_MASK             0xf1
+#define                DATA_OVERRUN            0xe1
+#define                MSGIN_PHASEMIS          0xd1
+#define                MSG_BUFFER_BUSY         0xc1
+#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                EXTENDED_MSG            0x41
+#define                NO_MATCH                0x31
+#define                NO_IDENT                0x21
+#define                SEND_REJECT             0x11
+#define                INT_PEND                0x0f
+#define                BRKADRINT               0x08
+#define                SCSIINT                 0x04
+#define                CMDCMPLT                0x02
+#define                BAD_PHASE               0x01
+#define                SEQINT                  0x01
+
+#define        CLRINT                          0x92
+#define                CLRBRKADRINT            0x08
+#define                CLRSCSIINT              0x04
+#define                CLRCMDINT               0x02
+#define                CLRSEQINT               0x01
+
+#define        ERROR                           0x92
+#define                PARERR                  0x08
+#define                ILLOPCODE               0x04
+#define                ILLSADDR                0x02
+#define                ILLHADDR                0x01
+
+#define        DFCNTRL                         0x93
+
+#define        DFSTATUS                        0x94
+#define                DWORDEMP                0x20
+#define                MREQPEND                0x10
+#define                HDONE                   0x08
+#define                DFTHRESH                0x04
+#define                FIFOFULL                0x02
+#define                FIFOEMP                 0x01
+
+#define        DFDAT                           0x99
+
+#define        SCBCNT                          0x9a
+#define                SCBAUTO                 0x80
+#define                SCBCNT_MASK             0x1f
+
+#define        QINFIFO                         0x9b
+
+#define        QINCNT                          0x9c
+
+#define        QOUTFIFO                        0x9d
+
+#define        QOUTCNT                         0x9e
+
+#define        SCB_CONTROL                     0xa0
+#define                MK_MESSAGE              0x80
+#define                DISCENB                 0x40
+#define                TAG_ENB                 0x20
+#define                MUST_DMAUP_SCB          0x10
+#define                ABORT_SCB               0x08
+#define                DISCONNECTED            0x04
+#define                SCB_TAG_TYPE            0x03
+
+#define        SCB_BASE                        0xa0
+
+#define        SCB_TCL                         0xa1
+#define                TID                     0xf0
+#define                SELBUSB                 0x08
+#define                LID                     0x07
+
+#define        SCB_TARGET_STATUS               0xa2
+
+#define        SCB_SGCOUNT                     0xa3
+
+#define        SCB_SGPTR                       0xa4
+
+#define        SCB_RESID_SGCNT                 0xa8
+
+#define        SCB_RESID_DCNT                  0xa9
+
+#define        SCB_DATAPTR                     0xac
+
+#define        SCB_DATACNT                     0xb0
+
+#define        SCB_LINKED_NEXT                 0xb3
+
+#define        SCB_CMDPTR                      0xb4
+
+#define        SCB_CMDLEN                      0xb8
+
+#define        SCB_TAG                         0xb9
+
+#define        SCB_NEXT                        0xba
+
+#define        SCB_PREV                        0xbb
+
+#define        SCB_BUSYTARGETS                 0xbc
+
+#define        SEECTL_2840                     0xc0
+#define                CS_2840                 0x04
+#define                CK_2840                 0x02
+#define                DO_2840                 0x01
+
+#define        STATUS_2840                     0xc1
+#define                EEPROM_TF               0x80
+#define                BIOS_SEL                0x60
+#define                ADSEL                   0x1e
+#define                DI_2840                 0x01
+
+
+#define        BUS_8_BIT       0x00
+#define        MAX_OFFSET_8BIT 0x0f
+#define        BUS_16_BIT      0x01
+#define        MAX_OFFSET_16BIT        0x08
+#define        SCB_LIST_NULL   0xff
+#define        SG_SIZEOF       0x08
+#define        BUS_32_BIT      0x02
index 15dfb01f19cd3fac5d2c65d80bf4ca34936323c4..50ce159a2d77b39d5ec5ad2e1f889ad116c10b7f 100644 (file)
@@ -90,6 +90,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/nvram.h>
 
 #include <asm/setup.h>
 #include <asm/atarihw.h>
@@ -596,20 +597,6 @@ int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 #endif
 
 
-#define        RTC_READ(reg)                           \
-    ({ unsigned char   __val;                  \
-               outb(reg,&tt_rtc.regsel);       \
-               __val = tt_rtc.data;            \
-               __val;                          \
-       })
-
-#define        RTC_WRITE(reg,val)                      \
-    do {                                       \
-               outb(reg,&tt_rtc.regsel);       \
-               tt_rtc.data = (val);            \
-       } while(0)
-    
-                                  
 int atari_scsi_detect (Scsi_Host_Template *host)
 {
        static int called = 0;
@@ -645,20 +632,11 @@ int atari_scsi_detect (Scsi_Host_Template *host)
                /* use 7 as default */
                host->this_id = 7;
                /* Test if a host id is set in the NVRam */
-               if (ATARIHW_PRESENT(TT_CLK)) {
-                       unsigned char sum = 0, b;
-                       int i;
-                       
-                       /* Make checksum */
-                       for( i = 14; i < 62; ++i )
-                               sum += RTC_READ(i);
-                       
-                       if (/* NV-Ram checksum valid? */
-                               RTC_READ(62) == sum && RTC_READ(63) == ~sum &&
-                               /* Arbitration enabled? (for TOS) */
-                               (b = RTC_READ( 30 )) & 0x80) {
+               if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
+                       unsigned char b = nvram_read_byte( 14 );
+                       /* Arbitration enabled? (for TOS) If yes, use configured host ID */
+                       if (b & 0x80)
                                host->this_id = b & 7;
-                       }
                }
        }
 
index 0380ff99a76971024d28ba3cadc27c41f5398b99..b479cc9fcecacae112949dc5d77e7faf04f4609c 100644 (file)
@@ -1705,7 +1705,7 @@ int esp_abort(Scsi_Cmnd *SCptr)
         * the nexus and tell the device to abort.  However, we really
         * cannot 'reconnect' per se, therefore we tell the upper layer
         * the safest thing we can.  This is, wait a bit, if nothing
-        * happens, we are really hung so reset the bug.
+        * happens, we are really hung so reset the bus.
         */
 
        return SCSI_ABORT_SNOOZE;
@@ -1743,11 +1743,10 @@ static void esp_done(struct Sparc_ESP *esp, int error)
                                             done_SC->request_bufflen,
                                             esp->edev->my_bus);
                } else {
-                       struct scatterlist *scl = (struct scatterlist *)done_SC->buffer;
 #ifdef DEBUG_ESP_SG
                        printk("esp%d: unmapping sg ", esp->esp_id);
 #endif
-                       mmu_release_scsi_sgl((struct mmu_sglist *) scl,
+                       mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
                                             done_SC->use_sg - 1,
                                             esp->edev->my_bus);
 #ifdef DEBUG_ESP_SG
@@ -2010,7 +2009,7 @@ static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev)
                if(sz > 0x1000000)
                        sz = 0x1000000;
        } else {
-               base = ((__u32)sp->SCp.ptr);
+               base = ((__u32)((unsigned long)sp->SCp.ptr));
                base &= (0x1000000 - 1);
                end = (base + sp->SCp.this_residual);
                if(end > 0x1000000)
@@ -2280,11 +2279,12 @@ static inline int esp_do_data(struct Sparc_ESP *esp, struct Sparc_ESP_regs *ereg
                        tmp |= DMA_ST_WRITE;
                else
                        tmp &= ~(DMA_ST_WRITE);
-               dregs->st_addr = ((__u32)SCptr->SCp.ptr);
+               dregs->st_addr = ((__u32)((unsigned long)SCptr->SCp.ptr));
                dregs->cond_reg = tmp;
        } else {
                esp_setcount(eregs, hmuch, 0);
-               dma_setup(dregs, esp->dma->revision, ((__u32)SCptr->SCp.ptr),
+               dma_setup(dregs, esp->dma->revision,
+                         ((__u32)((unsigned long)SCptr->SCp.ptr)),
                          hmuch, (thisphase == in_datain));
                ESPDATA(("DMA|TI --> do_intr_end\n"));
                esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
@@ -4059,8 +4059,12 @@ repeat:
 }
 #else
 
+/* XXX Gross hack for sun4u SMP, fix it right later... -DaveM */
 #ifdef __sparc_v9__
-#error Dave you need to fix some things first...
+extern unsigned char ino_to_pil[];
+#define INO_TO_PIL(esp)                (ino_to_pil[(esp)->irq])
+#else
+#define INO_TO_PIL(esp)                ((esp)->irq & 0xf)
 #endif
 
 /* For SMP we only service one ESP on the list list at our IRQ level! */
@@ -4070,7 +4074,7 @@ static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 
        /* Handle all ESP interrupts showing at this IRQ level. */
        for_each_esp(esp) {
-               if((esp->irq & 0xf) == irq) {
+               if(INO_TO_PIL(esp) == irq) {
                        if(DMA_IRQ_P(esp->dregs)) {
                                DMA_INTSOFF(esp->dregs);
 
index f2bb6c3392ee3b8a24ff4f191c4cc75237b54691..c5715819567f093d1bda327d6e6d3ae71634b9b8 100644 (file)
@@ -58,13 +58,15 @@ static inline int copy_from_user(void *dst, void *src, unsigned long len)
 #endif
 
 #ifdef DEBUG
-#define DPRINTK(D) printk D;
+#define DPRINTK(D) (printk D)
 #else
-#define DPRINTK(D)
+#define DPRINTK(D) ((void)0)
 #endif
 
 #define AUTOFS_SUPER_MAGIC 0x0187
 
+#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ)        /* Time before asking the daemon again */
+
 /* Structures associated with the root directory hash */
 
 #define AUTOFS_HASH_SIZE 67
index 61900c481732d9fb18bab5741fff2a5e022ad234..59a30b0e843ca0a8e2b890816010735cf798335b 100644 (file)
@@ -44,16 +44,20 @@ static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry)
 }
 
 static struct file_operations autofs_dir_operations = {
-       NULL,                   /* lseek */
+       NULL,                   /* llseek */
        NULL,                   /* read */
        NULL,                   /* write */
        autofs_dir_readdir,     /* readdir */
-       NULL,                   /* select */
+       NULL,                   /* poll */
        NULL,                   /* ioctl */
        NULL,                   /* mmap */
        NULL,                   /* open */
        NULL,                   /* release */
-       NULL                    /* fsync */
+       NULL,                   /* fsync */
+       NULL,                   /* fasync */
+       NULL,                   /* check_media_change */
+       NULL,                   /* revalidate */
+       NULL                    /* lock */
 };
 
 struct inode_operations autofs_dir_inode_operations = {
@@ -68,10 +72,14 @@ struct inode_operations autofs_dir_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        NULL,                   /* readlink */
-       NULL,                   /* read_page */
+       NULL,                   /* follow_link */
+       NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
        NULL,                   /* truncate */
-       NULL                    /* permission */
+       NULL,                   /* permission */
+       NULL,                   /* smap */
+       NULL,                   /* updatepage */
+       NULL                    /* revalidate */
 };
 
index 870ff120da121880e4b5b2637c90374fac5dbfa5..9422237d5de6d56f4894fcca3faeff112c3f5743 100644 (file)
@@ -172,27 +172,27 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
        unlock_super(s);
        s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
        if (!s->s_root) {
-               s->s_dev = 0;
-               kfree(sbi);
                printk("autofs: get root inode failed\n");
+               kfree(sbi);
+               s->s_dev = 0;
                MOD_DEC_USE_COUNT;
                return NULL;
        }
 
        if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+               printk("autofs: called with bogus options\n");
                dput(s->s_root);
-               s->s_dev = 0;
                kfree(sbi);
-               printk("autofs: called with bogus options\n");
+               s->s_dev = 0;
                MOD_DEC_USE_COUNT;
                return NULL;
        }
 
        if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
+               printk("autofs: kernel does not match daemon version\n");
                dput(s->s_root);
-               s->s_dev = 0;
                kfree(sbi);
-               printk("autofs: kernel does not match daemon version\n");
+               s->s_dev = 0;
                MOD_DEC_USE_COUNT;
                return NULL;
        }
@@ -207,8 +207,8 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
                        printk("autofs: could not open pipe file descriptor\n");
                }
                dput(s->s_root);
-               s->s_dev = 0;
                kfree(sbi);
+               s->s_dev = 0;
                MOD_DEC_USE_COUNT;
                return NULL;
        }
index 37b1f781ae998a1423524c049c3ca4609f14a42c..c09bc669e06ee7228071169a0ecd16998ffab838 100644 (file)
@@ -24,16 +24,20 @@ static int autofs_root_mkdir(struct inode *,struct dentry *,int);
 static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
 
 static struct file_operations autofs_root_operations = {
-        NULL,                   /* lseek */
+        NULL,                   /* llseek */
         NULL,                   /* read */
         NULL,                   /* write */
         autofs_root_readdir,    /* readdir */
-        NULL,                   /* select */
+        NULL,                   /* poll */
         autofs_root_ioctl,     /* ioctl */
         NULL,                   /* mmap */
         NULL,                   /* open */
         NULL,                   /* release */
-        NULL                    /* fsync */
+        NULL,                  /* fsync */
+       NULL,                   /* fasync */
+       NULL,                   /* check_media_change */
+       NULL,                   /* revalidate */
+       NULL                    /* lock */
 };
 
 struct inode_operations autofs_root_inode_operations = {
@@ -53,7 +57,10 @@ struct inode_operations autofs_root_inode_operations = {
         NULL,                   /* writepage */
         NULL,                   /* bmap */
         NULL,                   /* truncate */
-        NULL                    /* permission */
+        NULL,                  /* permission */
+       NULL,                   /* smap */
+       NULL,                   /* updatepage */
+       NULL                    /* revalidate */
 };
 
 static int autofs_root_readdir(struct inode *inode, struct file *filp,
@@ -97,24 +104,31 @@ static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, s
 {
        struct inode * inode;
        struct autofs_dir_ent *ent;
-       
+
        while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
                int status = autofs_wait(sbi, &dentry->d_name);
 
                /* Turn this into a real negative dentry? */
                if (status == -ENOENT) {
-                       dentry->d_flags = 0;
-                       return 0;
+                       dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
+                       dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+                       return 1;
+               } else if (status) {
+                       /* Return a negative dentry, but leave it "pending" */
+                       return 1;
                }
-               if (status)
-                       return status;
        }
 
+       /* Abuse this field as a pointer to the directory entry, used to
+          find the expire list pointers */
+       dentry->d_time = (unsigned long) ent;
+       
        if (!dentry->d_inode) {
                inode = iget(sb, ent->ino);
-               if (!inode)
-                       return -EACCES;
-
+               if (!inode) {
+                       /* Failed, but leave pending for next time */
+                       return 1;
+               }
                dentry->d_inode = inode;
        }
 
@@ -122,8 +136,11 @@ static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, s
                while (dentry == dentry->d_mounts)
                        schedule();
        }
-       dentry->d_flags = 0;
-       return 0;
+
+       autofs_update_usage(&sbi->dirhash,ent);
+
+       dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+       return 1;
 }
 
 
@@ -137,23 +154,25 @@ static int autofs_revalidate(struct dentry * dentry)
 {
        struct autofs_sb_info *sbi;
        struct inode * dir = dentry->d_parent->d_inode;
+       struct autofs_dir_ent *ent;
 
        sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
 
-       /* Incomplete dentry? */
-       if (dentry->d_flags) {
+       /* Pending dentry */
+       if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
                if (autofs_oz_mode(sbi))
                        return 1;
 
-               try_to_fill_dentry(dentry, dir->i_sb, sbi);
-               return 1;
+               return try_to_fill_dentry(dentry, dir->i_sb, sbi);
        }
 
-       /* Negative dentry.. Should we time these out? */
+       /* Negative dentry.. invalidate if "old" */
        if (!dentry->d_inode)
-               return 1;
+               return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
 
-       /* We should update the usage stuff here.. */
+       /* Update the usage list */
+       ent = (struct autofs_dir_ent *) dentry->d_time;
+       autofs_update_usage(&sbi->dirhash,ent);
        return 1;
 }
 
@@ -186,12 +205,13 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
         * We need to do this before we release the directory semaphore.
         */
        dentry->d_revalidate = autofs_revalidate;
-       dentry->d_flags = 1;
+       dentry->d_flags |= DCACHE_AUTOFS_PENDING;
        d_add(dentry, NULL);
 
        up(&dir->i_sem);
        autofs_revalidate(dentry);
        down(&dir->i_sem);
+       
        return 0;
 }
 
index e3ff3d31bec00dc00732af7a1a70deae78a6a828..b42955feb05828f3b14742e392a298f7d8284f90 100644 (file)
@@ -51,5 +51,8 @@ struct inode_operations autofs_symlink_inode_operations = {
        NULL,                   /* writepage */
        NULL,                   /* bmap */
        NULL,                   /* truncate */
-       NULL                    /* permission */
+       NULL,                   /* permission */
+       NULL,                   /* smap */
+       NULL,                   /* updatepage */
+       NULL                    /* revalidate */
 };
index 3ca36804b0db733601138a7d1bd6b37112abdb6f..cb4ec5eefe92563dd5e6e465dbed1a514f23f39b 100644 (file)
@@ -561,6 +561,7 @@ struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
                if (!bh)
                        return NULL;
                bh->b_count++;
+               bh->b_lru_time = jiffies;
                wait_on_buffer(bh);
                if (bh->b_dev == dev            &&
                    bh->b_blocknr == block      &&
@@ -643,34 +644,20 @@ void set_blocksize(kdev_t dev, int size)
        }
 }
 
-/* Check if a buffer is OK to be reclaimed. */
-static inline int can_reclaim(struct buffer_head *bh, int size)
-{
-       if (bh->b_count                 || 
-           buffer_protected(bh)        ||
-           buffer_locked(bh))
-               return 0;
-                        
-       if (buffer_dirty(bh)) {
-               refile_buffer(bh);
-               return 0;
-       }
-
-       if (bh->b_size != size)
-               return 0;
-
-       return 1;
-}
-
-/* Find a candidate buffer to be reclaimed. */
-static struct buffer_head *find_candidate(struct buffer_head *list,
+/*
+ * Find a candidate buffer to be reclaimed. 
+ * N.B. Must search the entire BUF_LOCKED list rather than terminating
+ * when the first locked buffer is found.  Buffers are unlocked at 
+ * completion of IO, and under some conditions there may be (many)
+ * unlocked buffers after the first locked one.
+ */
+static struct buffer_head *find_candidate(struct buffer_head *bh,
                                          int *list_len, int size)
 {
-       struct buffer_head *bh;
-       
-       for (bh = list; 
-            bh && (*list_len) > 0; 
-            bh = bh->b_next_free, (*list_len)--) {
+       if (!bh)
+               goto no_candidate;
+
+       for (; (*list_len) > 0; bh = bh->b_next_free, (*list_len)--) {
                if (size != bh->b_size) {
                        /* This provides a mechanism for freeing blocks
                         * of other sizes, this is necessary now that we
@@ -681,110 +668,144 @@ static struct buffer_head *find_candidate(struct buffer_head *list,
                                break;
                        continue;
                }
-
-               if (buffer_locked(bh) && bh->b_list == BUF_LOCKED) {
-                       /* Buffers are written in the order they are placed 
-                        * on the locked list. If we encounter a locked
-                        * buffer here, this means that the rest of them
-                        * are also locked.
-                        */
-                       (*list_len) = 0;
-                       return NULL;
-               }
-
-               if (can_reclaim(bh,size))
-                   return bh;
+               else if (!bh->b_count           && 
+                        !buffer_locked(bh)     && 
+                        !buffer_protected(bh)  &&
+                        !buffer_dirty(bh)) 
+                       return bh;
        }
 
+no_candidate:
        return NULL;
 }
 
 static void refill_freelist(int size)
 {
-       struct buffer_head * bh;
+       struct buffer_head * bh, * next;
        struct buffer_head * candidate[BUF_DIRTY];
-       unsigned int best_time, winner;
        int buffers[BUF_DIRTY];
        int i;
-       int needed;
+       int needed, obtained=0;
 
        refilled = 1;
-       /* If there are too many dirty buffers, we wake up the update process
-        * now so as to ensure that there are still clean buffers available
-        * for user processes to use (and dirty).
-        */
        
        /* We are going to try to locate this much memory. */
        needed = bdf_prm.b_un.nrefill * size;  
 
-       while ((nr_free_pages > min_free_pages*2)       &&
-              (needed > 0)                             &&
-              grow_buffers(GFP_BUFFER, size))
-               needed -= PAGE_SIZE;
+       while ((nr_free_pages > min_free_pages*2) && 
+               grow_buffers(GFP_BUFFER, size)) {
+               obtained += PAGE_SIZE;
+               if (obtained >= needed)
+                       return;
+       }
 
+       /*
+        * Update the needed amount based on the number of potentially
+        * freeable buffers. We don't want to free more than one quarter
+        * of the available buffers.
+        */
+       i = (nr_buffers_type[BUF_CLEAN] + nr_buffers_type[BUF_LOCKED]) >> 2;
+       if (i < bdf_prm.b_un.nrefill) {
+               needed = i * size;
+               if (needed < PAGE_SIZE)
+                       needed = PAGE_SIZE;
+       }
+
+       /* 
+        * OK, we cannot grow the buffer cache, now try to get some
+        * from the lru list.
+        */
 repeat:
-       if(needed <= 0)
+       if (obtained >= needed)
                return;
 
-       /* OK, we cannot grow the buffer cache, now try to get some
-        * from the lru list.
-        *
+       /*
         * First set the candidate pointers to usable buffers.  This
-        * should be quick nearly all of the time.
+        * should be quick nearly all of the time.  N.B. There must be 
+        * no blocking calls after setting up the candidate[] array!
         */
-
-       for(i=0; i<BUF_DIRTY; i++) {
+       for (i = BUF_CLEAN; i<BUF_DIRTY; i++) {
                buffers[i] = nr_buffers_type[i];
                candidate[i] = find_candidate(lru_list[i], &buffers[i], size);
        }
        
-       /* Now see which candidate wins the election. */
-       
-       winner = best_time = UINT_MAX;  
-       for(i=0; i<BUF_DIRTY; i++) {
-               if(!candidate[i])
-                       continue;
-               if(candidate[i]->b_lru_time < best_time) {
-                       best_time = candidate[i]->b_lru_time;
-                       winner = i;
-               }
-       }
-       
-       /* If we have a winner, use it, and then get a new candidate from that list. */
-       if(winner != UINT_MAX) {
-               i = winner;
-               while (needed>0 && (bh=candidate[i])) {
-                       candidate[i] = bh->b_next_free;
-                       if(candidate[i] == bh)
-                               candidate[i] = NULL;  /* Got last one */                
-                       remove_from_queues(bh);
-                       bh->b_dev = B_FREE;
-                       put_last_free(bh);
-                       needed -= bh->b_size;
-                       buffers[i]--;
-                       if(buffers[i] == 0)
-                               candidate[i] = NULL;
-               
-                       if (candidate[i] && !can_reclaim(candidate[i],size))
-                               candidate[i] = find_candidate(candidate[i],
-                                                             &buffers[i], size);
+       /*
+        * Select the older of the available buffers until we reach our goal.
+        */
+       for (;;) {
+               i = BUF_CLEAN;
+               if (!candidate[BUF_CLEAN]) {
+                       if (!candidate[BUF_LOCKED])
+                               break;
+                       i = BUF_LOCKED;
                }
-               goto repeat;
-       }
+               else if (candidate[BUF_LOCKED] &&
+                               (candidate[BUF_LOCKED]->b_lru_time < 
+                                candidate[BUF_CLEAN ]->b_lru_time))
+                       i = BUF_LOCKED;
+               /*
+                * Free the selected buffer and get the next candidate.
+                */
+               bh = candidate[i];
+               next = bh->b_next_free;
+
+               obtained += bh->b_size;
+               remove_from_queues(bh);
+               put_last_free(bh);
+               if (obtained >= needed)
+                       return;
+
+               if (--buffers[i] && bh != next)
+                       candidate[i] = find_candidate(next, &buffers[i], size);
+               else
+                       candidate[i] = NULL;
+       }       
+
+       /*
+        * If we achieved at least half of our goal, return now.
+        */
+       if (obtained >= (needed >> 1))
+               return;
        
        /* Too bad, that was not enough. Try a little harder to grow some. */
        if (nr_free_pages > min_free_pages + 5) {
                if (grow_buffers(GFP_BUFFER, size)) {
-                       needed -= PAGE_SIZE;
+                       obtained += PAGE_SIZE;
                        goto repeat;
                }
        }
-       
-       /* And repeat until we find something good. */
+
+       /*
+        * Make one more attempt to allocate some buffers.
+        */
        if (grow_buffers(GFP_ATOMIC, size))
-               needed -= PAGE_SIZE;
-       else
-               wakeup_bdflush(1);
+               obtained += PAGE_SIZE;
+
+       /*
+        * If we got any buffers, or another task freed some, 
+        * return now to let this task proceed.
+        */
+       if (obtained || free_list[BUFSIZE_INDEX(size)]) {
+#ifdef BUFFER_DEBUG
+printk("refill_freelist: obtained %d of %d, free list=%d\n", 
+obtained, needed, free_list[BUFSIZE_INDEX(size)] != NULL);
+#endif
+               return;
+       }
+
+       /*
+        * System is _very_ low on memory ... wake up bdflush and wait.
+        */
+#ifdef BUFFER_DEBUG
+printk("refill_freelist: waking bdflush\n");
+#endif
+       wakeup_bdflush(1);
+       /*
+        * While we slept, other tasks may have needed buffers and entered
+        * refill_freelist.  This could be a big problem ... reset the 
+        * needed amount to the absolute minimum.
+        */
+       needed = size;
        goto repeat;
 }
 
@@ -832,6 +853,8 @@ repeat:
         * and that it's unused (b_count=0), unlocked (buffer_locked=0), and clean.
         */
        bh->b_count=1;
+       bh->b_list      = BUF_CLEAN;
+       bh->b_lru_time  = jiffies;
        bh->b_flushtime=0;
        bh->b_state=(1<<BH_Touched);
        bh->b_dev=dev;
@@ -856,6 +879,16 @@ void set_writetime(struct buffer_head * buf, int flag)
 }
 
 
+/*
+ * Put a buffer into the appropriate list, without side-effects.
+ */
+static inline void file_buffer(struct buffer_head *bh, int list)
+{
+       remove_from_queues(bh);
+       bh->b_list = list;
+       insert_into_queues(bh);
+}
+
 /*
  * A buffer may need to be moved from one buffer list to another
  * (e.g. in case it is not shared any more). Handle this.
@@ -874,15 +907,9 @@ void refile_buffer(struct buffer_head * buf)
                dispose = BUF_LOCKED;
        else
                dispose = BUF_CLEAN;
-       if(dispose == BUF_CLEAN)
-               buf->b_lru_time = jiffies;
        if(dispose != buf->b_list) {
-               if(dispose == BUF_DIRTY)
-                        buf->b_lru_time = jiffies;
-               remove_from_queues(buf);
-               buf->b_list = dispose;
-               insert_into_queues(buf);
-               if (dispose == BUF_DIRTY) {
+               file_buffer(buf, dispose);
+               if(dispose == BUF_DIRTY) {
                        int too_many = (nr_buffers * bdf_prm.b_un.nfract/100);
 
                        /* This buffer is dirty, maybe we need to start flushing.
index 26f668e7fade0a807bd9a6478ed03203c29305fc..db6c64d7f896afd253d321b6229c2c728b60212d 100644 (file)
@@ -210,7 +210,9 @@ int check_disk_change(kdev_t dev)
        printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
                kdevname(dev));
 
-       invalidate_inodes(dev);
+       if (invalidate_inodes(dev))
+               printk("VFS: busy inodes on changed media..\n");
+
        invalidate_buffers(dev);
 
        if (fops->revalidate)
index 6223c1c48ece9e48310656593c1e4bb1c49c432d..5fdcb772edaeb8528eb32f36a2b23925a3666cd7 100644 (file)
@@ -276,8 +276,7 @@ int fat_free(struct inode *inode,int skip)
                }
        }
        if (last)
-               fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits ==
-                   12 ? EOF_FAT12 : EOF_FAT16);
+               fat_access(inode->i_sb,last,EOF_FAT(inode->i_sb));
        else {
                MSDOS_I(inode)->i_start = 0;
                mark_inode_dirty(inode);
index ee0df4a15e88ac58b6087d35c91d2aac1d42f873..5b71573b38cabd6a832c34700d66edf45f6590db 100644 (file)
@@ -138,8 +138,7 @@ printk("free cluster: %d\n",nr);
                unlock_fat(sb);
                return -ENOSPC;
        }
-       fat_access(sb,nr,MSDOS_SB(sb)->fat_bits == 12 ?
-           EOF_FAT12 : EOF_FAT16);
+       fat_access(sb,nr,EOF_FAT(sb));
        if (MSDOS_SB(sb)->free_clusters != -1)
                MSDOS_SB(sb)->free_clusters--;
        unlock_fat(sb);
index 8fc081b77844881ddb51f850915a2ec6f39448f4..5bddf1b44471977376cee55758929aa72723c47b 100644 (file)
@@ -206,14 +206,37 @@ void clear_inode(struct inode *inode)
        inode->i_state = 0;
 }
 
-#define CAN_UNUSE(inode) \
-       (((inode)->i_count == 0) && \
-        ((inode)->i_nrpages == 0) && \
-        (!(inode)->i_state))
+/*
+ * Dispose-list gets a local list, so it doesn't need to
+ * worry about list corruption.
+ */
+static void dispose_list(struct list_head * head)
+{
+       struct list_head *next;
+
+       next = head->next;
+       for (;;) {
+               struct list_head * tmp = next;
+               struct inode * inode;
+
+               next = next->next;
+               if (tmp == head)
+                       break;
+               inode = list_entry(tmp, struct inode, i_list);
+               truncate_inode_pages(inode, 0);
+               list_del(&inode->i_list);
+       }
 
-static void invalidate_list(struct list_head *head, kdev_t dev)
+       /* Add them all to the unused list in one fell swoop */
+       spin_lock(&inode_lock);
+       list_splice(head, &inode_unused);
+       spin_unlock(&inode_lock);
+}
+
+static int invalidate_list(struct list_head *head, kdev_t dev, struct list_head * dispose)
 {
        struct list_head *next;
+       int busy = 0;
 
        next = head->next;
        for (;;) {
@@ -225,22 +248,39 @@ static void invalidate_list(struct list_head *head, kdev_t dev)
                        break;
                inode = list_entry(tmp, struct inode, i_list);
                if (inode->i_dev != dev)
-                       continue;               
-               if (!CAN_UNUSE(inode))
                        continue;
-               list_del(&inode->i_hash);
-               INIT_LIST_HEAD(&inode->i_hash);
-               list_del(&inode->i_list);
-               list_add(&inode->i_list, &inode_unused);
+               if (!inode->i_count && !inode->i_state) {
+                       list_del(&inode->i_hash);
+                       INIT_LIST_HEAD(&inode->i_hash);
+                       list_del(&inode->i_list);
+                       list_add(&inode->i_list, dispose);
+                       continue;
+               }
+               busy = 1;
        }
+       return busy;
 }
 
-void invalidate_inodes(kdev_t dev)
+/*
+ * This is a two-stage process. First we collect all
+ * offending inodes onto the throw-away list, and in
+ * the second stage we actually dispose of them. This
+ * is because we don't want to sleep while messing
+ * with the global lists..
+ */
+int invalidate_inodes(kdev_t dev)
 {
+       int busy;
+       LIST_HEAD(throw_away);
+
        spin_lock(&inode_lock);
-       invalidate_list(&inode_in_use, dev);
-       invalidate_list(&inode_dirty, dev);
+       busy = invalidate_list(&inode_in_use, dev, &throw_away);
+       busy |= invalidate_list(&inode_dirty, dev, &throw_away);
        spin_unlock(&inode_lock);
+
+       dispose_list(&throw_away);
+
+       return busy;
 }
 
 /*
@@ -251,6 +291,11 @@ void invalidate_inodes(kdev_t dev)
  * Otherwise we just move the inode to be the first inode and expect to
  * get back to the problem later..
  */
+#define CAN_UNUSE(inode) \
+       (((inode)->i_count == 0) && \
+        ((inode)->i_nrpages == 0) && \
+        (!(inode)->i_state))
+
 static void try_to_free_inodes(void)
 {
        struct list_head * tmp;
index a17100943c9a4f3a57c474f2123af3fbc7916dea..dc2810fde8d798023d6e9d1ef7f6d7cbdb423259 100644 (file)
@@ -455,7 +455,7 @@ static unsigned long get_wchan(struct task_struct *p)
                return ((unsigned long *)schedule_frame)[12];
            }
            return pc;
-       }
+       }       
 #elif defined(__mc68000__)
        {
            unsigned long fp, pc;
@@ -480,6 +480,8 @@ static unsigned long get_wchan(struct task_struct *p)
                    fp = *(unsigned long *) fp;
            } while (count++ < 16);
        }
+#elif defined(__powerpc__)
+       return (p->tss.wchan);
 #endif
        return 0;
 }
@@ -505,6 +507,9 @@ static unsigned long get_wchan(struct task_struct *p)
              eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc;    \
         eip; })
 #define        KSTK_ESP(tsk)   ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(__powerpc__)
+#define KSTK_EIP(tsk)  ((tsk)->tss.regs->nip)
+#define KSTK_ESP(tsk)  ((tsk)->tss.regs->gpr[1])
 #elif defined (__sparc_v9__)
 # define KSTK_EIP(tsk)  ((tsk)->tss.kregs->tpc)
 # define KSTK_ESP(tsk)  ((tsk)->tss.kregs->u_regs[UREG_FP])
index 346e72ed1a7bd8ef1529cdde5fd3f34de5a7c134..5d98507f03d7dcb114abe3d8f686bdf0d7348738 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
+/* $Id: openpromfs.c,v 1.20 1997/07/22 06:40:07 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -54,12 +54,10 @@ static struct openpromfs_dev **devices;
 #define NODE2INO(node) (node + PROC_OPENPROM_FIRST)
 #define NODEP2INO(no) (no + PROC_OPENPROM_FIRST + last_node)
 
-static int openpromfs_create (struct inode *, const char *, int, int,
-                             struct inode **);
+static int openpromfs_create (struct inode *, struct dentry *, int);
 static int openpromfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int openpromfs_lookup(struct inode *, const char *, int,
-                            struct inode **);
-static int openpromfs_unlink (struct inode *, const char *, int);
+static int openpromfs_lookup(struct inode *, struct dentry *dentry);
+static int openpromfs_unlink (struct inode *, struct dentry *dentry);
 
 static long nodenum_read(struct inode *inode, struct file *file,
                         char *buf, unsigned long count)
@@ -602,8 +600,7 @@ static int lookup_children(u16 n, const char * name, int len)
        return 0;
 }
 
-static int openpromfs_lookup(struct inode * dir, const char * name, int len,
-       struct inode ** result)
+static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
 {
        int ino = 0;
 #define OPFSL_DIR      0
@@ -613,40 +610,21 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
        int type = 0;
        char buffer[128];
        char *p;
+       const char *name;
        u32 n;
        u16 dirnode;
+       unsigned int len;
        int i;
        struct inode *inode;
        struct openpromfs_dev *d = NULL;
        char buffer2[64];
        
-       *result = NULL;
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               iput(dir);
-               return -ENOTDIR;
-       }
-       *result = dir;
-       if (!len) return 0;
-       if (name [0] == '.') {
-               if (len == 1)
-                       return 0;
-               if (name [1] == '.' && len == 2) {
-                       if (dir->i_ino == PROC_OPENPROM) {
-                               inode = proc_get_inode (dir->i_sb,
-                                                       PROC_ROOT_INO,
-                                                       &proc_root);
-                               iput(dir);
-                               if (!inode)
-                                       return -EINVAL;
-                               *result = inode;
-                               return 0;
-                       }
-                       ino = NODE2INO(NODE(dir->i_ino).parent);
-                       type = OPFSL_DIR;
-               } else if (len == 5 && !strncmp (name + 1, "node", 4)) {
-                       ino = NODEP2INO(NODE(dir->i_ino).first_prop);
-                       type = OPFSL_NODENUM;
-               }
+       inode = NULL;
+       name = dentry->d_name.name;
+       len = dentry->d_name.len;
+       if (name [0] == '.' && len == 5 && !strncmp (name + 1, "node", 4)) {
+               ino = NODEP2INO(NODE(dir->i_ino).first_prop);
+               type = OPFSL_NODENUM;
        }
        if (!ino) {
                u16 node = NODE(dir->i_ino).child;
@@ -712,13 +690,10 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
                ino = lookup_children (NODE(dir->i_ino).child, name, len);
                if (ino)
                        type = OPFSL_DIR;
-               else {
-                       iput(dir);
+               else
                        return -ENOENT;
-               }
        }
        inode = proc_get_inode (dir->i_sb, ino, 0);
-       iput(dir);
        if (!inode)
                return -EINVAL;
        switch (type) {
@@ -762,7 +737,7 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
                inode->i_rdev = d->rdev;
                break;
        }               
-       *result = inode;
+       d_add(dentry, inode);
        return 0;
 }
 
@@ -858,16 +833,14 @@ static int openpromfs_readdir(struct inode * inode, struct file * filp,
        return 0;
 }
 
-static int openpromfs_create (struct inode *dir, const char *name, int len, 
-                             int mode, struct inode **result)
+static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode)
 {
        char *p;
        struct inode *inode;
        
-       *result = NULL;
        if (!dir)
                return -ENOENT;
-       if (len > 256) {
+       if (dentry->d_name.len > 256) {
                iput (dir);
                return -EINVAL;
        }
@@ -875,13 +848,13 @@ static int openpromfs_create (struct inode *dir, const char *name, int len,
                iput (dir);
                return -EIO;
        }
-       p = kmalloc (len + 1, GFP_KERNEL);
+       p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL);
        if (!p) {
                iput (dir);
                return -ENOMEM;
        }
-       strncpy (p, name, len);
-       p [len] = 0;
+       strncpy (p, dentry->d_name.name, dentry->d_name.len);
+       p [dentry->d_name.len] = 0;
        alias_names [aliases_nodes++] = p;
        inode = proc_get_inode (dir->i_sb,
                                NODEP2INO(NODE(dir->i_ino).first_prop)
@@ -895,17 +868,19 @@ static int openpromfs_create (struct inode *dir, const char *name, int len,
        if (inode->i_size < 0) inode->i_size = 0;
        inode->u.generic_ip = (void *)(long)(((u16)aliases) | 
                        (((u16)(aliases_nodes - 1)) << 16));
-       *result = inode;
+       d_instantiate(dentry, inode);
        return 0;
 }
 
-static int openpromfs_unlink (struct inode *dir, const char *name, int len)
+static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
 {
+       unsigned int len;
        char *p;
+       const char *name;
        int i;
        
-       if (!dir)
-               return -ENOENT;
+       name = dentry->d_name.name;
+       len = dentry->d_name.len;
        for (i = 0; i < aliases_nodes; i++)
                if ((strlen (alias_names [i]) == len)
                    && !strncmp (name, alias_names[i], len)) {
@@ -919,7 +894,7 @@ static int openpromfs_unlink (struct inode *dir, const char *name, int len)
                        buffer [10 + len] = 0;
                        prom_feval (buffer);
                }
-       iput (dir);
+       d_delete(dentry);
        return 0;
 }
 
index 2b456ca5729fb66e3bef28a189722862d8b46fe4..544e74d05ae959dca877cf1156ebf8f35adcb7f4 100644 (file)
@@ -151,14 +151,14 @@ struct proc_dir_entry proc_sys_root = {
 #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
 
 static int (*proc_openprom_defreaddir_ptr)(struct inode *, struct file *, void *, filldir_t);
-static int (*proc_openprom_deflookup_ptr)(struct inode *, struct qstr *, struct inode **);
+static int (*proc_openprom_deflookup_ptr)(struct inode *, struct dentry *);
 void (*proc_openprom_use)(struct inode *, int) = 0;
 static struct openpromfs_dev *proc_openprom_devices = NULL;
 static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST;
 
 struct inode_operations *
 proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
-                      int (*lookup)(struct inode *, struct qstr *, struct inode **),
+                      int (*lookup)(struct inode *, struct dentry *),
                       void (*use)(struct inode *, int),
                       struct openpromfs_dev ***devices)
 {
@@ -220,13 +220,13 @@ proc_openprom_defreaddir(struct inode * inode, struct file * filp,
 }
 
 static int 
-proc_openprom_deflookup(struct inode * dir, struct qstr *str, struct inode ** result)
+proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
 {
        request_module("openpromfs");
        if (proc_openprom_inode_operations.lookup !=
            proc_openprom_deflookup)
                return proc_openprom_inode_operations.lookup 
-                               (dir, str, result);
+                               (dir, dentry);
        return -ENOENT;
 }
 #endif
index d9a334f8519bf96ed16bca24a73e25ce36838045..934f80094327ae85afcb5947970b9e92a6f1381c 100644 (file)
  *                                     Changed for 2.1.19 modules
  *     Jan 1997                        Initial release
  *     Jun 1997                        2.1.43+ changes
- *     Jul 1997                        proper page locking in readpage
+ *                                     Proper page locking in readpage
  *                                     Changed to work with 2.1.45+ fs
- *                                     Fixed follow_link
+ *     Jul 1997                        Fixed follow_link
+ *                     2.1.47
+ *                                     lookup shouldn't return -ENOENT
+ *                                     from Horst von Brand:
+ *                                       fail on wrong checksum
+ *                                       double unlock_super was possible
+ *                                       correct namelen for statfs
+ *                                     spotted by Bill Hawes:
+ *                                       readlink shouldn't iput()
  */
 
 /* todo:
  *     - see Documentation/filesystems/romfs.txt
  *     - use malloced memory for file names?
+ *     - quicklist routines from fs/namei.c, get_page is possibly not
+ *       intended to be used now
  *     - considering write access...
  *     - network (tftp) files?
  *     - in the ancient times something leaked to made umounts
@@ -106,6 +116,7 @@ romfs_read_super(struct super_block *s, void *data, int silent)
        if (romfs_checksum(rsb, min(sz,512))) {
                printk ("romfs: bad initial checksum on dev "
                        "%s.\n", kdevname(dev));
+               goto out;
        }
 
        s->s_magic = ROMFS_MAGIC;
@@ -123,11 +134,11 @@ romfs_read_super(struct super_block *s, void *data, int silent)
        s->s_op = &romfs_ops;
        s->s_root = d_alloc_root(iget(s, sz), NULL);
 
-       unlock_super(s);
-
        if (!s->s_root)
                goto outnobh;
 
+       unlock_super(s);
+
        /* Ehrhm; sorry.. :)  And thanks to Hans-Joachim Widmaier  :) */
        if (0) {
 out:
@@ -165,7 +176,7 @@ romfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
        tmp.f_type = ROMFS_MAGIC;
        tmp.f_bsize = ROMBSIZE;
        tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
-       /* XXX tmp.f_namelen = relevant? */
+       tmp.f_namelen = ROMFS_MAXFN;
        return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
 }
 
@@ -314,16 +325,14 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
        const char *name;               /* got from dentry */
        int len;
 
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               res = -EBADF;
+       res = -EBADF;
+       if (!dir || !S_ISDIR(dir->i_mode))
                goto out;
-       }
 
+       res = 0;                        /* instead of ENOENT */
        offset = dir->i_ino & ROMFH_MASK;
-       if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
-               res = -ENOENT;
+       if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
                goto out;
-       }
 
        maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
        offset = ntohl(ri.spec) & ROMFH_MASK;
@@ -336,10 +345,8 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
 
        for(;;) {
                if (!offset || offset >= maxoff
-                   || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
-                       res = -ENOENT;
+                   || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
                        goto out;
-               }
 
                /* try to match the first 16 bytes of name */
                fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
@@ -367,9 +374,9 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
        if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
                offset = ntohl(ri.spec) & ROMFH_MASK;
 
-       res = -EACCES;
-       if ((inode = iget(dir->i_sb, offset))!=NULL) {
-               res = 0;
+       if ((inode = iget(dir->i_sb, offset))==NULL) {
+               res = -EACCES;
+       } else {
                d_add(dentry, inode);
        }
 
@@ -439,7 +446,6 @@ romfs_readlink(struct inode *inode, char *buffer, int len)
        copy_to_user(buffer, buf, mylen);
 
 out:
-       iput(inode);
        return mylen;
 }
 
@@ -597,6 +603,8 @@ romfs_read_inode(struct inode *i)
                        printk("romfs: read error for inode 0x%x\n", ino);
                        return;
                }
+               /* XXX: do romfs_checksum here too (with name) */
+
                nextfh = ntohl(ri.next);
                if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
                        break;
index a7a2d434e908e0448316fec3c9f84ee036e107b9..72844bb62c078763f79d6a7009b15cf212cbd428 100644 (file)
@@ -618,6 +618,9 @@ static int do_umount(kdev_t dev,int unmount_root)
        d_umount(sb->s_root);
        sb->s_root = NULL;
 
+       /* Forget any inodes */
+       invalidate_inodes(dev);
+
        if (sb->s_op) {
                if (sb->s_op->write_super && sb->s_dirt)
                        sb->s_op->write_super(sb);
index 8996c6ca0e4b4d931a1aeb150ba3edf852a3d5b9..ec9ec31196f577cd428cc781961ec5f389125f89 100644 (file)
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_namei.c,v 1.8 1997/07/17 02:24:14 davem Exp $
+ * $Id: ufs_namei.c,v 1.9 1997/07/22 06:40:12 davem Exp $
  *
  */
 
@@ -131,8 +131,11 @@ int ufs_lookup (struct inode * dir, struct qstr *qname,
                                break;
                        }
                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
-                               printk("lfragno 0x%lx  direct d 0x%x  d_ino %u  d_reclen %u  d_namlen %u  d_name `%s'\n",
-                                      lfragno, (unsigned int)d, ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen), ufs_swab16(d->d_namlen), d->d_name);
+                               printk("lfragno 0x%lx  direct d 0x%x  d_ino %u  "
+                                      "d_reclen %u  d_namlen %u  d_name `%s'\n",
+                                      lfragno, (unsigned int)((unsigned long)d),
+                                      ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen),
+                                      ufs_swab16(d->d_namlen), d->d_name);
                        }
                        if ((ufs_swab16(d->d_namlen) == len) &&
                            /* XXX - don't use strncmp() - see ext2fs */
index d25e2f5b41441e99e13692046714ae8ef17aece4..34390e362a24389465942f9c282a2574ba31dc03 100644 (file)
@@ -24,6 +24,7 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode         pckbd_setkeycode
 #define kbd_getkeycode         pckbd_getkeycode
@@ -32,9 +33,12 @@ extern void pckbd_init_hw(void);
 #define kbd_unexpected_up      pckbd_unexpected_up
 #define kbd_leds               pckbd_leds
 #define kbd_init_hw            pckbd_init_hw
+#define kbd_sysrq_xlate                pckbd_sysrq_xlate
 
 #define INIT_KBD
 
+#define SYSRQ_KEY 0x54
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMalpha_KEYBOARD_H */
index a703176545a57a6973d16f22b0c084d70970b36a..103bc0417b15e7f77ed31590bdcdbaed79d82fd6 100644 (file)
@@ -24,6 +24,7 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode         pckbd_setkeycode
 #define kbd_getkeycode         pckbd_getkeycode
@@ -32,6 +33,9 @@ extern void pckbd_init_hw(void);
 #define kbd_unexpected_up      pckbd_unexpected_up
 #define kbd_leds               pckbd_leds
 #define kbd_init_hw            pckbd_init_hw
+#define kbd_sysrq_xlate                pckbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
 
 #endif /* __KERNEL__ */
 
index 4f78f97fb69a3b5e51db47da56992c51f462d8c8..fc7eb94dee598009ec1ec4dbd5ff3f66e09cf574 100644 (file)
@@ -39,6 +39,8 @@ do { if (depth) __asm__ __volatile__( \
 } while (0)
        
 
+extern const char lk_lockmsg[]; 
+
 /* Locking the kernel */
 extern __inline__ void lock_kernel(void)
 {
@@ -46,7 +48,7 @@ extern __inline__ void lock_kernel(void)
 
        if (local_irq_count[cpu]) {
                __label__ l1;
-l1:            printk("lock from interrupt context at %p\n", &&l1);
+l1:            printk(lk_lockmsg, &&l1);
        }
        if (cpu == global_irq_holder) {
                __label__ l2;
index 7c873c34176b22b6fd182d33fd038ba4dd51b7b2..607b408ec790b9f093c8f70f03cc1e149ca22f0f 100644 (file)
@@ -31,7 +31,7 @@
 #define        SER_AMIGA       105     /* Amiga built-in serial port */
 #define SER_IOEXT      106     /* Amiga GVP IO-Extender (16c552) */
 #define SER_MFC_III    107     /* Amiga BSC Multiface Card III (MC68681) */
-
+#define SER_WHIPPET    108     /* Amiga Hisoft Whippet PCMCIA (16c550B) */
 
 struct serial_struct {
        int     type;
index d7356d91a8500e4ba5ba7ec19f7e6716b27927e2..ac241fef040ea36f412121d3d1b2bab6f98ae768 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: byteorder.h,v 1.5 1997/06/25 19:10:18 ralf Exp $
+ * $Id: byteorder.h,v 1.6 1997/07/20 15:15:01 ralf Exp $
  */
 #ifndef __ASM_MIPS_BYTEORDER_H
 #define __ASM_MIPS_BYTEORDER_H
@@ -24,7 +24,7 @@
 #if defined (__MIPSEB__)
 
 #ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
 #endif
 
 #ifndef __BIG_ENDIAN_BITFIELD
 #define __constant_htonl(x) (x)
 #define __constant_htons(x) (x)
 
+#elif defined (__MIPSEL__)
+
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#define __LITTLE_ENDIAN_BITFIELD
+#endif
+
+#define __constant_ntohl(x) __swap32(x)
+#define __constant_ntohs(x) __swap16(x)
+#define __constant_htonl(x) __swap32(x)
+#define __constant_htons(x) __swap16(x)
+
+#endif /* defined(__MIPSEL_) */
+
 #ifdef __KERNEL__
 
+#if defined (__MIPSEB__)
+
 /*
  * In-kernel byte order macros to handle stuff like
  * byte-order-dependent filesystems etc.
 #define cpu_to_be16(x) (x)
 #define be16_to_cpu(x) (x)
 
-#endif /* __KERNEL__ */
-
 #elif defined (__MIPSEL__)
 
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN
-#endif
-
-#ifndef __LITTLE_ENDIAN_BITFIELD
-#define __LITTLE_ENDIAN_BITFIELD
-#endif
-
-#define __constant_ntohl(x) __swap32(x)
-#define __constant_ntohs(x) __swap16(x)
-#define __constant_htonl(x) __swap32(x)
-#define __constant_htons(x) __swap16(x)
-
-#ifdef __KERNEL__
-
 /*
  * In-kernel byte order macros to handle stuff like
  * byte-order-dependent filesystems etc.
@@ -85,8 +87,6 @@
 #define cpu_to_be16(x) __swap16((x))
 #define be16_to_cpu(x) __swap16((x))
 
-#endif /* __KERNEL__ */
-
 #else
 #error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
 #endif
@@ -144,7 +144,8 @@ extern __inline__ void cpu_to_be32s(__u32 *addr)
 #define be16_to_cpus(x) cpu_to_be16s(x)
 #define be32_to_cpus(x) cpu_to_be32s(x)
 
-#ifdef __KERNEL__
+#endif /* __KERNEL__ */
+
 extern unsigned long int ntohl(unsigned long int __x);
 extern unsigned short int ntohs(unsigned short int __x);
 extern unsigned short int htons(unsigned short int __x);
@@ -170,6 +171,5 @@ extern __inline__ unsigned short int htons(unsigned short int __x)
 {
        return __constant_htons(__x);
 }
-#endif /* __KERNEL__ */
 
 #endif /* __ASM_MIPS_BYTEORDER_H */
index 54512f8d8f85010784defcd3671c284a887427ab..cbecf6ef024a74d2242c3d62bf980efe1c2dc677 100644 (file)
@@ -96,6 +96,8 @@
 
 #define TCSBRKP                0x5486  /* Needed for POSIX tcsendbreak() */
 #define TIOCTTYGSTRUCT 0x5487  /* For debugging only */
+#define TIOCSBRK       0x5427  /* BSD compatibility */
+#define TIOCCBRK       0x5428  /* BSD compatibility */
 
 #define TIOCSERCONFIG  0x5488
 #define TIOCSERGWILD   0x5489
index 41ab8963485a3ce78111da01f8c2c4970e11b0c2..a7e5133a8d9740a883b3d0ab5ea1dea42ece7117 100644 (file)
@@ -210,7 +210,7 @@ typedef struct {
 #define JAZZ_SERIAL2_IRQ        4
 #define JAZZ_PARALLEL_IRQ       5
 #define JAZZ_FLOPPY_IRQ         6 /* needs to be consistent with floppy driver! */
-
+#define JAZZ_SCSI_INTERRUPT     12
 
 /*
  * JAZZ DMA Channels
index c7f1730cf4f588d06d444d253f274efe6cbf4268..6519a1cefe445603d5d489f2ed3d27078722b3e2 100644 (file)
@@ -28,7 +28,7 @@ int vdma_get_residue(int channel);
 #define VDMA_PAGESIZE          4096
 #define VDMA_PGTBL_ENTRIES     4096
 #define VDMA_PGTBL_SIZE                (sizeof(VDMA_PGTBL_ENTRY) * VDMA_PGTBL_ENTRIES)
-#define VDMA_PAGE_EMPTY                0
+#define VDMA_PAGE_EMPTY                0xff000000
 
 /*
  * Macros to get page no. and offset of a given address
index 5d080f822676074e1251cee1df2bbd9867ac29b5..ee549ea42459299306500566909e2999471c46bb 100644 (file)
@@ -494,6 +494,9 @@ extern void (*update_mmu_cache)(struct vm_area_struct *vma,
 #define SWP_OFFSET(entry) ((entry) >> 15)
 #define SWP_ENTRY(type,offset) (((type) << 8) | ((offset) << 15))
 
+#define module_map      vmalloc
+#define module_unmap    vfree
+
 /* TLB operations. */
 extern inline void tlb_probe(void)
 {
index daf477459101558fd0c2539ec231ab799c98fead..2c752a0c09264ccba46e9c563d8b773a2fe1033a 100644 (file)
@@ -108,13 +108,13 @@ __restore_flags(int flags)
 #define save_and_cli(x) __save_and_cli(x)
 #define restore_flags(x) __restore_flags(x)
 
-#define sync_mem()                       \
-__asm__ __volatile__(                    \
-       ".set\tnoreorder\n\t"            \
-       "sync\n\t"                       \
-       ".set\treorder"                  \
-        : /* no output */                \
-       : /* no input */                 \
+#define mb()                                           \
+__asm__ __volatile__(                                  \
+       "# prevent instructions being moved around\n\t" \
+       ".set\tnoreorder\n\t"                           \
+       ".set\treorder"                                 \
+        : /* no output */                              \
+       : /* no input */                                \
        : "memory")
 
 #if !defined (__LANGUAGE_ASSEMBLY__)
index 4cf30a110eb6e1f042ee76f8e555733ae96d42fa..4517106ca25c9dabc72d0d88af8ed682467dc32f 100644 (file)
 #define __NR_query_module              (__NR_Linux + 187)
 #define __NR_poll                      (__NR_Linux + 188)
 #define __NR_nfsservctl                        (__NR_Linux + 189)
+#define __NR_setresgid                 (__NR_Linux + 190)
+#define __NR_getresgid                 (__NR_Linux + 191)
 
 /*
  * Offset of the last Linux flavoured syscall
  */
-#define __NR_Linux_syscalls            189
+#define __NR_Linux_syscalls            191
 
 #ifndef __LANGUAGE_ASSEMBLY__
 
index c34bc36ef99a0ce7885488cdef7b3b007f44ad44..6070ea73863e7fbc00ee1d8d163bc9a676a2165e 100644 (file)
 #ifndef _ASM_PPC_ATOMIC_H_ 
 #define _ASM_PPC_ATOMIC_H_
 
+#ifdef __SMP__
+typedef struct { volatile int counter; } atomic_t;
+#else
 typedef struct { int counter; } atomic_t;
-#define ATOMIC_INIT(i) { (i) }
+#endif
 
-/*
- * Make sure gcc doesn't try to be clever and move things around
- * on us. We need to use _exactly_ the address the user gave us,
- * not some alias that contains the same information.
- */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+#define ATOMIC_INIT(i) { (i) }
 
 #define atomic_read(v)         ((v)->counter)
-#define atomic_set(v)          (((v)->counter) = i)
+#define atomic_set(v,i)                (((v)->counter) = (i))
 
-#define atomic_dec_return(v) ({atomic_sub(1,(v));(v);})
-#define atomic_inc_return(v) ({atomic_add(1,(v));(v);})
+extern void atomic_add(int a, atomic_t *v);
+extern void atomic_sub(int a, atomic_t *v);
+extern void atomic_inc(atomic_t *v);
+extern int  atomic_inc_return(atomic_t *v);
+extern void atomic_dec(atomic_t *v);
+extern int  atomic_dec_return(atomic_t *v);
+extern int  atomic_dec_and_test(atomic_t *v);
 
-#define atomic_inc(v) atomic_add(1,(v))
-#define atomic_dec(v) atomic_sub(1,(v))
-#endif
+extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
+extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
+
+#if 0  /* for now */
+extern __inline__ void atomic_add(atomic_t a, atomic_t *v)
+{
+       atomic_t t;
+
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%3\n\
+       add     %0,%2,%0\n\
+       stwcx.  %0,0,%3\n\
+       bne     1b"
+       : "=&r" (t), "=m" (*v)
+       : "r" (a), "r" (v)
+       : "cc");
+}
+
+extern __inline__ void atomic_sub(atomic_t a, atomic_t *v)
+{
+       atomic_t t;
+
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%3\n\
+       subf    %0,%2,%0\n\
+       stwcx.  %0,0,%3\n\
+       bne     1b"
+       : "=&r" (t), "=m" (*v)
+       : "r" (a), "r" (v)
+       : "cc");
+}
+
+extern __inline__ int atomic_sub_and_test(atomic_t a, atomic_t *v)
+{
+       atomic_t t;
+
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%3\n\
+       subf    %0,%2,%0\n\
+       stwcx.  %0,0,%3\n\
+       bne     1b"
+       : "=&r" (t), "=m" (*v)
+       : "r" (a), "r" (v)
+       : "cc");
+
+       return t == 0;
+}
+
+extern __inline__ void atomic_inc(atomic_t *v)
+{
+       atomic_t t;
+
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%2\n\
+       addic   %0,%0,1\n\
+       stwcx.  %0,0,%2\n\
+       bne     1b"
+       : "=&r" (t), "=m" (*v)
+       : "r" (v)
+       : "cc");
+}
+
+extern __inline__ void atomic_dec(atomic_t *v)
+{
+       atomic_t t;
+
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%2\n\
+       addic   %0,%0,-1\n\
+       stwcx.  %0,0,%2\n\
+       bne     1b"
+       : "=&r" (t), "=m" (*v)
+       : "r" (v)
+       : "cc");
+}
+
+extern __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+       atomic_t t;
+
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%2\n\
+       addic   %0,%0,-1\n\
+       stwcx.  %0,0,%2\n\
+       bne     1b"
+       : "=&r" (t), "=m" (*v)
+       : "r" (v)
+       : "cc");
+
+       return t == 0;
+}
+#endif /* 0 */
 
+#endif /* _ASM_PPC_ATOMIC_H_ */
index 959f2b3027a0b9579ba336f76432fe63ba26bd2f..3b8a24575d9e12bdd049ff82a69346eb3cce657e 100644 (file)
 
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <linux/kernel.h> /* for printk */
 
 #define BIT(n) 1<<(n&0x1F)
 typedef unsigned long BITFIELD;
 
 
-/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
- * is in the highest of the four bytes and bit '31' is the high bit
- * within the first byte. powerpc is BIG-Endian. Unless noted otherwise
- * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
+/*
+ * These are ifdef'd out here because using : "cc" as a constraing
+ * results in errors from gcc. -- Cort
  */
-extern __inline__ int set_bit(int nr, void * add)
+#if 0
+extern __inline__ int set_bit(int nr, void * addr)
 {
-  BITFIELD *addr = add;
-       long    mask,oldbit;       
-#ifdef __KERNEL__
-       int s = _disable_interrupts();
-#endif
-       addr += nr >> 5;
-       mask = BIT(nr);
-       oldbit = (mask & *addr) != 0;
-       *addr |= mask;
-#ifdef __KERNEL__      
-       _enable_interrupts(s);
-#endif
-       return oldbit;
+       unsigned long old, t;
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+       
+       if ((unsigned long)addr & 3)
+               printk("set_bit(%lx, %p)\n", nr, addr);
+
+       __asm__ __volatile__(
+               "1:lwarx %0,0,%3 \n\t"
+               "or     %1,%0,%2 \n\t"
+               "stwcx. %1,0,%3 \n\t"
+               "bne    1b \n\t"
+               : "=&r" (old), "=&r" (t)        /*, "=m" (*p)*/
+               : "r" (mask), "r" (p)
+               /*: "cc" */);
+
+n      return (old & mask) != 0;
 }
 
-extern __inline__ int change_bit(int nr, void *add)
+extern __inline__  unsigned long clear_bit(unsigned long nr, void *addr)
 {
-       BITFIELD *addr = add;
-       int     mask, retval;
-#ifdef __KERNEL__
-       int s = _disable_interrupts();
-#endif
-       addr += nr >> 5;
-       mask = BIT(nr);
-       retval = (mask & *addr) != 0;
-       *addr ^= mask;
-#ifdef __KERNEL__
-       _enable_interrupts(s);
-#endif
-       return retval;
+       unsigned long old, t;
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+       if ((unsigned long)addr & 3)
+               printk("clear_bit(%lx, %p)\n", nr, addr);
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%3
+       andc    %1,%0,%2
+       stwcx.  %1,0,%3
+       bne     1b"
+       : "=&r" (old), "=&r" (t)        /*, "=m" (*p)*/
+       : "r" (mask), "r" (p)
+      /*: "cc"*/);
+
+       return (old & mask) != 0;
 }
 
-extern __inline__ int clear_bit(int nr, void *add)
+extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
 {
-        BITFIELD *addr = add;
-       int     mask, retval;
-#ifdef __KERNEL__
-       int s = _disable_interrupts();
-#endif
-       addr += nr >> 5;
-       mask = BIT(nr);
-       retval = (mask & *addr) != 0;
-       *addr &= ~mask;
-#ifdef __KERNEL__      
-       _enable_interrupts(s);
+       unsigned long old, t;
+       unsigned long mask = 1 << (nr & 0x1f);
+       unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+       if ((unsigned long)addr & 3)
+               printk("change_bit(%lx, %p)\n", nr, addr);
+       __asm__ __volatile__("\n\
+1:     lwarx   %0,0,%3
+       xor     %1,%0,%2
+       stwcx.  %1,0,%3
+       bne     1b"
+       : "=&r" (old), "=&r" (t)        /*, "=m" (*p)*/
+       : "r" (mask), "r" (p)
+      /*: "cc"*/);
+
+       return (old & mask) != 0;
+}
 #endif
-       return retval;
+
+extern __inline__ int ffz(unsigned int x)
+{
+       int n;
+
+       x = ~x & (x+1);         /* set LS zero to 1, other bits to 0 */
+       __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+       return 31 - n;
 }
 
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+extern __inline__ unsigned long find_first_zero_bit(void * addr, unsigned long size)
+{
+       unsigned int * p = ((unsigned int *) addr);
+       unsigned int result = 0;
+       unsigned int tmp;
+
+       if (size == 0)
+               return 0;
+       while (size & ~31UL) {
+               if (~(tmp = *(p++)))
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
+       tmp |= ~0UL << size;
+found_middle:
+       return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size,
+                                unsigned long offset)
+{
+       unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+       unsigned int result = offset & ~31UL;
+       unsigned int tmp;
+
+       if (offset >= size)
+               return size;
+       size -= result;
+       offset &= 31UL;
+       if (offset) {
+               tmp = *(p++);
+               tmp |= ~0UL >> (32-offset);
+               if (size < 32)
+                       goto found_first;
+               if (~tmp)
+                       goto found_middle;
+               size -= 32;
+               result += 32;
+       }
+       while (size & ~31UL) {
+               if (~(tmp = *(p++)))
+                       goto found_middle;
+               result += 32;
+               size -= 32;
+       }
+       if (!size)
+               return result;
+       tmp = *p;
+found_first:
+       tmp |= ~0UL << size;
+found_middle:
+       return result + ffz(tmp);
+}
+
+
 #define _EXT2_HAVE_ASM_BITOPS_
 #define ext2_find_first_zero_bit(addr, size) \
         ext2_find_next_zero_bit((addr), (size), 0)
index 202f9ab06c5f970a9fc82de4bd68e7fa84a01694..8dce1e290fd0a5e1561cc9df1c3b6699311b7668 100644 (file)
@@ -2,7 +2,5 @@
  * This file is included by 'init/main.c'
  */
 
-void
-check_bugs(void)
-{
-} 
+extern void
+check_bugs(void);
index bbb257941b612b904caf859842d1937a0eef98cb..eab03c752650538d553a0b52698095718113606f 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _PPC_BYTEORDER_H
 #define _PPC_BYTEORDER_H
 
+#include <asm/types.h>
+
 #ifndef __BIG_ENDIAN
 #define __BIG_ENDIAN
 #endif
 
 #define __htonl(x) ntohl(x)
 #define __htons(x) ntohs(x)
+
+#define __constant_ntohs(x) ntohs(x)
+#define __constant_ntohl(x) ntohl(x)
 #define __constant_htonl(x) ntohl(x)
 #define __constant_htons(x) ntohs(x)
 
 #ifdef __KERNEL__
+/*
+ * 16 and 32 bit little-endian loads and stores.
+ */
+extern inline unsigned ld_le16(volatile unsigned short *addr)
+{
+       unsigned val;
 
-/* Convert from CPU byte order, to specified byte order. */
-extern __inline__ __u16 cpu_to_le16(__u16 value)
+       asm volatile("lhbrx %0,0,%1" : "=r" (val) : "r" (addr));
+       return val;
+}
+
+extern inline void st_le16(volatile unsigned short *addr, unsigned val)
+{
+       asm volatile("sthbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+extern inline unsigned ld_le32(volatile unsigned *addr)
+{
+       unsigned val;
+
+       asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr));
+       return val;
+}
+
+extern inline void st_le32(volatile unsigned *addr, unsigned val)
 {
-       return (value >> 8) | (value << 8);
+       asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
 }
 
+
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+       return ld_le16(&value);
+}
 extern __inline__ __u32 cpu_to_le32(__u32 value)
 {
-       return((value>>24) | ((value>>8)&0xff00) |
-              ((value<<8)&0xff0000) | (value<<24));
+       return ld_le32(&value);
 }
 #define cpu_to_be16(x)  (x)
 #define cpu_to_be32(x)  (x)
@@ -38,33 +69,33 @@ extern __inline__ __u32 cpu_to_le32(__u32 value)
 /* The same, but returns converted value from the location pointer by addr. */
 extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
 {
-       return cpu_to_le16(*addr);
+       return ld_le16(addr);
 }
 
 extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
 {
-       return cpu_to_le32(*addr);
+       return ld_le32(addr);
 }
 
 extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
 {
-       return cpu_to_be16(*addr);
+       return *addr;
 }
 
 extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
 {
-       return cpu_to_be32(*addr);
+       return *addr;
 }
 
 /* The same, but do the conversion in situ, ie. put the value back to addr. */
 extern __inline__ void cpu_to_le16s(__u16 *addr)
 {
-       *addr = cpu_to_le16(*addr);
+       st_le16(addr,*addr);
 }
 
 extern __inline__ void cpu_to_le32s(__u32 *addr)
 {
-       *addr = cpu_to_le32(*addr);
+       st_le32(addr,*addr);
 }
 
 #define cpu_to_be16s(x) do { } while (0)
@@ -86,5 +117,12 @@ extern __inline__ void cpu_to_le32s(__u32 *addr)
 #define be16_to_cpus(x) cpu_to_be16s(x)
 #define be32_to_cpus(x) cpu_to_be32s(x)
 
+
 #endif /* __KERNEL__ */
 #endif /* !(_PPC_BYTEORDER_H) */
+
+
+
+
+
+
index da609f27153c517a4d0da55dc49485d087690796..8bdffcdfb5f5ccc3d7a33807753bfa8f82efb6d3 100644 (file)
@@ -5,7 +5,8 @@
 #define __ARCH_PPC_CACHE_H
 
 /* bytes per L1 cache line */
-#define        L1_CACHE_BYTES  32      /* a guess */
+/* a guess */ /* a correct one -- Cort */
+#define        L1_CACHE_BYTES  32      
 
 #define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 
index 74e943792af0b57a3b8a6d7e2be1715ff1c16eb5..7b55f0032a443f7e0ec001e7ded2386bde9ef757 100644 (file)
@@ -47,6 +47,20 @@ unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
  */
 #define csum_partial_copy_fromuser csum_partial_copy
 
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ *
+ * right now - it just calls csum_partial_copy()
+ *   -- Cort
+ */
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+                                               int len, int sum, int *err_ptr)
+{
+       int *dst_err_ptr=NULL;
+       return csum_partial_copy( src, dst, len, sum);
+}
 
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
index d815aaad3c64e33d8f46029c7c8f4d2e5c917a93..d7a0a9215ee8ba6350d0ab7a2fd83dc215d80065 100644 (file)
@@ -1,12 +1,10 @@
 #ifndef _PPC_CURRENT_H
 #define _PPC_CURRENT_H
 
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel.  For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
- */
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()])      /* Current on this processor */
+#include <linux/config.h>
+
+extern struct task_struct *current_set[1];
+
+register struct task_struct *current asm("r2");
 
 #endif /* !(_PPC_CURRENT_H) */
index 68f1a4da71d75bb629b5bcab0a8d569b979fc7f8..9da227167143b4b979cf1125181f90a82f58d137 100644 (file)
@@ -1,14 +1,31 @@
 #ifndef _PPC_DELAY_H
 #define _PPC_DELAY_H
 
+/*
+ * Copyright 1996, Paul Mackerras.
+ *
+ * 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.
+ */
 
-extern __inline__ void __delay(unsigned long );
-extern __inline__ void __udelay(unsigned long );
-
+extern __inline__ void __delay(unsigned int loops)
+{
+       if (loops != 0)
+               __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
+                                    "r" (loops) : "ctr");
+}
 
-extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
+extern __inline__ void udelay(unsigned long usecs)
 {
-       return (a*b)/c;
+       unsigned long loops;
+
+       /* compute (usecs * 2^32 / 10^6) * loops_per_sec / 2^32 */
+       usecs *= 0x10c6;                /* 2^32 / 10^6 */
+       __asm__("mulhwu %0,%1,%2" : "=r" (loops) :
+               "r" (usecs), "r" (loops_per_sec));
+       __delay(loops);
 }
 
 #endif /* defined(_PPC_DELAY_H) */
index ca609062e22a9bc16b11447fe69e9b0f61af84e5..7becf0190253cc004073f9e67e52cfa249bc2081 100644 (file)
@@ -1,16 +1,21 @@
-/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
+/* $Id: dma.h,v 1.3 1997/03/16 06:20:39 cort Exp $
  * linux/include/asm/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
  * and John Boyd, Nov. 1992.
  */
 
+#include <linux/config.h>
+
 /*
  * Note: Adapted for PowerPC by Gary Thomas
  * Modified by Cort Dougan <cort@cs.nmt.edu>
  *
+ * None of this really applies for Power Macintoshes.  There is
+ * basically just enough here to get kernel/dma.c to compile.
+ *
  * There may be some comments or restrictions made here which are
- * not valid for the PowerPC (PreP) platform.  Take what you read
+ * not valid for the PReP platform.  Take what you read
  * with a grain of salt.
  */
  
@@ -18,6 +23,7 @@
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
 
+#ifdef CONFIG_PREP
 #include <asm/io.h>            /* need byte IO */
 
 
@@ -295,5 +301,6 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
 /* These are in kernel/dma.c: */
 extern void free_dma(unsigned int dmanr);      /* release it again */
 
+#endif /* CONFIG_PREP */
 
 #endif /* _ASM_DMA_H */
index 8c47b73e7781136ff4b80e6c289c9e8ed064e877..ff364b820aead1bb0dcb28f8ce4ac69025449a0d 100644 (file)
 #define ERESTARTNOHAND 514     /* restart if no handler.. */
 #define ENOIOCTLCMD    515     /* No ioctl command */
 
+#define _LAST_ERRNO    515
+
 #endif
diff --git a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h
new file mode 100644 (file)
index 0000000..631e597
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+extern unsigned int local_irq_count[NR_CPUS];
+#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
+
+#ifndef __SMP__
+
+#define hardirq_trylock(cpu)   (local_irq_count[cpu] == 0)
+#define hardirq_endlock(cpu)   do { } while (0)
+
+#define hardirq_enter(cpu)     (local_irq_count[cpu]++)
+#define hardirq_exit(cpu)      (local_irq_count[cpu]--)
+
+#define synchronize_irq()      do { } while (0)
+
+#else
+
+#error Somebody should do SMP support for PPC...
+
+#endif /* __SMP__ */
+
+#endif /* __ASM_HARDIRQ_H */
index 69838b8b1244e6350d60c9d57e8df1a969931f0b..bc16288a8a50937637550246485ffd213fd0acb4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/include/asm-i386/ide.h
+ *  linux/include/asm-ppc/ide.h
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors
  */
@@ -13,7 +13,7 @@
 
 #ifdef __KERNEL__
 
-typedef unsigned short ide_ioreg_t;
+#include <linux/config.h>
 
 #ifndef MAX_HWIFS
 #define MAX_HWIFS      4
@@ -21,11 +21,15 @@ typedef unsigned short ide_ioreg_t;
 
 #define ide_sti()      sti()
 
+#ifdef CONFIG_PREP
+
+typedef unsigned short ide_ioreg_t;
+
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
        switch (base) {
-               case 0x1f0: return 14;
-               case 0x170: return 15;
+               case 0x1f0: return 13;
+               case 0x170: return 13;
                case 0x1e8: return 11;
                case 0x168: return 10;
                default:
@@ -66,18 +70,7 @@ typedef union {
                unsigned lba            : 1;    /* using LBA instead of CHS */
                unsigned bit7           : 1;    /* always 1 */
        } b;
-       } select_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-                       unsigned long flags, const char *device, void *dev_id)
-{
-       return request_irq(irq, handler, flags, device, dev_id);
-}                      
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-       free_irq(irq, dev_id);
-}
+} select_t;
 
 static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
@@ -94,26 +87,92 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
        release_region(from, extent);
 }
 
-/*
- * The following are not needed for the non-m68k ports
- */
-static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
+#define ide_fix_driveid(id)            do {} while (0)
+
+#endif
+
+#ifdef CONFIG_PMAC
+
+#include <asm/io.h>            /* so we can redefine insw/outsw */
+
+typedef unsigned long ide_ioreg_t;
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+       return 0;
+}
+
+extern __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+       return index;
+}
+
+extern void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+
+typedef union {
+       unsigned all                    : 8;    /* all of the bits together */
+       struct {
+               unsigned bit7           : 1;    /* always 1 */
+               unsigned lba            : 1;    /* using LBA instead of CHS */
+               unsigned bit5           : 1;    /* always 1 */
+               unsigned unit           : 1;    /* drive select number, 0/1 */
+               unsigned head           : 4;    /* always zeros here */
+       } b;
+} select_t;
+
+#undef SUPPORT_SLOW_DATA_PORTS
+#define        SUPPORT_SLOW_DATA_PORTS 0
+#undef SUPPORT_VLB_SYNC
+#define SUPPORT_VLB_SYNC       0
+
+static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
-       return(1);
+       return 0;
 }
 
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
+static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
 }
 
-static __inline__ void ide_release_lock (int *ide_lock)
+static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
 }
 
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
+#undef insw
+#undef outsw
+#define insw(port, buf, ns)    ide_insw((port), (buf), (ns))
+#define outsw(port, buf, ns)   ide_outsw((port), (buf), (ns))
+
+void ide_insw(ide_ioreg_t port, void *buf, int ns);
+void ide_outsw(ide_ioreg_t port, void *buf, int ns);
+
+#define ide_fix_driveid(id)    do {                    \
+       int nh;                                         \
+       unsigned short *p = (unsigned short *) id;      \
+       for (nh = SECTOR_WORDS * 2; nh != 0; --nh, ++p) \
+               *p = (*p << 8) + (*p >> 8);             \
+} while (0)
+
+#endif
+
+static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                       unsigned long flags, const char *device, void *dev_id)
 {
+       return request_irq(irq, handler, flags, device, dev_id);
+}                      
+
+static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
+{
+       free_irq(irq, dev_id);
 }
 
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(base, irq)                (1)
+#define ide_release_lock(lock)         do {} while (0)
+#define ide_get_lock(lock, hdlr, data) do {} while (0)
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMPPC_IDE_H */
index 82ce44ce834cf4161f5a26c4d50819db1dd4c08e..09b38d899a882486f066e6a3be0c41f5dddf6dba 100644 (file)
@@ -1,14 +1,23 @@
 #ifndef _PPC_INIT_H
 #define _PPC_INIT_H
 
-/* Throwing the initialization code and data out is not supported yet... */
-
-#define        __init
+#define __init
 #define __initdata
-#define __initfunc(__arginit) __arginit
-/* For assembly routines */
+#define __initfunc(x) x
+/*
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+       __arginit __init; \
+       __arginit
+*/
+       /* For assembly routines */
 #define __INIT
 #define __FINIT
 #define __INITDATA
-
+/*     
+#define __INIT         .section        ".text.init",#alloc,#execinstr
+#define __FINIT        .previous
+#define __INITDATA     .section        ".data.init",#alloc,#write
+*/
 #endif
index 581d5164398dd1417ac6c8165c5e31aa9b49576a..e2dfcc49aacd4dd3288717e1f0cbb71db3ebae77 100644 (file)
@@ -1,8 +1,11 @@
 #ifndef _PPC_IO_H
 #define _PPC_IO_H
 
+#include <linux/config.h>
 #include <asm/page.h>
+#include <asm/byteorder.h>
 
+#ifdef CONFIG_PREP
 /* from the Carolina Technical Spec -- Cort */
 #define IBM_ACORN 0x82A
 #define SIO_CONFIG_RA  0x398
 #define IBM_L2_INVALIDATE 0x814
 #define IBM_SYS_CTL       0x81c
 
-
-
-/* Define the particulars of outb/outw/outl "instructions" */
 #define SLOW_DOWN_IO
 
 #ifndef PCI_DRAM_OFFSET
 #define PCI_DRAM_OFFSET  0x80000000
 #endif
 
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+void outsl(int port, long *ptr, int len);
+
+__inline__ unsigned char outb(unsigned char val, int port);
+__inline__ unsigned short outw(unsigned short val, int port);
+__inline__ unsigned long outl(unsigned long val, int port);
+__inline__ unsigned char inb(int port);
+__inline__ unsigned short inw(int port);
+__inline__ unsigned long inl(int port);
+
+#define inb_p inb
+#define inw_p inw
+#define inl_p inl
+#define outb_p outb
+#define outw_p outw
+#define outl_p outl
+
+#endif /* CONFIG_PREP */
+
+#ifdef CONFIG_PMAC
+/*
+ * Read and write the non-volatile RAM.
+ */
+extern int nvram_readb(int addr);
+extern void nvram_writeb(int addr, int val);
+
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET  0
+#endif
+
+#define inb(port)              in_8((unsigned char *)(port))
+#define outb(val, port)                out_8((unsigned char *)(port), (val))
+#define inw(port)              in_le16((unsigned short *)(port))
+#define outw(val, port)                out_le16((unsigned short *)(port), (val))
+#define inl(port)              in_le32((unsigned long *)(port))
+#define outl(val, port)                out_le32((unsigned long *)(port), (val))
+
+#define inb_p(port)            in_8((unsigned char *)(port))
+#define outb_p(val, port)      out_8((unsigned char *)(port), (val))
+#define inw_p(port)            in_le16((unsigned short *)(port))
+#define outw_p(val, port)      out_le16((unsigned short *)(port), (val))
+#define inl_p(port)            in_le32(((unsigned long *)port))
+#define outl_p(val, port)      out_le32((unsigned long *)(port), (val))
+
+#define insw(port, buf, ns)    _insw((unsigned short *)(port), (buf), (ns))
+#define outsw(port, buf, ns)   _outsw((unsigned short *)(port), (buf), (ns))
+#define insl(port, buf, nl)    _insl((unsigned long *)(port), (buf), (nl))
+#define outsl(port, buf, nl)   _outsl((unsigned long *)(port), (buf), (nl))
+#endif /* CONFIG_PMAC */
 
 /*
  * The PCI bus is inherently Little-Endian.  The PowerPC is being
@@ -42,19 +97,12 @@ extern inline void * bus_to_virt(unsigned long address)
         if (address == 0) return 0;
         return ((void *)(address - PCI_DRAM_OFFSET + KERNELBASE));
 }
-/* #define virt_to_bus(a) ((unsigned long)(((char *)a==(char *) 0) ? ((char *)0) \
-                       : ((char *)((long)a - KERNELBASE + PCI_DRAM_OFFSET))))
-#define bus_to_virt(a) ((void *) (((char *)a==(char *)0) ? ((char *)0) \
-                       : ((char *)((long)a - PCI_DRAM_OFFSET + KERNELBASE))))
-*/
-
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
 
+/*
+ * Map in an area of physical address space, for accessing
+ * I/O devices etc.
+ */
+extern void *ioremap(unsigned long address, unsigned long size);
 
 /*
  * Change virtual addresses to physical addresses and vv.
@@ -72,27 +120,101 @@ extern inline void * phys_to_virt(unsigned long address)
        return (void *) address;
 }
 
-/* from arch/ppc/kernel/port_io.c
- *               -- Cort
+#define _IO_BASE ((unsigned long)0x80000000)
+
+/*
+ * These are much more useful le/be io functions from Paul
+ * than leXX_to_cpu() style functions since the ppc has
+ * load/store byte reverse instructions
+ *  -- Cort
  */
-unsigned char inb(int port);
-unsigned short inw(int port);
-unsigned long inl(int port);
-unsigned char outb(unsigned char val,int port);
-unsigned short outw(unsigned short val,int port);
-unsigned long outl(unsigned long val,int port);
-void outsl(int port, long *ptr, int len);
 
-static inline unsigned char  inb_p(int port) {return (inb(port)); }
-static inline unsigned short inw_p(int port) {return (inw(port)); }
-static inline unsigned long  inl_p(int port) {return (inl(port)); }
+/*
+ * Enforce In-order Execution of I/O:
+ * Acts as a barrier to ensure all previous I/O accesses have
+ * completed before any further ones are issued.
+ */
+extern inline void eieio(void)
+{
+       asm volatile ("eieio" : :);
+}
+
+/*
+ * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ */
+extern inline int in_8(volatile unsigned char *addr)
+{
+       int ret;
+
+       ret = *addr;
+       eieio();
+       return ret;
+}
+
+extern inline void out_8(volatile unsigned char *addr, int val)
+{
+       *addr = val;
+       eieio();
+}
+
+extern inline int in_le16(volatile unsigned short *addr)
+{
+       int ret;
+
+       ret = ld_le16(addr);
+       eieio();
+       return ret;
+}
+
+extern inline int in_be16(volatile unsigned short *addr)
+{
+       int ret;
+
+       ret = *addr;
+       eieio();
+       return ret;
+}
 
+extern inline void out_le16(volatile unsigned short *addr, int val)
+{
+       st_le16(addr, val);
+       eieio();
+}
 
+extern inline void out_be16(volatile unsigned short *addr, int val)
+{
+       *addr = val;
+       eieio();
+}
 
-static inline unsigned char  outb_p(unsigned char val,int port) { return (outb(val,port)); }
-static inline unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
-static inline unsigned long  outl_p(unsigned long val,int port) { return (outl(val,port)); }
+extern inline unsigned in_le32(volatile unsigned *addr)
+{
+       unsigned ret;
 
+       ret = ld_le32(addr);
+       eieio();
+       return ret;
+}
 
+extern inline int in_be32(volatile unsigned *addr)
+{
+       int ret;
+
+       ret = *addr;
+       eieio();
+       return ret;
+}
+
+extern inline void out_le32(volatile unsigned *addr, int val)
+{
+       st_le32(addr, val);
+       eieio();
+}
+
+extern inline void out_be32(volatile unsigned *addr, int val)
+{
+       *addr = val;
+       eieio();
+}
 
 #endif
index f56e53db7db867c75a7f35fdc7405437f93ca963..2039f4954e6f4699be8e83f9e9dada4576e84d36 100644 (file)
@@ -83,8 +83,8 @@
 #define TIOCGETD       0x5424
 #define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
 #define TIOCTTYGSTRUCT 0x5426  /* For debugging only */
-#define TIOCSBRK       0x5427  /* BSD compatibility */
-#define TIOCCBRK       0x5428  /* BSD compatibility */
+#define TIOCSBRK       0x5427  /* BSD compatibility */
+#define TIOCCBRK       0x5428  /* BSD compatibility */
 
 #define TIOCSERCONFIG  0x5453
 #define TIOCSERGWILD   0x5454
index f457f82c3461df162066e946f9c2b52cac765d7f..ebffe2bcb6893faf5882ef6720dc2a1b2f78a687 100644 (file)
@@ -1,7 +1,13 @@
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
+#include <linux/config.h>
+
+#ifdef CONFIG_PMAC
 #define NR_IRQS        32
+#else
+#define NR_IRQS        16
+#endif
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
index f782da3a57a58497b7bcec6505a9e7e7cd33f0a7..41fa0c2ca4807a48b195e694ec072e50a5b03e17 100644 (file)
@@ -2,10 +2,12 @@
  *  linux/include/asm-ppc/keyboard.h
  *
  *  Created 3 Nov 1996 by Geert Uytterhoeven
+ *  Modified for Power Macintosh by Paul Mackerras
  */
 
 /*
- *  This file contains the ppc architecture specific keyboard definitions
+ * This file contains the ppc architecture specific keyboard definitions -
+ * like the intel pc for prep systems, different for power macs.
  */
 
 #ifndef __ASMPPC_KEYBOARD_H
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+
+#ifdef CONFIG_MAC_KEYBOARD
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+                          char raw_mode);
+extern int mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+
+#define kbd_setkeycode         mackbd_setkeycode
+#define kbd_getkeycode         mackbd_getkeycode
+#define kbd_pretranslate       mackbd_pretranslate
+#define kbd_translate          mackbd_translate
+#define kbd_unexpected_up      mackbd_unexpected_up
+#define kbd_leds               mackbd_leds
+#define kbd_init_hw            mackbd_init_hw
+
+#else /* CONFIG_MAC_KEYBOARD */
+
 #define KEYBOARD_IRQ                   1
 #define DISABLE_KBD_DURING_INTERRUPTS  0
 
@@ -34,6 +59,7 @@ extern void pckbd_init_hw(void);
 #define kbd_init_hw            pckbd_init_hw
 
 #define INIT_KBD
+#endif /* CONFIG_MAC_KEYBOARD */
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-ppc/mc146818rtc.h b/include/asm-ppc/mc146818rtc.h
deleted file mode 100644 (file)
index 78cf56e..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* mc146818rtc.h - register definitions for the Real-Time-Clock / CMOS RAM
- * Copyright Torsten Duwe <duwe@informatik.uni-erlangen.de> 1993
- * derived from Data Sheet, Copyright Motorola 1984 (!).
- * It was written to be part of the Linux operating system.
- */
-/* permission is hereby granted to copy, modify and redistribute this code
- * in terms of the GNU Library General Public License, Version 2 or later,
- * at your option.
- */
-
-#ifndef _MC146818RTC_H
-#define _MC146818RTC_H
-#include <asm/io.h>
-
-#ifndef MCRTC_PORT
-#define MCRTC_PORT(x)  (0x70 + (x))
-#define MCRTC_ALWAYS_BCD       1
-#endif
-
-#define CMOS_MCRTC_READ(addr) ({ \
-outb_p((addr),MCRTC_PORT(0)); \
-inb_p(MCRTC_PORT(1)); \
-})
-#define CMOS_MCRTC_WRITE(val, addr) ({ \
-outb_p((addr),MCRTC_PORT(0)); \
-outb_p((val),MCRTC_PORT(1)); \
-})
-
-/**********************************************************************
- * register summary
- **********************************************************************/
-#define MCRTC_SECONDS          0
-#define MCRTC_SECONDS_ALARM    1
-#define MCRTC_MINUTES          2
-#define MCRTC_MINUTES_ALARM    3
-#define MCRTC_HOURS            4
-#define MCRTC_HOURS_ALARM              5
-/* RTC_*_alarm is always true if 2 MSBs are set */
-# define MCRTC_ALARM_DONT_CARE         0xC0
-
-#define MCRTC_DAY_OF_WEEK              6
-#define MCRTC_DAY_OF_MONTH     7
-#define MCRTC_MONTH            8
-#define MCRTC_YEAR             9
-
-/* control registers - Moto names
- */
-#define MCRTC_REG_A            10
-#define MCRTC_REG_B            11
-#define MCRTC_REG_C            12
-#define MCRTC_REG_D            13
-
-/**********************************************************************
- * register details
- **********************************************************************/
-#define MCRTC_FREQ_SELECT      MCRTC_REG_A
-
-/* update-in-progress  - set to "1" 244 microsecs before RTC goes off the bus,
- * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
- * totalling to a max high interval of 2.228 ms.
- */
-# define MCRTC_UIP             0x80
-# define MCRTC_DIV_CTL         0x70
-   /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
-#  define MCRTC_REF_CLCK_4MHZ  0x00
-#  define MCRTC_REF_CLCK_1MHZ  0x10
-#  define MCRTC_REF_CLCK_32KHZ 0x20
-   /* 2 values for divider stage reset, others for "testing purposes only" */
-#  define MCRTC_DIV_RESET1     0x60
-#  define MCRTC_DIV_RESET2     0x70
-  /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
-# define MCRTC_RATE_SELECT     0x0F
-
-/**********************************************************************/
-#define MCRTC_CONTROL  MCRTC_REG_B
-# define MCRTC_SET 0x80                /* disable updates for clock setting */
-# define MCRTC_PIE 0x40                /* periodic interrupt enable */
-# define MCRTC_AIE 0x20                /* alarm interrupt enable */
-# define MCRTC_UIE 0x10                /* update-finished interrupt enable */
-# define MCRTC_SQWE 0x08               /* enable square-wave output */
-# define MCRTC_DM_BINARY 0x04  /* all time/date values are BCD if clear */
-# define MCRTC_24H 0x02                /* 24 hour mode - else hours bit 7 means pm */
-# define MCRTC_DST_EN 0x01     /* auto switch DST - works f. USA only */
-
-/**********************************************************************/
-#define MCRTC_INTR_FLAGS       MCRTC_REG_C
-/* caution - cleared by read */
-# define MCRTC_IRQF 0x80               /* any of the following 3 is active */
-# define MCRTC_PF 0x40
-# define MCRTC_AF 0x20
-# define MCRTC_UF 0x10
-
-/**********************************************************************/
-#define MCRTC_VALID    MCRTC_REG_D
-# define MCRTC_VRT 0x80                /* valid RAM and time */
-/**********************************************************************/
-
-/* example: !(CMOS_READ(MCRTC_CONTROL) & MCRTC_DM_BINARY) 
- * determines if the following two #defines are needed
- */
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
-#endif /* _MC146818RTC_H */
index 1b3217cfd07e2675d209f5a18671eebd0883acb3..c6c8352294f33cdb1ecb50d813d10a2301ba8737 100644 (file)
@@ -32,42 +32,68 @@ typedef struct _PTE
 
 /* Segment Register */
 typedef struct _SEGREG
-   {
-      unsigned long t:1;       /* Normal or I/O  type */
-      unsigned long ks:1;      /* Supervisor 'key' (normally 0) */
-      unsigned long kp:1;      /* User 'key' (normally 1) */
-      unsigned long n:1;       /* No-execute */
-      unsigned long :4;                /* Unused */
-      unsigned long vsid:24;   /* Virtual Segment Identifier */
-   } SEGREG;
+{
+  unsigned long t:1;   /* Normal or I/O  type */
+  unsigned long ks:1;  /* Supervisor 'key' (normally 0) */
+  unsigned long kp:1;  /* User 'key' (normally 1) */
+  unsigned long n:1;   /* No-execute */
+  unsigned long :4;            /* Unused */
+  unsigned long vsid:24;       /* Virtual Segment Identifier */
+} SEGREG;
 
 /* Block Address Translation (BAT) Registers */
+typedef struct _P601_BATU
+{
+  unsigned long bepi:15;       /* Effective page index (virtual address) */
+  unsigned long :8;            /* unused */
+  unsigned long w:1;
+  unsigned long i:1;           /* Cache inhibit */
+  unsigned long m:1;           /* Memory coherence */
+  unsigned long vs:1;  /* Supervisor valid */
+  unsigned long vp:1;  /* User valid */
+  unsigned long pp:2;  /* Page access protections */
+} P601_BATU;
+
 typedef struct _BATU           /* Upper part of BAT */
-   {
-      unsigned long bepi:15;   /* Effective page index (virtual address) */
-      unsigned long :4;                /* Unused */
-      unsigned long bl:11;     /* Block size mask */
-      unsigned long vs:1;      /* Supervisor valid */
-      unsigned long vp:1;      /* User valid */
-   } BATU;   
+{
+  unsigned long bepi:15;       /* Effective page index (virtual address) */
+  unsigned long :4;            /* Unused */
+  unsigned long bl:11; /* Block size mask */
+  unsigned long vs:1;  /* Supervisor valid */
+  unsigned long vp:1;  /* User valid */
+} BATU;   
+
+typedef struct _P601_BATL
+{
+  unsigned long brpn:15;       /* Real page index (physical address) */
+  unsigned long :10;           /* Unused */
+  unsigned long v:1;           /* valid/invalid */
+  unsigned long bl:6;          /* Block size mask */
+} P601_BATL;
 
 typedef struct _BATL           /* Lower part of BAT */
-   {
-      unsigned long brpn:15;   /* Real page index (physical address) */
-      unsigned long :10;       /* Unused */
-      unsigned long w:1;       /* Write-thru cache */
-      unsigned long i:1;       /* Cache inhibit */
-      unsigned long m:1;       /* Memory coherence */
-      unsigned long g:1;       /* Guarded (MBZ) */
-      unsigned long :1;                /* Unused */
-      unsigned long pp:2;      /* Page access protections */
-   } BATL;
+{
+  unsigned long brpn:15;       /* Real page index (physical address) */
+  unsigned long :10;           /* Unused */
+  unsigned long w:1;   /* Write-thru cache */
+  unsigned long i:1;   /* Cache inhibit */
+  unsigned long m:1;   /* Memory coherence */
+  unsigned long g:1;   /* Guarded (MBZ) */
+  unsigned long :1;            /* Unused */
+  unsigned long pp:2;  /* Page access protections */
+} BATL;
 
 typedef struct _BAT
-   {
-      BATU batu;               /* Upper register */
-      BATL batl;               /* Lower register */
-   } BAT;
+{
+  BATU batu;           /* Upper register */
+  BATL batl;           /* Lower register */
+} BAT;
+
+typedef struct _P601_BAT
+{
+  P601_BATU batu;              /* Upper register */
+  P601_BATL batl;              /* Lower register */
+} P601_BAT;
 
 /* Block size masks */
 #define BL_128K        0x000
@@ -118,15 +144,6 @@ typedef struct _MMU_context
       pte      **pmap;         /* Two-level page-map structure */
    } MMU_context;
 
-#if 0
-BAT    ibat[4];        /* Instruction BAT images */
-BAT    dbat[4];        /* Data BAT images */
-PTE    *hash_table;    /* Hardware hashed page table */
-int    hash_table_size;
-int    hash_table_mask;
-unsigned long sdr;     /* Hardware image of SDR */
-#endif   
-
 /* Used to set up SDR register */
 #define HASH_TABLE_SIZE_64K    0x00010000
 #define HASH_TABLE_SIZE_128K   0x00020000
@@ -143,6 +160,4 @@ unsigned long sdr;  /* Hardware image of SDR */
 #define HASH_TABLE_MASK_2M     0x01F   
 #define HASH_TABLE_MASK_4M     0x03F   
 
-extern inline int MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg);
-
 #endif
index f4bd1e84f0a9bb9c89882e9c57a2c778b2a94633..89a649bb31cc9887f25006d9006e39e1fe91c013 100644 (file)
@@ -1,13 +1,59 @@
 #ifndef __PPC_MMU_CONTEXT_H
 #define __PPC_MMU_CONTEXT_H
 
+/* the way contexts are handled on the ppc they are vsid's and
+   don't need any special treatment right now.
+   perhaps I can defer flushing the tlb by keeping a list of
+   zombie vsid/context's and handling that through destroy_context
+   later -- Cort
+ */
+
+#define NO_CONTEXT     0
+#define LAST_CONTEXT   0xfffff
+
+extern int next_mmu_context;
+extern void mmu_context_overflow(void);
+extern void set_context(int context);
+
 /*
- * get a new mmu context.. PowerPC's don't know about contexts [yet]
+ * Allocating context numbers this way tends to spread out
+ * the entries in the hash table better than a simple linear
+ * allocation.
  */
-#define get_mmu_context(x) do { } while (0)
+#define MUNGE_CONTEXT(n)       (((n) * 897) & LAST_CONTEXT)
 
-#define init_new_context(mm)   do { } while(0)
-#define destroy_context(mm)    do { } while(0)
+/*
+ * Get a new mmu context for task tsk if necessary.
+ */
+#define get_mmu_context(tsk)                                   \
+do {                                                           \
+       struct mm_struct *mm = (tsk)->mm;                       \
+       if (mm->context == NO_CONTEXT) {                        \
+               int i; \
+               if (next_mmu_context == LAST_CONTEXT)           \
+                       mmu_context_overflow();                 \
+               mm->context = MUNGE_CONTEXT(++next_mmu_context);\
+               if ( tsk == current )                           \
+                       set_context(mm->context);               \
+       }                                                       \
+} while (0)
 
-#endif
+/*
+ * Set up the context for a new address space.
+ */
+#define init_new_context(mm)   ((mm)->context = NO_CONTEXT)
+
+/*
+ * We're finished using the context for an address space.
+ */
+#define destroy_context(mm)    do { } while (0)
 
+/*
+ * compute the vsid from the context and segment
+ * segments > 7 are kernel segments and their
+ * vsid is the segment -- Cort
+ */
+#define        VSID_FROM_CONTEXT(segment,context) \
+   ((segment < 8) ? ((segment) | (context)<<4) : (segment))
+
+#endif
diff --git a/include/asm-ppc/namei.h b/include/asm-ppc/namei.h
new file mode 100644 (file)
index 0000000..cf6cba2
--- /dev/null
@@ -0,0 +1,21 @@
+/* $Id: namei.h,v 1.1 1997/07/25 09:28:40 cort Exp $
+ * linux/include/asm-i386/namei.h
+ *
+ * Included from linux/fs/namei.c
+ */
+
+#ifndef __I386_NAMEI_H
+#define __I386_NAMEI_H
+
+/* These dummy routines maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define translate_namei(pathname, base, follow_links, res_inode)       \
+       do { } while (0)
+
+#define translate_open_namei(pathname, flag, mode, res_inode, base) \
+       do { } while (0)
+
+#endif /* __I386_NAMEI_H */
index 1d704ff6a540285f82595ebfa1fe9048375f17b1..665bc76afe54ddf2d6f4e65bf335b9841a217f3e 100644 (file)
@@ -9,6 +9,7 @@
 #define NVRAM_AS1  0x75
 #define NVRAM_DATA 0x77
 
+
 /* RTC Offsets */
 
 #define RTC_SECONDS            0x1FF9
@@ -18,6 +19,8 @@
 #define RTC_DAY_OF_MONTH       0x1FFD
 #define RTC_MONTH              0x1FFE
 #define RTC_YEAR               0x1FFF
+#define RTC_CONTROLA            0x1FF8
+#define RTC_CONTROLB            0x1FF9
 
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
index 273d31fd0011e9cc4e5c719b53412d3943d0134a..a18d5e3243cb7a6178451173709d40f0697ff013 100644 (file)
@@ -1,11 +1,32 @@
 #ifndef _PPC_PAGE_H
 #define _PPC_PAGE_H
 
+#include <linux/config.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT     12
 #define PAGE_SIZE      (1UL << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
+/* This handles the memory map.. */
+
+/*
+ * these virtual mappings for prep and pmac
+ * on the prep machine the io areas are at different physical locations
+ * than their virtual address.  On the pmac the io areas
+ * are mapped 1-1 virtual/physical.
+ * -- Cort
+ */
+#ifdef CONFIG_PREP
+#define KERNELBASE     0x90000000
+#endif
+#ifdef CONFIG_PMAC
+#define KERNELBASE     0xc0000000
+#endif
+#define PAGE_OFFSET    KERNELBASE
+
+
+#ifndef __ASSEMBLY__
 #ifdef __KERNEL__
 
 #define STRICT_MM_TYPECHECKS
@@ -50,13 +71,13 @@ typedef unsigned long pgprot_t;
 
 #endif
 
+
+/* align addr on a size boundry - adjust address up if needed -- Cort */
+#define _ALIGN(addr,size)      (((addr)+size-1)&(~(size-1)))
+
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* This handles the memory map.. */
-
-#define KERNELBASE     0x90000000
-#define PAGE_OFFSET    KERNELBASE
 
 #define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)     memcpy((void *)(to), (void *)(from), PAGE_SIZE)
@@ -67,7 +88,8 @@ typedef unsigned long pgprot_t;
 #define MAP_NR(addr)   (__pa(addr) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED      (1<<15)
 
+extern __inline__ unsigned long get_prezerod_page(void);
 
 #endif /* __KERNEL__ */
-
+#endif /* __ASSEMBLY__ */
 #endif /* _PPC_PAGE_H */
index e9c400345491681356df4949afeded68df6bddc3..fd52a64c7b4a357d5e3db002109f12ecb726a96b 100644 (file)
@@ -1,22 +1,31 @@
-/* * Last edited: Nov  7 23:44 1995 (cort) */
 #ifndef _PPC_PGTABLE_H
 #define _PPC_PGTABLE_H
 
+#include <linux/config.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 
-inline void flush_tlb(void);
-inline void flush_tlb_all(void);
-inline void flush_tlb_mm(struct mm_struct *mm);
-inline void flush_tlb_page(struct vm_area_struct *vma, long vmaddr);
-inline void flush_tlb_range(struct mm_struct *mm, long start, long end);
-inline void flush_page_to_ram(unsigned long);
-inline void really_flush_cache_all(void);
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+                           unsigned long end);
+extern void flush_tlb(void);
+
+/* Caches aren't brain-dead on the ppc. */
+#define flush_cache_all()                      
+#define flush_cache_mm(mm)                     
+#define flush_cache_range(mm, start, end)      
+#define flush_cache_page(vma, vmaddr)          
+/*
+ * For the page specified, write modified lines in the data cache
+ * out to memory, and invalidate lines in the instruction cache.
+ */
+extern void flush_page_to_ram(unsigned long);
 
-/* only called from asm in head.S, so why bother? */
-/*void MMU_init(void);*/
+extern unsigned long va_to_phys(unsigned long address);
 
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
+/* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
 #define PMD_SHIFT      22
 #define PMD_SIZE       (1UL << PMD_SHIFT)
 #define PMD_MASK       (~(PMD_SIZE-1))
@@ -27,8 +36,8 @@ inline void really_flush_cache_all(void);
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
 /*
- * entries per page directory level: the i386 is two-level, so
- * we don't really have any PMD directory physically.
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
  */
 #define PTRS_PER_PTE   1024
 #define PTRS_PER_PMD   1
@@ -41,41 +50,42 @@ inline void really_flush_cache_all(void);
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
-/* this must be a decent size since the ppc bat's can map only certain sizes
-   but these can be different from the physical ram size configured.
-   bat mapping must map at least physical ram size and vmalloc start addr
-   must beging AFTER the area mapped by the bat.
-   32 works for now, but may need to be changed with larger differences.
-   offset = next greatest bat mapping to ramsize - ramsize
-   (ie would be 0 if batmapping = ramsize)
-        -- Cort 10/6/96
-   */
-#define VMALLOC_OFFSET (32*1024*1024)
+#define VMALLOC_OFFSET (0x2000000) /* 32M */
 #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 
-#define _PAGE_PRESENT  0x001
-#define _PAGE_RW       0x002
-#define _PAGE_USER     0x004
-#define _PAGE_PCD      0x010
-#define _PAGE_ACCESSED 0x020
-#define _PAGE_DIRTY    0x040
-#define _PAGE_COW      0x200   /* implemented in software (one of the AVL bits) */
-#define _PAGE_NO_CACHE 0x400
+/*
+ * Bits in a linux-style PTE.  These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible.
+ */
+#define _PAGE_PRESENT  0x001   /* software: pte contains a translation */
+#define _PAGE_USER     0x002   /* matches one of the PP bits */
+#define _PAGE_RW       0x004   /* software: user write access allowed */
+#define _PAGE_GUARDED  0x008
+#define _PAGE_COHERENT 0x010   /* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE 0x020   /* I: cache inhibit */
+#define _PAGE_WRITETHRU        0x040   /* W: cache write-through */
+#define _PAGE_DIRTY    0x080   /* C: page changed */
+#define _PAGE_ACCESSED 0x100   /* R: page referenced */
+#define _PAGE_HWWRITE  0x200   /* software: _PAGE_RW & _PAGE_DIRTY */
 
-#define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
 #define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
+#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
+                                _PAGE_ACCESSED)
+#define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define PAGE_KERNEL_NO_CACHE   __pgprot(_PAGE_NO_CACHE | _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
+                                _PAGE_HWWRITE | _PAGE_ACCESSED)
+#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_NO_CACHE | _PAGE_RW | \
+                                _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
 
 /*
- * The i386 can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
+ * The PowerPC can only do execute protection on a segment (256MB) basis,
+ * not on a page basis.  So we consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
  */
 #define __P000 PAGE_NONE
 #define __P001 PAGE_READONLY
@@ -95,18 +105,6 @@ inline void really_flush_cache_all(void);
 #define __S110 PAGE_SHARED
 #define __S111 PAGE_SHARED
 
-/*
- * Define this if things work differently on a i386 and a i486:
- * it will (on a i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
- */
-#undef CONFIG_TEST_VERIFY_AREA
-
-#if 0
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
-#endif
-
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
  * BAD_PAGE is used for a bogus page.
@@ -119,49 +117,36 @@ extern pte_t * __bad_pagetable(void);
 
 extern unsigned long empty_zero_page[1024];
 
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
+#define BAD_PAGETABLE  __bad_pagetable()
+#define BAD_PAGE       __bad_page()
+#define ZERO_PAGE      ((unsigned long) empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR                   (8*sizeof(unsigned long))
+#define BITS_PER_PTR   (8*sizeof(unsigned long))
 
 /* to align the pointer to a pointer address */
-#define PTR_MASK                       (~(sizeof(void*)-1))
+#define PTR_MASK       (~(sizeof(void*)-1))
 
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* sizeof(void*) == 1<<SIZEOF_PTR_LOG2 */
 /* 64-bit machines, beware!  SRB. */
-#define SIZEOF_PTR_LOG2                        2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+#define SIZEOF_PTR_LOG2        2
 
 /* to set the page-dir */
 /* tsk is a task_struct and pgdir is a pte_t */
-#define SET_PAGE_DIR(tsk,pgdir) \
-do { \
-       (tsk)->tss.pg_tables = (unsigned long *)(pgdir); \
-       if ((tsk) == current) \
-       { \
-/*_printk("Change page tables = %x\n", pgdir);*/ \
-       } \
-} while (0)
-
-/* comes from include/linux/mm.h now -- Cort */
-/*extern void *high_memory;*/
+#define SET_PAGE_DIR(tsk,pgdir) ({ \
+       ((tsk)->tss.pg_tables = (unsigned long *)(pgdir)); \
+})
 
 extern inline int pte_none(pte_t pte)          { return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)       { return pte_val(pte) & _PAGE_PRESENT; }
 extern inline void pte_clear(pte_t *ptep)      { pte_val(*ptep) = 0; }
 
 extern inline int pmd_none(pmd_t pmd)          { return !pmd_val(pmd); }
-extern inline int pmd_bad(pmd_t pmd)           { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE; }
-extern inline int pmd_present(pmd_t pmd)       { return pmd_val(pmd) & _PAGE_PRESENT; }
-extern inline int pmd_inuse(pmd_t *pmdp)       { return 0; }
+extern inline int pmd_bad(pmd_t pmd)           { return (pmd_val(pmd) & ~PAGE_MASK) != 0; }
+extern inline int pmd_present(pmd_t pmd)       { return (pmd_val(pmd) & PAGE_MASK) != 0; }
 extern inline void pmd_clear(pmd_t * pmdp)     { pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp)     { }
 
+     
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
@@ -172,7 +157,6 @@ extern inline int pgd_bad(pgd_t pgd)                { return 0; }
 extern inline int pgd_present(pgd_t pgd)       { return 1; }
 extern inline void pgd_clear(pgd_t * pgdp)     { }
 
-
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
@@ -182,48 +166,82 @@ extern inline int pte_write(pte_t pte)            { return pte_val(pte) & _PAGE_RW; }
 extern inline int pte_exec(pte_t pte)          { return pte_val(pte) & _PAGE_USER; }
 extern inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
-extern inline int pte_cow(pte_t pte)           { return pte_val(pte) & _PAGE_COW; }
-
-extern inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_RW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_uncow(pte_t pte)       { pte_val(pte) &= ~_PAGE_COW; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_RW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)      { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)      { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mkcow(pte_t pte)       { pte_val(pte) |= _PAGE_COW; return pte; }
 
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
+extern inline int pte_uncache(pte_t pte)        { return pte_val(pte) |= _PAGE_NO_CACHE; }
+extern inline int pte_cache(pte_t pte)          { return pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+extern inline pte_t pte_rdprotect(pte_t pte) {
+       pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte) {
+       pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte) {
+       pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+extern inline pte_t pte_mkclean(pte_t pte) {
+       pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+extern inline pte_t pte_mkold(pte_t pte) {
+       pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+
+extern inline pte_t pte_mkread(pte_t pte) {
+       pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte) {
+       pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)
+{
+       pte_val(pte) |= _PAGE_RW;
+       if (pte_val(pte) & _PAGE_DIRTY)
+               pte_val(pte) |= _PAGE_HWWRITE;
+       return pte;
+}
+extern inline pte_t pte_mkdirty(pte_t pte)
+{
+       pte_val(pte) |= _PAGE_DIRTY;
+       if (pte_val(pte) & _PAGE_RW)
+               pte_val(pte) |= _PAGE_HWWRITE;
+       return pte;
+}
+extern inline pte_t pte_mkyoung(pte_t pte) {
+       pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#if 1
+#define set_pte(pteptr, pteval)        ((*(pteptr)) = (pteval))
+#else
+extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+       unsigned long val = pte_val(pteval);
+       extern void xmon(void *);
+
+       if ((val & _PAGE_PRESENT) && ((val < 0x111000 || (val & 0x800)
+           || ((val & _PAGE_HWWRITE) && (~val & (_PAGE_RW|_PAGE_DIRTY)))) {
+               printk("bad pte val %lx ptr=%p\n", val, pteptr);
+               xmon(0);
+       }
+       *pteptr = pteval;
+}
+#endif
 
-static pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+static inline pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
 { pte_t pte; pte_val(pte) = (page) | pgprot_val(pgprot); return pte; }
-/*#define mk_pte_phys(physpage, pgprot) \
-({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })*/
 
 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+{ pte_t pte; pte_val(pte) = __pa(page) | pgprot_val(pgprot); return pte; }
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
 extern inline unsigned long pte_page(pte_t pte)
-{ return pte_val(pte) & PAGE_MASK; }
+{ return (pte_val(pte) & PAGE_MASK) + KERNELBASE; }
 
 extern inline unsigned long pmd_page(pmd_t pmd)
-{ return pmd_val(pmd) & PAGE_MASK; }
+{ return pmd_val(pmd); }
 
 
 /* to find an entry in a kernel page-table-directory */
@@ -250,13 +268,14 @@ extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any, and marks the page tables reserved.
+ * used to allocate a kernel page table, but are actually identical
+ * to the xxx() versions.
  */
 extern inline void pte_free_kernel(pte_t * pte)
 {
        free_page((unsigned long) pte);
 }
+
 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
 {
        address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
@@ -264,20 +283,17 @@ extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
                pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
                if (pmd_none(*pmd)) {
                        if (page) {
-/*                                pmd_set(pmd,page);*/
-                       pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+                               pmd_val(*pmd) = (unsigned long) page;
                                return page + address;
                        }
-/*                     pmd_set(pmd, BAD_PAGETABLE);*/
-                       pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+                       pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
                        return NULL;
                }
                free_page((unsigned long) page);
        }
        if (pmd_bad(*pmd)) {
                printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-/*             pmd_set(pmd, (pte_t *) BAD_PAGETABLE);          */
-               pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+               pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
                return NULL;
        }
        return (pte_t *) pmd_page(*pmd) + address;
@@ -308,17 +324,17 @@ extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
                pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
                if (pmd_none(*pmd)) {
                        if (page) {
-                               pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+                               pmd_val(*pmd) = (unsigned long) page;
                                return page + address;
                        }
-                       pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+                       pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
                        return NULL;
                }
                free_page((unsigned long) page);
        }
        if (pmd_bad(*pmd)) {
                printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+               pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
                return NULL;
        }
        return (pte_t *) pmd_page(*pmd) + address;
@@ -350,18 +366,17 @@ extern inline pgd_t * pgd_alloc(void)
 extern pgd_t swapper_pg_dir[1024];
 
 /*
- * Software maintained MMU tables may have changed -- update the
- * hardware [aka cache]
+ * Page tables may have changed.  We don't need to do anything here
+ * as entries are faulted into the hash table by the low-level
+ * data/instruction access exception handlers.
  */
-extern inline void update_mmu_cache(struct vm_area_struct * vma,
-       unsigned long address, pte_t _pte);
+#define update_mmu_cache(vma,address,pte) while(0){}
 
 
 #define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
 #define SWP_OFFSET(entry) ((entry) >> 8)
 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
 
-#define module_map      vmalloc
-#define module_unmap    vfree
+
 
 #endif /* _PPC_PAGE_H */
diff --git a/include/asm-ppc/poll.h b/include/asm-ppc/poll.h
new file mode 100644 (file)
index 0000000..e5feda7
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __i386_POLL_H
+#define __i386_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN         0x0001
+#define POLLPRI                0x0002
+#define POLLOUT                0x0004
+#define POLLERR                0x0008
+#define POLLHUP                0x0010
+#define POLLNVAL       0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM     0x0040
+#define POLLRDBAND     0x0080
+#define POLLWRNORM     0x0100
+#define POLLWRBAND     0x0200
+#define POLLMSG                0x0400
+
+struct pollfd {
+       int fd;
+       short events;
+       short revents;
+};
+
+#endif
diff --git a/include/asm-ppc/ppc_machine.h b/include/asm-ppc/ppc_machine.h
deleted file mode 100644 (file)
index 1cf9a79..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * PowerPC machine specifics
- */
-
-#ifndef _PPC_MACHINE_H_
-#define _PPC_MACHINE_H_ 
-
-#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
-#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
-
-/* Bit encodings for Machine State Register (MSR) */
-#define MSR_POW                (1<<18)         /* Enable Power Management */
-#define MSR_TGPR       (1<<17)         /* TLB Update registers in use */
-#define MSR_ILE                (1<<16)         /* Interrupt Little-Endian enable */
-#define MSR_EE         (1<<15)         /* External Interrupt enable */
-#define MSR_PR         (1<<14)         /* Supervisor/User privilege */
-#define MSR_FP         (1<<13)         /* Floating Point enable */
-#define MSR_ME         (1<<12)         /* Machine Check enable */
-#define MSR_FE0                (1<<11)         /* Floating Exception mode 0 */
-#define MSR_SE         (1<<10)         /* Single Step */
-#define MSR_BE         (1<<9)          /* Branch Trace */
-#define MSR_FE1                (1<<8)          /* Floating Exception mode 1 */
-#define MSR_IP         (1<<6)          /* Exception prefix 0x000/0xFFF */
-#define MSR_IR         (1<<5)          /* Instruction MMU enable */
-#define MSR_DR         (1<<4)          /* Data MMU enable */
-#define MSR_RI         (1<<1)          /* Recoverable Exception */
-#define MSR_LE         (1<<0)          /* Little-Endian enable */
-
-#define MSR_           MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
-#define MSR_USER       MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
-
-/* Bit encodings for Hardware Implementation Register (HID0) */
-#define HID0_EMCP      (1<<31)         /* Enable Machine Check pin */
-#define HID0_EBA       (1<<29)         /* Enable Bus Address Parity */
-#define HID0_EBD       (1<<28)         /* Enable Bus Data Parity */
-#define HID0_SBCLK     (1<<27)
-#define HID0_EICE      (1<<26)
-#define HID0_ECLK      (1<<25)
-#define HID0_PAR       (1<<24)
-#define HID0_DOZE      (1<<23)
-#define HID0_NAP       (1<<22)
-#define HID0_SLEEP     (1<<21)
-#define HID0_DPM       (1<<20)
-#define HID0_ICE       (1<<15)         /* Instruction Cache Enable */
-#define HID0_DCE       (1<<14)         /* Data Cache Enable */
-#define HID0_ILOCK     (1<<13)         /* Instruction Cache Lock */
-#define HID0_DLOCK     (1<<12)         /* Data Cache Lock */
-#define HID0_ICFI      (1<<11)         /* Instruction Cache Flash Invalidate */
-#define HID0_DCI       (1<<10)         /* Data Cache Invalidate */
-#define HID0_SIED      (1<<7)          /* Serial Instruction Execution [Disable] */
-#define HID0_BHTE      (1<<2)          /* Branch History Table Enable */
-
-/* fpscr settings */
-#define FPSCR_FX        (1<<31)
-#define FPSCR_FEX       (1<<30)
-#endif
index aa05332d99c9f1f2e8a3c1f00cfc250e05b14677..10ca545590089e71d3ab68c9e4a985a4c8559896 100644 (file)
@@ -1,12 +1,8 @@
 #ifndef __ASM_PPC_PROCESSOR_H
 #define __ASM_PPC_PROCESSOR_H
 
-/*
- * PowerPC machine specifics
- */
+#include <linux/config.h>
 
-#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
-#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
 
 /* Bit encodings for Machine State Register (MSR) */
 #define MSR_POW                (1<<18)         /* Enable Power Management */
@@ -26,7 +22,8 @@
 #define MSR_RI         (1<<1)          /* Recoverable Exception */
 #define MSR_LE         (1<<0)          /* Little-Endian enable */
 
-#define MSR_           MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
+#define MSR_           MSR_FE0|MSR_FE1|MSR_ME
+#define MSR_KERNEL      MSR_|MSR_IR|MSR_DR
 #define MSR_USER       MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
 
 /* Bit encodings for Hardware Implementation Register (HID0) */
 #define HID0_DCI       (1<<10)         /* Data Cache Invalidate */
 #define HID0_SIED      (1<<7)          /* Serial Instruction Execution [Disable] */
 #define HID0_BHTE      (1<<2)          /* Branch History Table Enable */
-
 /* fpscr settings */
 #define FPSCR_FX        (1<<31)
 #define FPSCR_FEX       (1<<30)
 
-
-
 #ifndef __ASSEMBLY__
 /*
  * PowerPC machine specifics
  */
 extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long );
 
-
 /*
  * Bus types
  */
@@ -77,79 +70,83 @@ extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long )
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
 
-/*
- * User space process size: 2GB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.
- *
- * "this is gonna have to change to 1gig for the sparc" - David S. Miller
- */
 #define TASK_SIZE      (0x80000000UL)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
 #define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
-
 struct thread_struct 
 {
-  unsigned long        ksp;            /* Kernel stack pointer */
-  unsigned long        *pg_tables;     /* MMU information */
-  unsigned long        segs[16];       /* MMU Segment registers */
-  unsigned long        last_pc;        /* PC when last entered system */
-  unsigned long        user_stack;     /* [User] Stack when entered kernel */
-  double               fpr[32];        /* Complete floating point set */
-  unsigned long        wchan;          /* Event task is sleeping on */
-  unsigned long        *regs;          /* Pointer to saved register state */
-  unsigned long fp_used;       /* number of quantums fp was used */
-  unsigned long fs;            /* for get_fs() validation */
-  unsigned long expc;          /* exception handler addr (see fault.c) */
-  unsigned long excount;       /* exception handler count */
+       unsigned long   ksp;            /* Kernel stack pointer */
+       unsigned long   *pg_tables;     /* MMU information */
+#ifdef CONFIG_PMAC
+       unsigned long   last_pc;        /* PC when last entered system */
+       unsigned long   user_stack;     /* [User] Stack when entered kernel */
+#endif  
+       unsigned long   fpscr_pad;      /* (so we can save fpscr with stfd) */
+       unsigned long   fpscr;          /* fp status reg */
+       double          fpr[32];        /* Complete floating point set */
+       unsigned long   fp_used;
+       unsigned long   wchan;          /* Event task is sleeping on */
+       struct pt_regs  *regs;          /* Pointer to saved register state */
+       unsigned long   fs;             /* for get_fs() validation */
+       signed long     last_syscall;
+       unsigned long   pad[2]; /* pad to 16-byte boundry */
 };
 
+/* Points to the thread_struct of the thread (if any) which
+   currently owns the FPU. */
+#define fpu_tss (&(last_task_used_math->tss))
+
+#ifdef CONFIG_PMAC
+#define LAZY_TSS_FPR_INIT 0,0,0,0,{0},
+#endif
+#ifdef CONFIG_PREP
+#define LAZY_TSS_FPR_INIT 0,0,{0},
+#endif
 
 #define INIT_TSS  { \
-       sizeof(init_kernel_stack) + (long) &init_kernel_stack,\
-       (long *)swapper_pg_dir, {0}, \
-       0, 0, {0}, \
-       0, 0, 0, \
-       KERNEL_DS, 0, 0 \
+       sizeof(init_stack) + (long) &init_stack, /* ksp */ \
+       (long *)swapper_pg_dir, /* pg_tables */ \
+       LAZY_TSS_FPR_INIT \
+       0, /*fp_used*/ 0, /*wchan*/ \
+       sizeof(init_stack) + (long)&init_stack - \
+               sizeof(struct pt_regs), /* regs */ \
+       KERNEL_DS /*fs*/, 0 /*last_syscall*/ \
 }
 
-#define INIT_MMAP { &init_mm, 0, 0x40000000, \
-                     PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-/* Free all resources held by a thread. */
-extern void release_thread(struct task_struct *);
+#define INIT_MMAP { &init_mm, KERNELBASE/*0*/, 0xffffffff/*0x40000000*/, \
+                     PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
 
 /*
  * Return saved PC of a blocked thread. For now, this is the "user" PC
  */
 static inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
-       return (t->last_pc);
+       return (t->regs) ? t->regs->nip : 0;
+       /*return (t->last_pc);*/
 }
 
-#define _PROC_Motorola 0
-#define _PROC_IBM      1
-#define _PROC_Be       2
-
-int _Processor;
+extern int _machine;
+#define _MACH_Motorola 0
+#define _MACH_IBM      1
+#define _MACH_Be       2
+#define _MACH_Pmac     3
 
-/* Allocation and freeing of basic task resources. */
-#define alloc_task_struct()    kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define free_task_struct(p)    kfree(p)
-
-#ifdef KERNEL_STACK_BUFFER
-/* give a 1 page buffer below the stack - if change then change ppc_machine.h */
-#define alloc_kernel_stack()  \
-          (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE)
-#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1)
-#else
-#define alloc_kernel_stack()    get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
-#endif
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+       ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p)    free_pages((unsigned long)(p),1)
 
-#endif /* ASSEMBLY*/
+/* in process.c - for early bootup debug -- Cort */
+int ll_printk(const char *, ...);
+void ll_puts(const char *);
 
-#endif
+#endif /* ndef ASSEMBLY*/
 
+#define init_task      (init_task_union.task)
+#define init_stack     (init_task_union.stack)
+  
+#endif /* __ASM_PPC_PROCESSOR_H */
index 5bad3b9da3cdca142b1c6d87cffc86e3867f66f8..13b526172349c9a077231d1717beec5f7db0a679 100644 (file)
@@ -2,54 +2,61 @@
 #define _PPC_PTRACE_H
 
 /*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry.
- * Note: the "_overhead" and "_underhead" spaces are stack locations
- * used by called routines.  Because of the way the PowerPC ABI
- * specifies the function prologue/epilogue, registers can be
- * saved in stack locations which are below the current stack
- * pointer (_underhead).  If an interrupt occurs during this
- * [albeit] small time interval, registers which were saved on
- * the stack could be trashed by the interrupt save code.  The
- * "_underhead" leaves a hole just in case this happens.  It also
- * wastes 80 bytes of stack if it doesn't!  Similarly, the called
- * routine stores some information "above" the stack pointer before
- * if gets adjusted.  This is covered by the "_overhead" field
- * and [thankfully] is not totally wasted.
+ * this should only contain volatile regs
+ * since we can keep non-volatile in the tss
+ * should set this up when only volatiles are saved
+ * by intr code.
  *
+ * I can't find any reference to the above comment (from Gary Thomas)
+ * about _underhead/_overhead in the sys V abi for the ppc
+ * dated july 25, 1994.
+ *
+ * the stack must be kept to a size that is a multiple of 16
+ * so this includes the stack frame overhead 
+ * -- Cort.
+ */
+
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't.  To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
  */
+#define STACK_FRAME_OVERHEAD 16
+#define STACK_UNDERHEAD        64
 
+#ifndef __ASSEMBLY__
 struct pt_regs {
-  unsigned long _overhead[14]; /* Callee's SP,LR,params */
-  unsigned long gpr[32];
-  unsigned long nip;
-  unsigned long msr;
-  unsigned long ctr;
-  unsigned long link;
-  unsigned long ccr;
-  unsigned long xer;
-  unsigned long dar;   /* Fault registers */
-  unsigned long dsisr;
-  unsigned long srr1;
-  unsigned long srr0;
-  unsigned long hash1, hash2;
-  unsigned long imiss, dmiss;
-  unsigned long icmp, dcmp;
-  unsigned long orig_gpr3; /* Used for restarting system calls */
-  unsigned long result;    /* Result of a system call */
-  double        fpcsr;
-  unsigned long trap;  /* Reason for being here */
-  unsigned long marker;        /* Should have DEADDEAD */
-  /*unsigned long _underhead[20]; *//* Callee's register save area */
-  unsigned long edx;   /* for binfmt_elf.c which wants edx */
+       unsigned long gpr[32];
+       unsigned long nip;      
+       unsigned long msr;      
+       unsigned long ctr;      
+       unsigned long link;     
+       unsigned long ccr;      
+       unsigned long xer;      
+       unsigned long dar;      /* Fault registers */
+       unsigned long dsisr;
+#if 0  
+       unsigned long srr1;
+       unsigned long srr0;
+       unsigned long hash1, hash2;
+       unsigned long imiss, dmiss;
+       unsigned long icmp, dcmp;
+#endif  
+       unsigned long orig_gpr3; /* Used for restarting system calls */
+       unsigned long result;   /* Result of a system call */
+       unsigned long trap;     /* Reason for being here */
+       unsigned long marker;   /* Should have DEADDEAD */
 };
 
+
 #define instruction_pointer(regs) ((regs)->nip)
 #define user_mode(regs) ((regs)->msr & 0x4000)
 #ifdef KERNEL
 extern void show_regs(struct pt_regs *);
 #endif
 
+/* should include and generate these in ppc_defs.h -- Cort */
 /* Offsets used by 'ptrace' system call interface */
 /* Note: these should correspond to gpr[x]        */
 #define PT_R0  0
@@ -94,6 +101,7 @@ extern void show_regs(struct pt_regs *);
 #define PT_CCR 38
 
 #define PT_FPR0        48
+#endif /* __ASSEMBLY__ */
 
-#endif
+#endif /* _PPC_PTRACE_H */
 
index 4d1f91372b3476a0aa81200118858d2e9e9a0b29..a4dfa0312f693a3a816270056e4d6231a675f020 100644 (file)
@@ -1,11 +1,18 @@
 #ifndef _PPC_SEMAPHORE_H
 #define _PPC_SEMAPHORE_H
 
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ * Adapted for PowerPC by Gary Thomas and Paul Mackerras
+ */
+
 #include <asm/atomic.h>
 
 struct semaphore {
        atomic_t count;
-       atomic_t waiting;
+       atomic_t waking;
        struct wait_queue * wait;
 };
 
@@ -13,44 +20,61 @@ struct semaphore {
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
 extern void __down(struct semaphore * sem);
+extern int  __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
-extern void atomic_add(int c, int *v);
-extern void atomic_sub(int c, int *v);
+#define sema_init(sem, val)    atomic_set(&((sem)->count), (val))
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ *
+ * This is trivially done with load_locked/store_cond,
+ * i.e. load with reservation and store conditional on the ppc.
+ */
 
-#define sema_init(sem, val)    atomic_set(&((sem)->count), val)
+static inline void wake_one_more(struct semaphore * sem)
+{
+       atomic_inc(&sem->waking);
+}
 
 static inline int waking_non_zero(struct semaphore *sem)
 {
-       unsigned long flags;
-       int ret = 0;
+       int ret, tmp;
+
+       __asm__ __volatile__(
+               "1:     lwarx %1,0,%2\n"
+               "       cmpwi 0,%1,0\n"
+               "       addi %1,%1,-1\n"
+               "       ble- 2f\n"
+               "       stwcx. %1,0,%2\n"
+               "       bne- 1b\n"
+               "       mr %0,%1\n"
+               "2:"
+               : "=r" (ret), "=r" (tmp)
+               : "r" (&sem->waking), "0" (0)
+               : "cr0", "memory");
 
-       save_flags(flags);
-       cli();
-       if (atomic_read(&sem->waking) > 0) {
-               atomic_dec(&sem->waking);
-               ret = 1;
-       }
-       restore_flags(flags);
        return ret;
 }
 
 extern inline void down(struct semaphore * sem)
 {
-  for (;;)
-  {
-    atomic_dec_return(&sem->count);
-    if ( sem->count >= 0)
-      break;
-    __down(sem);
-  }
+       if (atomic_dec_return(&sem->count) < 0)
+               __down(sem);
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+       int ret = 0;
+       if (atomic_dec_return(&sem->count) < 0)
+               ret = __down_interruptible(sem);
+       return ret;
 }
 
 extern inline void up(struct semaphore * sem)
 {
-  atomic_inc_return(&sem->count);
-  if ( sem->count <= 0)
-    __up(sem);
+       if (atomic_inc_return(&sem->count) <= 0)
+               __up(sem);
 }      
 
 #endif /* !(_PPC_SEMAPHORE_H) */
index 00a1e7c9a2721826214d8d4080d2fb56f678ae71..7f54dd7794f5e426818a881922aa36b2f9ec7125 100644 (file)
@@ -19,7 +19,7 @@ struct cpuinfo_PPC {
 };
 
 extern struct cpuinfo_PPC cpu_data[NR_CPUS];
-
+#endif /* __ASSEMBLY__ */
 
 #endif /* !(__SMP__) */
 
diff --git a/include/asm-ppc/smp_lock.h b/include/asm-ppc/smp_lock.h
new file mode 100644 (file)
index 0000000..af47b5c
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PPC_SMPLOCK_H
+#define __PPC_SMPLOCK_H
+
+#ifndef __SMP__
+
+#define lock_kernel()          do { } while (0)
+#define unlock_kernel()                do { } while (0)
+#define release_kernel_lock(task, cpu, depth)  ((depth) = 1)
+#define reacquire_kernel_lock(task, cpu, depth)        do { } while(0)
+
+#else
+
+#error need to defined lock_kernel and unlock_kernel, etc.
+
+#endif /* __SMP__ */
+#endif /* __PPC_SMPLOCK_H */
index d0947469628e2669296b85f296314a4a763f7eff..632717509f8d1f742b69b1d7180377387ee18a36 100644 (file)
 #define SO_PRIORITY    12
 #define SO_LINGER      13
 #define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 14 */
+/* To add :#define SO_REUSEPORT 15 */
 #define SO_RCVLOWAT    16
 #define SO_SNDLOWAT    17
 #define SO_RCVTIMEO    18
 #define SO_SNDTIMEO    19
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION             20
-#define SO_SECURITY_ENCRYPTION_TRANSPORT       21
-#define SO_SECURITY_ENCRYPTION_NETWORK         22
+#define SO_PASSCRED    20
+#define SO_PEERCRED    21
 
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-ppc/softirq.h b/include/asm-ppc/softirq.h
new file mode 100644 (file)
index 0000000..97e7e5e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Software interrupts..
+ */
+
+#ifndef __ASM_SOFTIRQ_H
+#define __ASM_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+#define get_active_bhs()       (bh_mask & bh_active)
+#define clear_active_bhs(x)    atomic_clear_mask((x),&bh_active)
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+       bh_base[nr] = routine;
+       bh_mask_count[nr] = 0;
+       bh_mask |= 1 << nr;
+}
+
+extern inline void remove_bh(int nr)
+{
+       bh_base[nr] = NULL;
+       bh_mask &= ~(1 << nr);
+}
+
+extern inline void mark_bh(int nr)
+{
+       set_bit(nr, &bh_active);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+       bh_mask &= ~(1 << nr);
+       bh_mask_count[nr]++;
+}
+
+extern inline void enable_bh(int nr)
+{
+       if (!--bh_mask_count[nr])
+               bh_mask |= 1 << nr;
+}
+
+#ifndef __SMP__
+
+/*
+ * The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
+ */
+
+extern int __ppc_bh_counter;
+
+extern inline void start_bh_atomic(void)
+{
+       __ppc_bh_counter++;
+       barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+       barrier();
+       __ppc_bh_counter--;
+}
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock()      (__ppc_bh_counter? 0: ((__ppc_bh_counter=1),1))
+#define softirq_endlock()      (__ppc_bh_counter = 0)
+
+#else
+#error Nein, wir haben noch kein SMP
+#endif
+
+#endif
diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
new file mode 100644 (file)
index 0000000..9187d40
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#ifndef __SMP__
+
+typedef struct { int blah; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { }
+
+#define spin_lock_init(lock)   do { } while(0)
+#define spin_lock(lock)                do { } while(0)
+#define spin_trylock(lock)     do { } while(0)
+#define spin_unlock(lock)      do { } while(0)
+#define spin_lock_irq(lock)    cli()
+#define spin_unlock_irq(lock)  sti()
+
+#define spin_lock_irqsave(lock, flags) \
+       do { save_flags(flags); cli(); } while (0)
+#define spin_unlock_irqrestore(lock, flags) \
+       restore_flags(flags)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+typedef struct { int fred; } rwlock_t;
+#define RW_LOCK_UNLOCKED { }
+
+#define read_lock(lock)                do { } while(0)
+#define read_unlock(lock)      do { } while(0)
+#define write_lock(lock)       do { } while(0)
+#define write_unlock(lock)     do { } while(0)
+#define read_lock_irq(lock)    cli()
+#define read_unlock_irq(lock)  sti()
+#define write_lock_irq(lock)   cli()
+#define write_unlock_irq(lock) sti()
+
+#define read_lock_irqsave(lock, flags) \
+       do { save_flags(flags); cli(); } while (0)
+#define read_unlock_irqrestore(lock, flags) \
+       restore_flags(flags)
+#define write_lock_irqsave(lock, flags)        \
+       do { save_flags(flags); cli(); } while (0)
+#define write_unlock_irqrestore(lock, flags) \
+       restore_flags(flags)
+
+#else
+
+/* Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+typedef struct {
+       volatile unsigned int lock;
+       unsigned long previous;
+} spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED { 0, 0 }
+
+#define spin_unlock(lock)      ((lock)->lock = 0)
+
+static inline void spin_lock(spinlock_t * lock)
+{
+       int stuck = 10000000;
+       int tmp, val;
+       __label__ l1;
+
+l1:    __asm__ __volatile__(
+               "       mtctr %2\n"
+               "1:     lwarx %0,0,%3\n"
+               "       andi. %1,%0,1\n\t"
+               "       ori %0,%0,1\n\t"
+               "       bne- 2f\n\t"
+               "       stwcx. %0,0,%3\n\t"
+               "2:     bdnzf- 2,1b"
+               : "=r" (tmp), "=r" (val)
+               : "r" (stuck), "r" (lock)
+               : "ctr");
+       if (!val) {
+               printk("spinlock stuck at %p (%lx)\n", &&l1, lock->previous);
+       } else
+               lock->previous = (unsigned long) &&l1;
+}
+
+#define spin_trylock(lock) (!set_bit(0,(lock)))
+
+#define spin_lock_irq(lock) \
+       do { __cli(); spin_lock(lock); } while (0)
+
+#define spin_unlock_irq(lock) \
+       do { spin_unlock(lock); __sti(); } while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+       do { __save_flags(flags); __cli(); spin_lock(lock); } while (0)
+
+#define spin_unlock_irqrestore(lock, flags) \
+       do { spin_unlock(lock); __restore_flags(flags); } while (0)
+
+#endif /* SMP */
+#endif /* __ASM_SPINLOCK_H */
index 66243582e51ff8ee7ddac9b71ee31f5c02343cb2..207ab36896e083415aab6c5c15f84874fcec71c6 100644 (file)
@@ -1,26 +1,27 @@
 #ifndef _PPC_STRING_H_
 #define _PPC_STRING_H_
 
-
-
-/*
- * keep things happy, the compile became unhappy since memset is
- * in include/linux/string.h and lib/string.c with different prototypes
- *                          -- Cort
- */
-#if 1
-#define  __HAVE_ARCH_MEMSET
-extern __inline__ void * memset(void * s,int c,__kernel_size_t count)
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRNCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMCMP
+#define __HAVE_ARCH_MEMCHR
+/*#define bzero(addr,size) memset((addr),(int)(0),(size))*/
+extern inline void * memchr(const void * cs,int c,size_t count)
 {
-       char *xs = (char *) s;
-
-       while (count--)
-               *xs++ = c;
-
-       return s;
+       unsigned long i = 0;
+       while ( count != i )
+       {
+               if ( (char)c == *(char *)(cs + i) )
+                       return (void *)(cs + i);
+               i--;
+       }
+       return NULL;
 }
 #endif
-#define bzero(addr,size) memset((addr),(int)(0),(size))
-
-
-#endif
index a1a3f12a0acd26196db0794293d7a18855219a42..df527e474204ea544afd670e3fe219629c526f9b 100644 (file)
@@ -1,27 +1,66 @@
 #ifndef __PPC_SYSTEM_H
 #define __PPC_SYSTEM_H
 
-#if 0
-#define mb() \
-__asm__ __volatile__("mb": : :"memory")
-#endif
-#define mb()  __asm__ __volatile__ (""   : : :"memory")
+#include <linux/delay.h>
+
+#define mb()  __asm__ __volatile__ ("sync" : : : "memory")
+
+#define __save_flags(flags)    ({\
+       __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
+/* using Paul's in misc.S now -- Cort */
+extern void __restore_flags(unsigned long flags);
 
+/*
+  #define __sti() _soft_sti(void)
+  #define __cli() _soft_cli(void)
+ */
+extern void __sti(void);
+extern void __cli(void);
 
-extern void __save_flags(long *flags);
-extern void __restore_flags(long flags);
-extern void sti(void);
-extern void cli(void);
+extern void _hard_sti(void);
+extern void _hard_cli(void);
+extern void _soft_sti(void);
+extern void _soft_cli(void);
 extern int _disable_interrupts(void);
 extern void _enable_interrupts(int);
 
-/*extern void memcpy(void *, void *, int);*/
+extern void flush_instruction_cache(void);
+extern void hard_reset_now(void);
+extern void poweroff_now(void);
+extern void find_scsi_boot(void);
+extern int sd_find_target(void *, int);
+extern int _get_PVR(void);
+extern void via_cuda_init(void);
+extern void read_rtc_time(void);
+extern void pmac_find_display(void);
+extern void giveup_fpu(void);
+extern void store_cache_range(unsigned long, unsigned long);
+extern void cvt_fd(float *from, double *to);
+extern void cvt_df(double *from, float *to);
+
+struct device_node;
+extern void note_scsi_host(struct device_node *, void *);
 
 struct task_struct;
 extern void switch_to(struct task_struct *prev, struct task_struct *next);
 
-#define save_flags(flags) __save_flags(&(flags))
-#define restore_flags(flags) __restore_flags(flags)
+struct thread_struct;
+extern void _switch(struct thread_struct *prev, struct thread_struct *next,
+                   unsigned long context);
+
+struct pt_regs;
+extern int do_signal(unsigned long oldmask, struct pt_regs *regs);
+extern void dump_regs(struct pt_regs *);
+
+#ifndef __SMP__
+#define cli()  __cli()
+#define sti()  __sti()
+#define save_flags(flags)      __save_flags(flags)
+#define restore_flags(flags)   __restore_flags(flags)
+
+#else
+#error need global cli/sti etc. defined for SMP
+#endif
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
index 6c19c1fef30b2933f9022b5a6fb7ceaa2d7c91a9..65cab0612b2b94fd32300d309b5f960b1f152200 100644 (file)
@@ -7,7 +7,6 @@ typedef unsigned char   cc_t;
 typedef unsigned int   speed_t;
 typedef unsigned int   tcflag_t;
 
-#if 0 /* This is how it's done on Alpha - maybe later. */
 /*
  * termios type and macro definitions.  Be careful about adding stuff
  * to this file since it's used in GNU libc and there are strict rules
@@ -27,23 +26,24 @@ struct termios {
 };
 
 /* c_cc characters */
-#define VEOF 0
-#define VEOL 1
-#define VEOL2 2
-#define VERASE 3
-#define VWERASE 4
-#define VKILL 5
-#define VREPRINT 6
-#define VSWTC 7
-#define VINTR 8
-#define VQUIT 9
-#define VSUSP 10
-#define VSTART 12
-#define VSTOP 13
-#define VLNEXT 14
-#define VDISCARD 15
-#define VMIN 16
-#define VTIME 17
+#define VINTR  0
+#define VQUIT  1
+#define VERASE         2
+#define VKILL  3
+#define VEOF   4
+#define VMIN   5
+#define VEOL   6
+#define VTIME  7
+#define VEOL2  8
+#define VSWTC  9
+
+#define VWERASE        10
+#define VREPRINT       11
+#define VSUSP          12
+#define VSTART         13
+#define VSTOP          14
+#define VLNEXT         15
+#define VDISCARD       16
 
 /* c_iflag bits */
 #define IGNBRK 0000001
@@ -57,7 +57,7 @@ struct termios {
 #define ICRNL  0000400
 #define IXON   0001000
 #define IXOFF  0002000
-#if !defined(KERNEL) || defined(__USE_BSD)
+#if defined(__KERNEL__) || defined(__USE_BSD)
   /* POSIX.1 doesn't want these... */
 # define IXANY         0004000
 # define IUCLC         0010000
@@ -102,7 +102,7 @@ struct termios {
 #define XTABS  01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
 
 /* c_cflag bit meaning */
-#define CBAUD  0000017
+#define CBAUD  0000377
 #define  B0    0000000         /* hang up */
 #define  B50   0000001
 #define  B75   0000002
@@ -173,6 +173,5 @@ struct termios {
 #define        TCSANOW         0
 #define        TCSADRAIN       1
 #define        TCSAFLUSH       2
-#endif
 
 #endif /* _PPC_TERMBITS_H */
index 26d88027fe2391050af4f252ac5258443658a391..b5e8c78df75eff7833bc47965db10ee6aa8bd4d7 100644 (file)
@@ -137,18 +137,6 @@ struct termio {
        unsigned char c_cc[NCC];        /* control characters */
 };
 
-#define NCCS 19
-struct termios {
-       tcflag_t c_iflag;               /* input mode flags */
-       tcflag_t c_oflag;               /* output mode flags */
-       tcflag_t c_cflag;               /* control mode flags */
-       tcflag_t c_lflag;               /* local mode flags */
-       cc_t c_cc[NCCS];                /* control characters */
-       cc_t c_line;                    /* line discipline (== c_cc[19]) */
-       int c_ispeed;                   /* input speed */
-       int c_ospeed;                   /* output speed */
-};
-
 /* c_cc characters */
 #define _VINTR 0
 #define _VQUIT 1
@@ -161,150 +149,11 @@ struct termios {
 #define _VEOL2 8
 #define _VSWTC 9
 
-#define VINTR  0
-#define VQUIT  1
-#define VERASE         2
-#define VKILL  3
-#define VEOF   4
-#define VMIN   5
-#define VEOL   6
-#define VTIME  7
-#define VEOL2  8
-#define VSWTC  9
-
-#define VWERASE        10
-#define VREPRINT       11
-#define VSUSP          12
-#define VSTART         13
-#define VSTOP          14
-#define VLNEXT         15
-#define VDISCARD       16
-
-
 #ifdef __KERNEL__
-/*     eof=^D          eol=\0          eol2=\0         erase=del
-       werase=^W       kill=^U         reprint=^R      sxtc=\0
-       intr=^C         quit=^\         susp=^Z         <OSF/1 VDSUSP>
-       start=^Q        stop=^S         lnext=^V        discard=^U
-       vmin=\1         vtime=\0
-#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000"
-*/
-
 /*                   ^C  ^\ del  ^U  ^D   1   0   0   0   0  ^W  ^R  ^Z  ^Q  ^S  ^V  ^U  */
 #define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025" 
 #endif
 
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK  0000020
-#define ISTRIP 0000040
-#define INLCR  0000100
-#define IGNCR  0000200
-#define ICRNL  0000400
-#define IXON   0001000
-#define IXOFF  0002000
-#define IXANY  0004000
-#define IUCLC  0010000
-#define IMAXBEL        0020000
-
-/* c_oflag bits */
-#define OPOST  0000001
-#define ONLCR  0000002
-#define OLCUC  0000004
-
-#define OCRNL  0000010
-#define ONOCR  0000020
-#define ONLRET 0000040
-
-#define OFILL  00000100
-#define OFDEL  00000200
-#define NLDLY  00001400
-#define   NL0  00000000
-#define   NL1  00000400
-#define   NL2  00001000
-#define   NL3  00001400
-#define TABDLY 00006000
-#define   TAB0 00000000
-#define   TAB1 00002000
-#define   TAB2 00004000
-#define   TAB3 00006000
-#define CRDLY  00030000
-#define   CR0  00000000
-#define   CR1  00010000
-#define   CR2  00020000
-#define   CR3  00030000
-#define FFDLY  00040000
-#define   FF0  00000000
-#define   FF1  00040000
-#define BSDLY  00100000
-#define   BS0  00000000
-#define   BS1  00100000
-#define VTDLY  00200000
-#define   VT0  00000000
-#define   VT1  00200000
-#define XTABS  01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
-
-/* c_cflag bit meaning */
-#define CBAUD  0000377
-#define  B0    0000000         /* hang up */
-#define  B50   0000001
-#define  B75   0000002
-#define  B110  0000003
-#define  B134  0000004
-#define  B150  0000005
-#define  B200  0000006
-#define  B300  0000007
-#define  B600  0000010
-#define  B1200 0000011
-#define  B1800 0000012
-#define  B2400 0000013
-#define  B4800 0000014
-#define  B9600 0000015
-#define  B19200        0000016
-#define  B38400        0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CBAUDEX 0000020
-#define  B57600   00020
-#define  B115200  00021
-#define  B230400  00022
-#define  B460800  00023
-
-#define CSIZE  00001400
-#define   CS5  00000000
-#define   CS6  00000400
-#define   CS7  00001000
-#define   CS8  00001400
-
-#define CSTOPB 00002000
-#define CREAD  00004000
-#define PARENB 00010000
-#define PARODD 00020000
-#define HUPCL  00040000
-
-#define CLOCAL 00100000
-#define CRTSCTS          020000000000          /* flow control */
-
-/* c_lflag bits */
-#define ISIG   0x00000080
-#define ICANON 0x00000100
-#define XCASE  0x00004000
-#define ECHO   0x00000008
-#define ECHOE  0x00000002
-#define ECHOK  0x00000004
-#define ECHONL 0x00000010
-#define NOFLSH 0x80000000
-#define TOSTOP 0x00400000
-#define ECHOCTL        0x00000040
-#define ECHOPRT        0x00000020
-#define ECHOKE 0x00000001
-#define FLUSHO 0x00800000
-#define PENDIN 0x20000000
-#define IEXTEN 0x00000400
-
 /* modem lines */
 #define TIOCM_LE       0x001
 #define TIOCM_DTR      0x002
@@ -321,23 +170,6 @@ struct termios {
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01   /* Transmitter physically empty */
 
-
-/* tcflow() and TCXONC use these */
-#define        TCOOFF          0
-#define        TCOON           1
-#define        TCIOFF          2
-#define        TCION           3
-
-/* tcflush() and TCFLSH use these */
-#define        TCIFLUSH        0
-#define        TCOFLUSH        1
-#define        TCIOFLUSH       2
-
-/* tcsetattr uses these */
-#define        TCSANOW         0
-#define        TCSADRAIN       1
-#define        TCSAFLUSH       2
-
 /* line disciplines */
 #define N_TTY          0
 #define N_SLIP         1
@@ -349,55 +181,33 @@ struct termios {
 /*
  * Translate a "termio" structure into a "termios". Ugh.
  */
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+       unsigned short __tmp; \
+       get_user(__tmp,&(termio)->x); \
+       (termios)->x = (0xffff0000 & (termios)->x) | __tmp; \
+}
+
 #define user_termio_to_kernel_termios(termios, termio) \
-do { \
-       unsigned short tmp; \
-       get_user(tmp, &(termio)->c_iflag); \
-       (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
-       get_user(tmp, &(termio)->c_oflag); \
-       (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \
-       get_user(tmp, &(termio)->c_cflag); \
-       (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \
-       get_user(tmp, &(termio)->c_lflag); \
-       (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
-       get_user((termios)->c_line, &(termio)->c_line); \
-       get_user((termios)->c_cc[VINTR], &(termio)->c_cc[_VINTR]); \
-       get_user((termios)->c_cc[VQUIT], &(termio)->c_cc[_VQUIT]); \
-       get_user((termios)->c_cc[VERASE], &(termio)->c_cc[_VERASE]); \
-       get_user((termios)->c_cc[VKILL], &(termio)->c_cc[_VKILL]); \
-       get_user((termios)->c_cc[VEOF], &(termio)->c_cc[_VEOF]); \
-       get_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
-       get_user((termios)->c_cc[VEOL], &(termio)->c_cc[_VEOL]); \
-       get_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
-       get_user((termios)->c_cc[VEOL2], &(termio)->c_cc[_VEOL2]); \
-       get_user((termios)->c_cc[VSWTC], &(termio)->c_cc[_VSWTC]); \
-} while(0)
+({ \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+       SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+       copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
 
 /*
  * Translate a "termios" structure into a "termio". Ugh.
- *
- * Note the "fun" _VMIN overloading.
  */
 #define kernel_termios_to_user_termio(termio, termios) \
-do { \
+({ \
        put_user((termios)->c_iflag, &(termio)->c_iflag); \
        put_user((termios)->c_oflag, &(termio)->c_oflag); \
        put_user((termios)->c_cflag, &(termio)->c_cflag); \
        put_user((termios)->c_lflag, &(termio)->c_lflag); \
        put_user((termios)->c_line,  &(termio)->c_line); \
-       put_user((termios)->c_cc[VINTR], &(termio)->c_cc[_VINTR]); \
-       put_user((termios)->c_cc[VQUIT], &(termio)->c_cc[_VQUIT]); \
-       put_user((termios)->c_cc[VERASE], &(termio)->c_cc[_VERASE]); \
-       put_user((termios)->c_cc[VKILL], &(termio)->c_cc[_VKILL]); \
-       put_user((termios)->c_cc[VEOF], &(termio)->c_cc[_VEOF]); \
-       put_user((termios)->c_cc[VEOL], &(termio)->c_cc[_VEOL]); \
-       put_user((termios)->c_cc[VEOL2], &(termio)->c_cc[_VEOL2]); \
-       put_user((termios)->c_cc[VSWTC], &(termio)->c_cc[_VSWTC]); \
-       if (1/*!((termios)->c_lflag & ICANON)*/) { \
-               put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
-               put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
-       } \
-} while(0)
+       copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
 
 #define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
 #define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
index 927447dbd14cc62853497f89608c486fdc9eb938..b1e19ef1fb9008948317bdaa79d883d15be9730e 100644 (file)
@@ -1,22 +1,30 @@
-#ifndef _ASM_UACCESS_H
-#define _ASM_UACCESS_H
+#ifndef _PPC_UACCESS_H
+#define _PPC_UACCESS_H
 
 #ifndef __ASSEMBLY__
 #include <linux/sched.h>
 #include <linux/errno.h>
 
-#define KERNEL_DS   (0)
-#define USER_DS                (1)
-
 #define VERIFY_READ    0
 #define VERIFY_WRITE   1
 
-#define get_fs() (current->tss.fs)
-#define get_ds() (KERNEL_DS)
-#define set_fs(val) ( current->tss.fs = (val))
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define KERNEL_DS      (0)
+#define USER_DS                (1)
+
+#define get_fs()       (current->tss.fs)
+#define get_ds()       (KERNEL_DS)
+#define set_fs(val)    (current->tss.fs = (val))
 
 #define __user_ok(addr,size) (((size) <= 0x80000000)&&((addr) <= 0x80000000-(size)))
-#define __kernel_ok (get_fs() == KERNEL_DS)
+#define __kernel_ok    (get_fs() == KERNEL_DS)
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
@@ -25,126 +33,227 @@ extern inline int verify_area(int type, const void * addr, unsigned long size)
        return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
 
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+       unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
  *
- * As the powerpc uses the same address space for kernel and user
- * data, we can just do these as direct assignments.  (Of course, the
- * exception handling means that it's no longer "just"...)
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the uglyness from the user.
+ *
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
  *
- * Careful to not
- * (a) re-use the arguments for side effects (sizeof/typeof is ok)
- * (b) require any knowledge of processes at this stage
+ * As we use the same address space for kernel and user data on the
+ * PowerPC, we can just do these as direct assignments.  (Of course, the
+ * exception handling means that it's no longer "just"...)
  */
+#define get_user(x,ptr) \
+  __get_user_check((x),(ptr),sizeof(*(ptr)))
+#define put_user(x,ptr) \
+  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __get_user(x,ptr) \
+  __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __put_user(x,ptr) \
+  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
 /*
- * The "__xxx" versions do not do address space checking, useful when
- * doing multiple accesses to the same area (the programmer has to do the
- * checks by hand with "access_ok()")
+ * The "xxx_ret" versions return constant specified in third argument, if
+ * something bad happens. These macros can be optimized for the
+ * case of just returning from the function xxx_ret is used.
  */
-#define put_user(x,ptr) ({ \
-unsigned long __pu_addr = (unsigned long)(ptr); \
-__put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
 
-#define get_user(x,ptr) ({ \
-unsigned long __gu_addr = (unsigned long)(ptr); \
-__get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
+#define put_user_ret(x,ptr,ret) ({ \
+if (put_user(x,ptr)) return ret; })
+
+#define get_user_ret(x,ptr,ret) ({ \
+if (get_user(x,ptr)) return ret; })
+
+#define __put_user_ret(x,ptr,ret) ({ \
+if (__put_user(x,ptr)) return ret; })
+
+#define __get_user_ret(x,ptr,ret) ({ \
+if (__get_user(x,ptr)) return ret; })
+
+
+extern long __put_user_bad(void);
+
+#define __put_user_nocheck(x,ptr,size)                 \
+({                                                     \
+       long __pu_err;                                  \
+       __put_user_size((x),(ptr),(size),__pu_err);     \
+       __pu_err;                                       \
+})
+
+#define __put_user_check(x,ptr,size)                           \
+({                                                             \
+       long __pu_err = -EFAULT;                                \
+       __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
+       if (access_ok(VERIFY_WRITE,__pu_addr,size))             \
+               __put_user_size((x),__pu_addr,(size),__pu_err); \
+       __pu_err;                                               \
+})
+
+#define __put_user_size(x,ptr,size,retval)                     \
+do {                                                           \
+       retval = 0;                                             \
+       switch (size) {                                         \
+         case 1: __put_user_asm(x,ptr,retval,"stb"); break;    \
+         case 2: __put_user_asm(x,ptr,retval,"sth"); break;    \
+         case 4: __put_user_asm(x,ptr,retval,"stw"); break;    \
+         default: __put_user_bad();                            \
+       }                                                       \
+} while (0)
 
-#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
-#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
 struct __large_struct { unsigned long buf[100]; };
-#define __m(x) ((struct __large_struct *)(x))
-
-#define __put_user_check(x,addr,size) ({ \
-int __pu_ret; \
-__pu_ret = -EFAULT; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __pu_ret =__put_user_8(x,addr); break; \
-case 2: __pu_ret =__put_user_16(x,addr); break; \
-case 4: __pu_ret =__put_user_32(x,addr); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} } __pu_ret; })
-
-#define __put_user_nocheck(x,addr,size) ({ \
-int __pu_ret; \
-__pu_ret = -EFAULT; \
-switch (size) { \
-case 1: __pu_ret =__put_user_8(x,addr); break; \
-case 2: __pu_ret =__put_user_16(x,addr); break; \
-case 4: __pu_ret =__put_user_32(x,addr); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} __pu_ret; })
-
-extern int __put_user_bad(void);
-
-#define __get_user_check(x,addr,size,type) ({ \
-register int __gu_ret asm("r4"); \
-unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __gu_val = __get_user_8(__gu_val,addr); break; \
-case 2: __gu_val = __get_user_16(__gu_val,addr); break; \
-case 4: __gu_val = __get_user_32(__gu_val,addr); break; \
-default: __get_user_bad(); break; \
-} } (x) = (type) __gu_val; __gu_ret; })
-
-#define __get_user_nocheck(x,addr,size,type) ({ \
-register int __gu_ret asm("r4"); \
-unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
-switch (size) { \
-case 1: __gu_val =__get_user_8(__gu_val,addr); break; \
-case 2: __gu_val =__get_user_16(__gu_val,addr); break; \
-case 4: __gu_val =__get_user_32(__gu_val,addr); break; \
-default: __gu_val = __get_user_bad(); break; \
-} (x) = (type) __gu_val; __gu_ret;  })
-     
+#define __m(x) (*(struct __large_struct *)(x))
+
+/*
+ * We don't tell gcc that we are accessing memory, but this is OK
+ * because we do not write to any memory gcc knows about, so there
+ * are no aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, op)                       \
+       __asm__ __volatile__(                                   \
+               "1:     "op" %1,0(%2)\n"                        \
+               "2:\n"                                          \
+               ".section .fixup,\"ax\"\n"                      \
+               "3:     li %0,%3\n"                             \
+               "       b 2b\n"                                 \
+               ".section __ex_table,\"a\"\n"                   \
+               "       .align 2\n"                             \
+               "       .long 1b,3b\n"                          \
+               ".text"                                         \
+               : "=r"(err)                                     \
+               : "r"(x), "b"(addr), "i"(-EFAULT), "0"(err))
+
+
+#define __get_user_nocheck(x,ptr,size)                         \
+({                                                             \
+       long __gu_err, __gu_val;                                \
+       __get_user_size(__gu_val,(ptr),(size),__gu_err);        \
+       (x) = (__typeof__(*(ptr)))__gu_val;                     \
+       __gu_err;                                               \
+})
+
+#define __get_user_check(x,ptr,size)                                   \
+({                                                                     \
+       long __gu_err = -EFAULT, __gu_val = 0;                          \
+       const __typeof__(*(ptr)) *__gu_addr = (ptr);                    \
+       if (access_ok(VERIFY_READ,__gu_addr,size))                      \
+               __get_user_size(__gu_val,__gu_addr,(size),__gu_err);    \
+       (x) = (__typeof__(*(ptr)))__gu_val;                             \
+       __gu_err;                                                       \
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval)                     \
+do {                                                           \
+       retval = 0;                                             \
+       switch (size) {                                         \
+         case 1: __get_user_asm(x,ptr,retval,"lbz"); break;    \
+         case 2: __get_user_asm(x,ptr,retval,"lhz"); break;    \
+         case 4: __get_user_asm(x,ptr,retval,"lwz"); break;    \
+         default: (x) = __get_user_bad();                      \
+       }                                                       \
+} while (0)
+
+#define __get_user_asm(x, addr, err, op)               \
+       __asm__ __volatile__(                           \
+               "1:     "op" %1,0(%2)\n"                \
+               "2:\n"                                  \
+               ".section .fixup,\"ax\"\n"              \
+               "3:     li %0,%3\n"                     \
+               "       li %1,0\n"                      \
+               "       b 2b\n"                         \
+               ".section __ex_table,\"a\"\n"           \
+               "       .align 2\n"                     \
+               "       .long 1b,3b\n"                  \
+               ".text"                                 \
+               : "=r"(err), "=r"(x)                    \
+               : "b"(addr), "i"(-EFAULT), "0"(err))
 
 /* more complex routines */
 
-extern int __copy_tofrom_user(unsigned long to, unsigned long from, int size);
-
-#define copy_to_user(to,from,n) ({ \
-unsigned long __copy_to = (unsigned long) (to); \
-unsigned long __copy_size = (unsigned long) (n); \
-unsigned long __copy_res = -EFAULT; \
-if(__copy_size && __access_ok(__copy_to, __copy_size)) { \
-__copy_res = __copy_tofrom_user(__copy_to, (unsigned long) (from), __copy_size); \
-}  \
-__copy_res; })
-
-#define copy_from_user(to,from,n) ({ \
-unsigned long __copy_from = (unsigned long) (from); \
-unsigned long __copy_size = (unsigned long) (n); \
-unsigned long __copy_res = -EFAULT; \
-if(__copy_size && __access_ok(__copy_from, __copy_size)) { \
-__copy_res = __copy_tofrom_user((unsigned long) (to), __copy_from, __copy_size); \
-} \
-__copy_res; })
-
-extern int __clear_user(unsigned long addr, int size);
-
-#define clear_user(addr,n) ({ \
-unsigned long __clear_addr = (unsigned long) (addr); \
-int __clear_size = (int) (n); \
-int __clear_res = -EFAULT; \
-if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \
-__clear_res = __clear_user(__clear_addr, __clear_size); \
-} \
-__clear_res; })
-
-extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count);
-
-#define strncpy_from_user(dest,src,count) ({ \
-unsigned long __sfu_src = (unsigned long) (src); \
-int __sfu_count = (int) (count); \
-long __sfu_res = -EFAULT; \
-if(__access_ok(__sfu_src, __sfu_count)) { \
-__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
-} __sfu_res; })
+extern int __copy_tofrom_user(void *to, const void *from, unsigned long size);
+
+extern inline unsigned long
+copy_from_user(void *to, const void *from, unsigned long n)
+{
+       if (access_ok(VERIFY_READ, from, n))
+               return __copy_tofrom_user(to, from, n);
+       return n? -EFAULT: 0;
+}
+
+extern inline unsigned long
+copy_to_user(void *to, const void *from, unsigned long n)
+{
+       if (access_ok(VERIFY_WRITE, to, n))
+               return __copy_tofrom_user(to, from, n);
+       return n? -EFAULT: 0;
+}
+
+#define __copy_from_user(to, from, size) \
+       __copy_tofrom_user((to), (from), (size))
+#define __copy_to_user(to, from, size) \
+       __copy_tofrom_user((to), (from), (size))
+
+extern unsigned long __clear_user(void *addr, unsigned long size);
+
+extern inline unsigned long
+clear_user(void *addr, unsigned long size)
+{
+       if (access_ok(VERIFY_WRITE, addr, size))
+               return __clear_user(addr, size);
+       return size? -EFAULT: 0;
+}
+
+extern int __strncpy_from_user(char *dst, const char *src, long count);
+
+extern inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+       if (access_ok(VERIFY_READ, src, 1))
+               return __strncpy_from_user(dst, src, count);
+       return -EFAULT;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error
+ */
+
+extern long strlen_user(const char *);
 
 #endif  /* __ASSEMBLY__ */
 
-#endif /* _ASM_UACCESS_H */
+#endif /* _PPC_UACCESS_H */
index 47b0a7912c3a27323b48ac3bb4f4d47a4bcd034c..5665d906c8541f1dec423ea0512d58fda179dc44 100644 (file)
@@ -1,10 +1,6 @@
-/* * Last edited: Nov 17 16:28 1995 (cort) */
 #ifndef _ASM_PPC_UNISTD_H_
 #define _ASM_PPC_UNISTD_H_
 
-#define _NR(n) #n
-#define _lisc(n) "li 0," _NR(n)
-
 /*
  * This file contains the system call numbers.
  */
 #define __NR_mremap            163
 #define __NR_setresuid         164
 #define __NR_getresuid         165
-#define __NR_nfsservctl                166
+#define __NR_query_module      166
+#define __NR_poll              167
+#define __NR_nfsservctl                168
+
+#define __NR(n)        #n
+#define __do_syscall(n) \
+       asm volatile ("li 0,%0\n\
+       sc\n\
+       bns 1f\n\
+       mr 0,3\n\
+       lis 3,errno@ha\n\
+       stw 0,errno@l(3)\n\
+       li 3,-1\n\
+1:" : : "i" (n) : "r0", "r3")
 
-/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
 #define _syscall0(type,name) \
 type name(void) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
 #define _syscall1(type,name,type1,arg1) \
 type name(type1 arg1) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
 #define _syscall2(type,name,type1,arg1,type2,arg2) \
 type name(type1 arg1,type2 arg2) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
 type name(type1 arg1,type2 arg2,type3 arg3) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-} 
-
+{ __do_syscall(__NR_##name); }
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
          type5,arg5) \
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
+{ __do_syscall(__NR_##name); }
 
 #ifdef __KERNEL_SYSCALLS__
 
 /*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
+ * Forking from kernel space will result in NO COPY ON WRITE (!!!),
+ * until an execve is executed. This is no problem, but for the stack.
+ * This is handled by not letting main() use the stack at all after
+ * fork().  On the PowerPC, this means we can only call leaf functions.
  */
 
-
-#if 0
 /*
-   This is the mechanism for creating a new kernel thread.
-   For the time being it only behaves the same as clone().
-   It should be changed very soon to work properly and cleanly.  This
-   gets us going for now, though.
-
-   some versions of gcc hate this -- complains about constraints being
-   incorrect.  not sure why so it's in arch/ppc/kernel/misc.S now.
-     -- Cort
+ * Create a new kernel thread.
  */
-static __inline__ long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-  long retval;
-  __asm__  (
-       "li 0, 120 \n\t"        /* __NR_clone */
-       "li 3, %5 \n\t"         /* load flags as arg to clone */
-       /*"mr 1,7 \n\t"*/               /* save kernel stack */
-       "sc \n\t"               /* syscall */
-       /*"cmp 0,1,7 \n\t"*/    /* if kernel stack changes -- child */
-       "cmpi   0,3,0 \n\t"
-       "bne 1f \n\t"           /* return if parent */
-       /* this is in child */
-       "li 3, %3 \n\t"         /* child -- load args and call fn */
-       "mtlr %4 \n\t"          
-       "blrl \n\t"
-       "li 0, %2 \n\t"         /* exit after child exits */
-        "li 3, 0 \n\t"
-       "sc \n\t"
-       /* parent */
-       "1: \n\t"
-       :"=3" (retval)
-       :"i" (__NR_clone), "i" (__NR_exit),
-        "r" (arg), "r" (fn), "g" (CLONE_VM|flags) 
-       :"cc", "1", "0", "3", "7", "31", "memory" );
-  return retval;
-}
-#else
 extern long __kernel_thread(unsigned long, int (*)(void *), void *);
 
 static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
        return __kernel_thread(flags | CLONE_VM, fn, arg);
 }
-#endif
 
-#define __NR__exit __NR_exit
-static inline _syscall0(int,idle) /* made inline "just in case" -- Cort */
-static inline _syscall0(int,fork) /* needs to be inline */
-static inline _syscall0(int,pause) /* needs to be inline */
-static inline _syscall1(int,setup,int,magic) /* called in init before execve */
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static /*inline*/ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static /*inline*/ _syscall1(int,dup,int,fd)
-static /*inline*/ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static /*inline*/ _syscall3(int,open,const char *,file,int,flag,int,mode)
-static /*inline*/ _syscall1(int,close,int,fd)
-static /*inline*/ _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
+/*
+ * System call prototypes.
+ */
+int idle(void);
+int setup(int);
+int sync(void);
+pid_t setsid(void);
+int write(int, const char *, off_t);
+int dup(int);
+int execve(const char *, char **, char **);
+int open(const char *, int, int);
+int close(int);
+pid_t waitpid(pid_t, int *, int);
 
-/* called from init before execve -- need to be inline? -- Cort */
 static inline pid_t wait(int * wait_stat) 
 {
        return waitpid(-1,wait_stat,0);
 }
 
-#endif
+#endif /* __KERNEL_SYSCALLS__ */
 
 #endif /* _ASM_PPC_UNISTD_H_ */
-
-
index 7c4ba26e4ac36284d652e01db5f43f791f4d58df..6d2f1e7301c163dfee33b57f98ad8e553295d022 100644 (file)
@@ -48,7 +48,6 @@ struct  fbtype {
 };
 #define FBIOGTYPE _IOR('F', 0, struct fbtype)
 
-/* Used by FBIOPUTCMAP */
 struct  fbcmap {
         int             index;          /* first element (0 origin) */
         int             count;
@@ -150,6 +149,21 @@ struct fb_wid_list {
 #define FBIO_WID_PUT   _IOW('F', 32, struct fb_wid_list)
 #define FBIO_WID_GET   _IOWR('F', 33, struct fb_wid_list)
 
+/* Creator ioctls */
+#define FFB_IOCTL      ('F'<<8)
+#define FFB_SYS_INFO           (FFB_IOCTL|80)
+#define FFB_CLUTREAD           (FFB_IOCTL|81)
+#define FFB_CLUTPOST           (FFB_IOCTL|82)
+#define FFB_SETDIAGMODE                (FFB_IOCTL|83)
+#define FFB_GETMONITORID       (FFB_IOCTL|84)
+#define FFB_GETVIDEOMODE       (FFB_IOCTL|85)
+#define FFB_SETVIDEOMODE       (FFB_IOCTL|86)
+#define FFB_SETSERVER          (FFB_IOCTL|87)
+#define FFB_SETOVCTL           (FFB_IOCTL|88)
+#define FFB_GETOVCTL           (FFB_IOCTL|89)
+#define FFB_GETSAXNUM          (FFB_IOCTL|90)
+#define FFB_FBDEBUG            (FFB_IOCTL|91)
+
 /* Cg14 ioctls */
 #define MDI_IOCTL          ('M'<<8)
 #define MDI_RESET          (MDI_IOCTL|1)
@@ -174,15 +188,15 @@ struct mdi_cfginfo {
  */
 #define MDI_CLEAR_XLUT       (MDI_IOCTL|9)
 
-/* leo ioctls */
-struct leo_clut_alloc {
+/* leo & ffb ioctls */
+struct fb_clut_alloc {
        __u32   clutid; /* Set on return */
        __u32   flag;
        __u32   index;
 };
 
-struct leo_clut {
-#define LEO_CLUT_WAIT  0x00000001      /* Not yet implemented */
+struct fb_clut {
+#define FB_CLUT_WAIT   0x00000001      /* Not yet implemented */
        __u32   flag;
        __u32   clutid;
        __u32   offset;
@@ -191,10 +205,21 @@ struct leo_clut {
        char *  green;
        char *  blue;
 };
-#define LEO_CLUTALLOC  _IOWR('L', 53, struct leo_clut_alloc)
-#define LEO_CLUTFREE   _IOW('L', 54, struct leo_clut_alloc)
-#define LEO_CLUTREAD   _IOW('L', 55, struct leo_clut)
-#define LEO_CLUTPOST   _IOW('L', 56, struct leo_clut)
+
+struct fb_clut32 {
+       __u32   flag;
+       __u32   clutid;
+       __u32   offset;
+       __u32   count;
+       __u32   red;
+       __u32   green;
+       __u32   blue;
+};
+
+#define LEO_CLUTALLOC  _IOWR('L', 53, struct fb_clut_alloc)
+#define LEO_CLUTFREE   _IOW('L', 54, struct fb_clut_alloc)
+#define LEO_CLUTREAD   _IOW('L', 55, struct fb_clut)
+#define LEO_CLUTPOST   _IOW('L', 56, struct fb_clut)
 #define LEO_SETGAMMA   _IOW('L', 68, int) /* Not yet implemented */
 #define LEO_GETGAMMA   _IOR('L', 69, int) /* Not yet implemented */
 
index 106fa4e1b0574d460f817c38b6539229b3d3ae15..62a97ed405e6ed964feb3d92a08ec2eaa7acb4ca 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef _SPARC_SMP_H
 #define _SPARC_SMP_H
 
+#include <asm/head.h>
+
 #ifndef __ASSEMBLY__
 /* PROM provided per-processor information we need
  * to start them all up.
index 577f3c8779b99282c056a8cae3b28070ab89e5fb..6b2852c2995eca569960ab310c66be323e9e475b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.7 1997/04/03 09:29:25 davem Exp $
+/* $Id: oplib.h,v 1.8 1997/07/24 12:15:15 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -179,8 +179,7 @@ extern enum prom_output_device prom_query_output_device(void);
 /* Start the CPU with the given device tree node, context table, and context
  * at the passed program counter.
  */
-extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table,
-                        int context, char *program_counter);
+extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0);
 
 /* Stop the CPU with the passed device tree node. */
 extern int prom_stopcpu(int cpunode);
index 5cbd9a3c54e85bbdcae109732277dcd3369471be..5d31b3bf5cdf00150438510b434036317a3c109d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.49 1997/06/30 09:24:12 jj Exp $
+/* $Id: pgtable.h,v 1.50 1997/07/24 16:48:31 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -158,33 +158,33 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
 
 /* Cache and TLB flush operations. */
 
-#define flush_cache_all()      \
-do {   unsigned long va;       \
-       flushw_all();           \
-       for(va = 0;             \
-           va<(PAGE_SIZE<<1);  \
-           va += 32)           \
-spitfire_put_icache_tag(va,0x0);\
-} while(0)
-
+/* These are the same regardless of whether this is an SMP kernel or not. */
 #define flush_cache_mm(mm)                     do { } while(0)
 #define flush_cache_range(mm, start, end)      do { } while(0)
 #define flush_cache_page(vma, page)            do { } while(0)
 
 /* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_page_to_ram(page)                do { } while (0)
+#define flush_page_to_ram(page)                        do { } while (0)
 
-extern void flush_tlb_all(void);
+extern void __flush_cache_all(void);
 
+extern void __flush_tlb_all(void);
 extern void __flush_tlb_mm(unsigned long context);
+extern void __flush_tlb_range(unsigned long context, unsigned long start,
+                             unsigned long end);
+extern void __flush_tlb_page(unsigned long context, unsigned long page);
+
+#ifndef __SMP__
+
+#define flush_cache_all()      __flush_cache_all()
+#define flush_tlb_all()                __flush_tlb_all()
+
 extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
 {
        if(mm->context != NO_CONTEXT)
                __flush_tlb_mm(mm->context & 0x1fff);
 }
 
-extern void __flush_tlb_range(unsigned long context, unsigned long start,
-                             unsigned long end);
 extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
                                       unsigned long end)
 {
@@ -192,7 +192,6 @@ extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start
                __flush_tlb_range(mm->context & 0x1fff, start, end);
 }
 
-extern void __flush_tlb_page(unsigned long context, unsigned long page);
 extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
        struct mm_struct *mm = vma->vm_mm;
@@ -201,6 +200,41 @@ extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long
                __flush_tlb_page(mm->context & 0x1fff, page & PAGE_MASK);
 }
 
+#else /* __SMP__ */
+
+extern void smp_flush_cache_all(void);
+extern void smp_flush_tlb_all(void);
+extern void smp_flush_tlb_mm(struct mm_struct *mm);
+extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+                               unsigned long end);
+extern void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+
+#define flush_cache_all()      smp_flush_cache_all()
+#define flush_tlb_all()                smp_flush_tlb_all()
+
+extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
+{
+       if(mm->context != NO_CONTEXT)
+               smp_flush_tlb_mm(mm);
+}
+
+extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+                                      unsigned long end)
+{
+       if(mm->context != NO_CONTEXT)
+               smp_flush_tlb_range(mm, start, end);
+}
+
+extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+       struct mm_struct *mm = vma->vm_mm;
+
+       if(mm->context != NO_CONTEXT)
+               smp_flush_tlb_page(vma, page);
+}
+
+#endif
+
 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
 { return __pte(__pa(page) | pgprot_val(pgprot)); }
 
index 57dc42260299c7c6d7021a77b60b658ef5774506..297173a89528a35ffeb6d6f4a9e63fee0f321804 100644 (file)
@@ -24,20 +24,17 @@ extern void __up(struct semaphore * sem);
 
 #define wake_one_more(sem)      atomic_inc(&sem->waking);
 
-extern __inline__ int waking_non_zero(struct semaphore *sem)
-{
-        unsigned long flags;
-        int ret = 0;
-
-        save_flags(flags);
-        cli();
-        if (atomic_read(&sem->waking) > 0) {
-                atomic_dec(&sem->waking);
-                ret = 1;
-        }
-        restore_flags(flags);
-        return ret;
-}
+#define waking_non_zero(sem) \
+({     unsigned long flags; \
+       int ret = 0; \
+       save_and_cli(flags); \
+       if (atomic_read(&sem->waking) > 0) { \
+               atomic_dec(&sem->waking); \
+               ret = 1; \
+       } \
+       restore_flags(flags); \
+       ret; \
+})
 
 extern __inline__ void down(struct semaphore * sem)
 {
index 73fc7178088115bc651980bd10c2bd2b6a0c6d5d..116f83237c52a2eb12e4a3bb8a224c30342c5e89 100644 (file)
@@ -19,7 +19,7 @@ struct prom_cpuinfo {
 };
 
 extern int linux_num_cpus;     /* number of CPUs probed  */
-extern struct prom_cpuinfo linux_cpus[NCPUS];
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 
 #endif /* !(__ASSEMBLY__) */
 
@@ -35,8 +35,12 @@ struct cpuinfo_sparc {
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
 
-typedef __volatile__ unsigned char klock_t;
-extern klock_t kernel_flag;
+struct klock_info {
+       unsigned char kernel_flag;
+       unsigned char akp;
+};
+
+extern struct klock_info klock_info;
 
 #define KLOCK_HELD       0xff
 #define KLOCK_CLEAR      0x00
@@ -47,7 +51,7 @@ extern klock_t kernel_flag;
  
 extern int smp_found_cpus;
 extern unsigned char boot_cpu_id;
-extern unsigned int cpu_present_map;
+extern unsigned long cpu_present_map;
 extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
 extern __volatile__ unsigned long kernel_counter;
 extern __volatile__ unsigned char active_kernel_processor;
@@ -68,42 +72,21 @@ typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
 extern void smp_callin(void);
 extern void smp_boot_cpus(void);
 extern void smp_store_cpu_info(int id);
-extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-                          unsigned long arg3, unsigned long arg4, unsigned long arg5);
-
-extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); }
-extern __inline__ void xc1(smpfunc_t func, unsigned long arg1)
-{ smp_cross_call(func, arg1, 0, 0, 0, 0); }
-extern __inline__ void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2)
-{ smp_cross_call(func, arg1, arg2, 0, 0, 0); }
-extern __inline__ void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-                          unsigned long arg3)
-{ smp_cross_call(func, arg1, arg2, arg3, 0, 0); }
-extern __inline__ void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-                          unsigned long arg3, unsigned long arg4)
-{ smp_cross_call(func, arg1, arg2, arg3, arg4, 0); }
-extern __inline__ void xc5(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-                          unsigned long arg3, unsigned long arg4, unsigned long arg5)
-{ smp_cross_call(func, arg1, arg2, arg3, arg4, arg5); }
 
 extern __volatile__ int cpu_number_map[NR_CPUS];
 extern __volatile__ int cpu_logical_map[NR_CPUS];
 
-extern __inline__ int smp_processor_id(void)
+extern __inline__ int hard_smp_processor_id(void)
 {
-       int cpuid;
+       unsigned long upaconfig;
 
-       /* Get MID from UPA Config register, and use that. */
-       __asm__ __volatile__("
-               ldxa    [%g0] %1, %0
-               srlx    %0, 17, %0
-               and     %0, 0x1f, %0
-       " : "=r" cpuid
-         : "i" (ASI_UPA_CONFIG));
-
-       return cpuid;
+       __asm__ __volatile__("ldxa      [%%g0] %1, %0"
+                            : "=r" (upaconfig)
+                            : "i" (ASI_UPA_CONFIG));
+       return ((upaconfig >> 17) & 0x1f);
 }
 
+#define smp_processor_id() (current->processor)
 
 extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
 #endif /* !(__ASSEMBLY__) */
@@ -122,9 +105,6 @@ extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing pr
 #define MBOX_IDLECPU2         0xFD
 #define MBOX_STOPCPU2         0xFE
 
-
-#define NO_PROC_ID            0xFF
-
 #define PROC_CHANGE_PENALTY     20
 
 #define SMP_FROM_INT           1
@@ -132,4 +112,6 @@ extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing pr
 
 #endif /* !(__SMP__) */
 
+#define NO_PROC_ID            0xFF
+
 #endif /* !(_SPARC64_SMP_H) */
index 12821b21557b5d96ca762be43fb0c62ad628b374..3012ed6bb5ee406165f15db49f03930883ae815a 100644 (file)
 #define reacquire_kernel_lock(task, cpu, depth)        do { } while(0)
 
 #else
-#error SMP on sparc64 not supported yet
+
+#include <asm/hardirq.h>
+
+/* Release global kernel lock and global interrupt lock */
+#define release_kernel_lock(task, cpu, depth)          \
+do {                                                   \
+       if((depth = (task)->lock_depth) != 0) {         \
+               __cli();                                \
+               (task)->lock_depth = 0;                 \
+               klock_info.akp = NO_PROC_ID;            \
+               klock_info.kernel_flag = 0;             \
+       }                                               \
+       release_irqlock(cpu);                           \
+       __sti();                                        \
+} while(0)
+
+/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
+#define reacquire_kernel_lock(task, cpu, depth)                                        \
+do {                                                                           \
+       if(depth) {                                                             \
+               register struct klock_info *klip asm("g1");                     \
+               klip = &klock_info;                                             \
+               __asm__ __volatile__("mov       %%o7, %%g5\n\t"                 \
+                                    "call      ___lock_reacquire_kernel\n\t"   \
+                                    " mov      %1, %%g2"                       \
+                                    : /* No outputs. */                        \
+                                    : "r" (klip), "r" (depth)                  \
+                                    : "g2", "g3", "g5", "g7", "memory", "cc"); \
+       }                                                                       \
+} while(0)
+
+/* The following acquire and release the master kernel global lock,
+ * the idea is that the usage of this mechanmism becomes less and less
+ * as time goes on, to the point where they are no longer needed at all
+ * and can thus disappear.
+ */
+
+/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
+extern __inline__ void lock_kernel(void)
+{
+       register struct klock_info *klip asm("g1");
+       klip = &klock_info;
+       __asm__ __volatile__("
+       mov     %%o7, %%g5
+       call    ___lock_kernel
+        ld     [%%g6 + %0], %%g2
+"      : : "i" (AOFF_task_lock_depth), "r" (klip)
+       : "g2", "g3", "g5", "g7", "memory", "cc");
+}
+
+/* Release kernel global lock. */
+extern __inline__ void unlock_kernel(void)
+{
+       register struct klock_info *klip asm("g1");
+       klip = &klock_info;
+       __asm__ __volatile__("
+       mov     %%o7, %%g5
+       call    ___unlock_kernel
+        ld     [%%g6 + %0], %%g2
+"      : : "i" (AOFF_task_lock_depth), "r" (klip)
+       : "g2", "g3", "g5", "memory", "cc");
+}
+
 #endif /* (__SMP__) */
 
 #endif /* !(__SPARC64_SMPLOCK_H) */
index 8386e4a15938ea84922a73876bf0faca2bdd38f3..397d6bf50e099e9da06cf173437de2c432bb7981 100644 (file)
@@ -68,6 +68,8 @@ extern atomic_t __sparc64_bh_counter;
 
 #include <asm/spinlock.h>
 
+extern spinlock_t global_bh_lock;
+
 #define init_bh(nr, routine)                           \
 do {   unsigned long flags;                            \
        int ent = nr;                                   \
@@ -115,13 +117,13 @@ do {      unsigned long flags;                            \
 #define softirq_trylock()                                      \
 ({                                                             \
        int ret = 1;                                            \
-       if(atomic_add_return(1, &__sparc_bh_counter) != 1) {    \
-               atomic_dec(&__sparc_bh_counter);                \
+       if(atomic_add_return(1, &__sparc64_bh_counter) != 1) {  \
+               atomic_dec(&__sparc64_bh_counter);              \
                ret = 0;                                        \
        }                                                       \
        ret;                                                    \
 })
-#define softirq_endlock()      atomic_dec(&__sparc_bh_counter)
+#define softirq_endlock()      atomic_dec(&__sparc64_bh_counter)
 #define clear_active_bhs(mask)                         \
 do {   unsigned long flags;                            \
        spin_lock_irqsave(&global_bh_lock, flags);      \
index cefd4330945dcd44204e17a15640ec2d7c244e01..cf2e51c710bb9ee646fc585820519565c3b924cc 100644 (file)
@@ -56,6 +56,14 @@ typedef struct { } rwlock_t;
 /* All of these locking primitives are expected to work properly
  * even in an RMO memory model, which currently is what the kernel
  * runs in.
+ *
+ * There is another issue.  Because we play games to save cycles
+ * in the non-contention case, we need to be extra careful about
+ * branch targets into the "spinning" code.  They live in their
+ * own section, but the newer V9 branches have a shorter range
+ * than the traditional 32-bit sparc branch variants.  The rule
+ * is that the branches that go into and out of the spinner sections
+ * must be pre-V9 branches.
  */
 
 typedef unsigned char spinlock_t;
@@ -67,13 +75,15 @@ extern __inline__ void spin_lock(spinlock_t *lock)
 {
        __asm__ __volatile__("
 1:     ldstub          [%0], %%g2
-       brnz,a,pn       %%g2, 2f
-        ldub           [%0], %%g2
-       membar          #LoadLoad | #LoadStore
+       brz,pt          %%g2, 2f
+        membar         #LoadLoad | #LoadStore
+       b,a             %%xcc, 3f
+2:
        .text           2
-2:     brnz,a,pt       2b
+3:     ldub            [%0], %%g2
+4:     brnz,a,pt       %%g2, 4b
         ldub           [%0], %%g2
-       b,a,pt          %%xcc, 1b
+       b,a             1b
        .previous
 "      : /* no outputs */
        : "r" (lock)
@@ -104,14 +114,16 @@ extern __inline__ void spin_lock_irq(spinlock_t *lock)
 {
        __asm__ __volatile__("
        wrpr            %%g0, 15, %%pil
-       ldstub          [%0], %%g2
-       brnz,a,pn       %%g2, 2f
-        ldub           [%0], %%g2
-       membar          #LoadLoad | #LoadStore
+1:     ldstub          [%0], %%g2
+       brz,pt          %%g2, 2f
+        membar         #LoadLoad | #LoadStore
+       b,a             3f
+2:
        .text           2
-2:     brnz,a,pt       2b
+3:     ldub            [%0], %%g2
+4:     brnz,a,pt       %%g2, 4b
         ldub           [%0], %%g2
-       b,a,pt          %%xcc, 1b
+       b,a             1b
        .previous
 "      : /* no outputs */
        : "r" (lock)
@@ -133,18 +145,20 @@ extern __inline__ void spin_unlock_irq(spinlock_t *lock)
 do {   register spinlock_t *lp asm("g1");                      \
        lp = lock;                                              \
        __asm__ __volatile__(                                   \
-       "       rdpr            %%pil, %0\n\t"                  \
-       "       wrpr            %%g0, 15, %%pil\n\t"            \
-       "1:     ldstub          [%1], %%g2\n\t"                 \
-       "       brnz,a,pnt      %%g2, 2f\n\t"                   \
-       "        ldub           [%1], %%g2\n\t"                 \
-       "       membar          #LoadLoad | #LoadStore\n\t"     \
-       "       .text           2\n\t"                          \
-       "2:     brnz,a,pt       %%g2, 2b\n\t"                   \
-       "        ldub           [%1], %%g2\n\t"                 \
-       "       b,a,pt          %%xcc, 1b\n\t"                  \
+       "\n     rdpr            %%pil, %0\n"                    \
+       "       wrpr            %%g0, 15, %%pil\n"              \
+       "1:     ldstub          [%1], %%g2\n"                   \
+       "       brz,pt          %%g2, 2f\n"                     \
+       "        membar         #LoadLoad | #LoadStore\n"       \
+       "       b,a             3f\n"                           \
+       "2:\n"                                                  \
+       "       .text           2\n"                            \
+       "3:     ldub            [%1], %%g2\n"                   \
+       "4:     brnz,a,pt       %%g2, 4b\n"                     \
+       "        ldub           [%1], %%g2\n"                   \
+       "       b,a             1b\n"                           \
        "       .previous\n"                                    \
-       : "=r" (flags)                                          \
+       : "=&r" (flags)                                         \
        : "r" (lp)                                              \
        : "g2", "memory");                                      \
 } while(0)
@@ -169,19 +183,20 @@ extern __inline__ void read_lock(rwlock_t *rw)
 {
        __asm__ __volatile__("
        ldx             [%0], %%g2
-1:
-       brlz,pn         %%g2, 2f
-4:      add            %%g2, 1, %%g3
-       casx            [%0], %%g2, %%g3
+1:     brgez,pt        %%g2, 4f
+        add            %%g2, 1, %%g3
+       b,a             2f
+4:     casx            [%0], %%g2, %%g3
        cmp             %%g2, %%g3
        bne,a,pn        %%xcc, 1b
-        ldx            [%0],%%g2
+        ldx            [%0], %%g2
        membar          #LoadLoad | #LoadStore
        .text           2
 2:     ldx             [%0], %%g2
-3:     brlz,pt         %%g2, 3b
+3:     brlz,a,pt       %%g2, 3b
         ldx            [%0], %%g2
-       b,a,pt          %%xcc, 4b
+       b               4b
+        add            %%g2, 1, %%g3
        .previous
 "      : /* no outputs */
        : "r" (rw)
@@ -193,8 +208,7 @@ extern __inline__ void read_unlock(rwlock_t *rw)
        __asm__ __volatile__("
        membar          #StoreStore | #LoadStore
        ldx             [%0], %%g2
-1:
-       sub             %%g2, 1, %%g3
+1:     sub             %%g2, 1, %%g3
        casx            [%0], %%g2, %%g3
        cmp             %%g2, %%g3
        bne,a,pn        %%xcc, 1b
@@ -208,31 +222,34 @@ extern __inline__ void write_lock(rwlock_t *rw)
 {
        __asm__ __volatile__("
        sethi           %%uhi(0x8000000000000000), %%g5
-       ldx             [%0] %%g2
+       ldx             [%0], %%g2
        sllx            %%g5, 32, %%g5
-1:
-       brlz,pn         %%g2, 5f
-4:      or             %%g2, %%g5, %%g3
-       casx            [%0], %%g2, %%g3
+1:     brgez,pt        %%g2, 4f
+        or             %%g2, %%g5, %%g3
+       b,a             5f
+4:     casx            [%0], %%g2, %%g3
        cmp             %%g2, %%g3
        bne,a,pn        %%xcc, 1b
         ldx            [%0], %%g2
        andncc          %%g3, %%g5, %%g0
-       bne,a,pn        %%xcc, 3f
-        ldx            [%0], %%g2
-       membar          #LoadLoad | #LoadStore
+       be,pt           %%xcc, 2f
+        membar         #LoadLoad | #LoadStore
+       b,a             7f
+2:
        .text           2
-3:
-       andn            %%g2, %%g5, %%g3
+7:     ldx             [%0], %%g2
+3:     andn            %%g2, %%g5, %%g3
        casx            [%0], %%g2, %%g3
        cmp             %%g2, %%g3
        bne,a,pn        %%xcc, 3b
         ldx            [%0], %%g2
        membar          #LoadLoad | #LoadStore
 5:     ldx             [%0], %%g2
-6:     brlz,pt         %%g2, 6b
+6:     brlz,a,pt       %%g2, 6b
         ldx            [%0], %%g2
-       b,a,pt          %%xcc, 4b
+       b               4b
+        or             %%g2, %%g5, %%g3
+       .previous
 "      : /* no outputs */
        : "r" (rw)
        : "g2", "g3", "g5", "memory", "cc");
@@ -245,8 +262,7 @@ extern __inline__ void write_unlock(rwlock_t *rw)
        sethi           %%uhi(0x8000000000000000), %%g5
        ldx             [%0], %%g2
        sllx            %%g5, 32, %%g5
-1:
-       andn            %%g2, %%g5, %%g3
+1:     andn            %%g2, %%g5, %%g3
        casx            [%0], %%g2, %%g3
        cmp             %%g2, %%g3
        bne,a,pn        %%xcc, 1b
index 6e7c42e55e346ba20cb25e81ae9a2731d7d1f436..ab05190e9ae676ed64e269760eb0c3c101e19a00 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.26 1997/06/28 10:04:03 davem Exp $ */
+/* $Id: system.h,v 1.29 1997/07/24 16:48:32 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -74,7 +74,27 @@ extern unsigned long empty_zero_page;
 #define restore_flags(x) __restore_flags(x)
 #define save_and_cli(x) __save_and_cli(x)
 #else
-#error SMP not supported on sparc64
+
+#ifndef __ASSEMBLY__
+extern unsigned char global_irq_holder;
+#endif
+
+#define save_flags(x) \
+do {   ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
+               ((getipl() != 0) ? 2 : 0))); } while(0)
+
+#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
+
+#ifndef __ASSEMBLY__
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern void __global_restore_flags(unsigned long flags);
+#endif
+
+#define cli()                  __global_cli()
+#define sti()                  __global_sti()
+#define restore_flags(flags)   __global_restore_flags(flags)
+
 #endif
 
 #define mb()           __asm__ __volatile__ ("stbar" : : : "memory")
@@ -112,48 +132,48 @@ extern __inline__ void flushw_user(void)
         * when modifying this code inspect output of sched.s very
         * carefully to make sure things still work.  -DaveM
         */
-#define switch_to(prev, next)                                                          \
-do {                                                                                   \
-       __label__ switch_continue;                                                      \
-       register unsigned long task_pc asm("o7");                                       \
-       (prev)->tss.kregs->fprs = 0;                                                    \
-       task_pc = ((unsigned long) &&switch_continue) - 0x8;                            \
-       __asm__ __volatile__(                                                           \
-       "rdpr   %%pstate, %%g2\n\t"                                                     \
-       "wrpr   %%g2, 0x3, %%pstate\n\t"                                                \
-       "flushw\n\t"                                                                    \
-/*XXX*/        "wr     %%g0, 0, %%fprs\n\t"                                                    \
-       "stx    %%i6, [%%sp + 2047 + 0x70]\n\t"                                         \
-       "stx    %%i7, [%%sp + 2047 + 0x78]\n\t"                                         \
-       "rdpr   %%wstate, %%o5\n\t"                                                     \
-       "stx    %%o6, [%%g6 + %3]\n\t"                                                  \
-       "stx    %%o5, [%%g6 + %2]\n\t"                                                  \
-       "rdpr   %%cwp, %%o5\n\t"                                                        \
-       "stx    %%o7, [%%g6 + %4]\n\t"                                                  \
-       "st     %%o5, [%%g6 + %5]\n\t"                                                  \
-       "mov    %0, %%g6\n\t"                                                           \
-       "ld     [%0 + %5], %%g1\n\t"                                                    \
-       "wrpr   %%g1, %%cwp\n\t"                                                        \
-       "ldx    [%%g6 + %2], %%o5\n\t"                                                  \
-       "ldx    [%%g6 + %3], %%o6\n\t"                                                  \
-       "ldx    [%%g6 + %4], %%o7\n\t"                                                  \
-       "mov    %%g6, %0\n\t"                                                           \
-       "wrpr   %%o5, 0x0, %%wstate\n\t"                                                \
-       "ldx    [%%sp + 2047 + 0x70], %%i6\n\t"                                         \
-       "ldx    [%%sp + 2047 + 0x78], %%i7\n\t"                                         \
-       "wrpr   %%g0, 0x96, %%pstate\n\t"                                               \
-       "jmpl   %%o7 + 0x8, %%g0\n\t"                                                   \
-       " mov   %0, %%g6\n\t"                                                           \
-       : /* No outputs */                                                              \
-       : "r" (next), "r" (task_pc),                                                    \
-         "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),          \
-         "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),             \
-         "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)),             \
-         "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp))              \
-       : "cc", "g1", "g2", "g3", "g5", "g7",                                           \
-         "l1", "l2", "l3", "l4", "l5", "l6", "l7",                                     \
-         "i0", "i1", "i2", "i3", "i4", "i5",                                           \
-         "o0", "o1", "o2", "o3", "o4", "o5");                                          \
+#define switch_to(prev, next)                                                  \
+do {   __label__ switch_continue;                                              \
+       register unsigned long task_pc asm("o7");                               \
+       (prev)->tss.kregs->fprs = 0;                                            \
+       task_pc = ((unsigned long) &&switch_continue) - 0x8;                    \
+       (next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());                 \
+       __asm__ __volatile__(                                                   \
+       "rdpr   %%pstate, %%g2\n\t"                                             \
+       "wrpr   %%g2, 0x3, %%pstate\n\t"                                        \
+       "flushw\n\t"                                                            \
+/*XXX*/        "wr     %%g0, 0, %%fprs\n\t"                                            \
+       "stx    %%i6, [%%sp + 2047 + 0x70]\n\t"                                 \
+       "stx    %%i7, [%%sp + 2047 + 0x78]\n\t"                                 \
+       "rdpr   %%wstate, %%o5\n\t"                                             \
+       "stx    %%o6, [%%g6 + %3]\n\t"                                          \
+       "stx    %%o5, [%%g6 + %2]\n\t"                                          \
+       "rdpr   %%cwp, %%o5\n\t"                                                \
+       "stx    %%o7, [%%g6 + %4]\n\t"                                          \
+       "st     %%o5, [%%g6 + %5]\n\t"                                          \
+       "mov    %0, %%g6\n\t"                                                   \
+       "ld     [%0 + %5], %%g1\n\t"                                            \
+       "wrpr   %%g1, %%cwp\n\t"                                                \
+       "ldx    [%%g6 + %2], %%o5\n\t"                                          \
+       "ldx    [%%g6 + %3], %%o6\n\t"                                          \
+       "ldx    [%%g6 + %4], %%o7\n\t"                                          \
+       "mov    %%g6, %0\n\t"                                                   \
+       "wrpr   %%o5, 0x0, %%wstate\n\t"                                        \
+       "ldx    [%%sp + 2047 + 0x70], %%i6\n\t"                                 \
+       "ldx    [%%sp + 2047 + 0x78], %%i7\n\t"                                 \
+       "wrpr   %%g0, 0x96, %%pstate\n\t"                                       \
+       "jmpl   %%o7 + 0x8, %%g0\n\t"                                           \
+       " mov   %0, %%g6\n\t"                                                   \
+       : /* No outputs */                                                      \
+       : "r" (next), "r" (task_pc),                                            \
+         "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),  \
+         "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),     \
+         "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)),     \
+         "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp))      \
+       : "cc", "g1", "g2", "g3", "g5", "g7",                                   \
+         "l1", "l2", "l3", "l4", "l5", "l6", "l7",                             \
+         "i0", "i1", "i2", "i3", "i4", "i5",                                   \
+         "o0", "o1", "o2", "o3", "o4", "o5");                                  \
 switch_continue: } while(0)
 
 /* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */
diff --git a/include/asm-sparc64/timer.h b/include/asm-sparc64/timer.h
new file mode 100644 (file)
index 0000000..860ae6d
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id: timer.h,v 1.1 1997/07/23 10:38:00 davem Exp $
+ * timer.h: System timer definitions for sun5.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_TIMER_H
+#define _SPARC64_TIMER_H
+
+/* How timers work:
+ *
+ * On uniprocessors we just use counter zero for the system wide
+ * ticker, this performs thread scheduling, clock book keeping,
+ * and runs timer based events.  Previously we used the Ultra
+ * %tick interrupt for this purpose.
+ *
+ * On multiprocessors we pick one cpu as the master level 10 tick
+ * processor.  Here this counter zero tick handles clock book
+ * keeping and timer events only.  Each Ultra has it's level
+ * 14 %tick interrupt set to fire off as well, even the master
+ * tick cpu runs this locally.  This ticker performs thread
+ * scheduling, system/user tick counting for the current thread,
+ * and also profiling if enabled.
+ */
+
+/* Two timers, traditionally steered to PIL's 10 and 14 respectively.
+ * But since INO packets are used on sun5, we could use any PIL level
+ * we like, however for now we use the normal ones.
+ *
+ * The 'reg' and 'interrupts' properties for these live in nodes named
+ * 'counter-timer'.  The first of three 'reg' properties describe where
+ * the sun5_timer registers are.  The other two I have no idea. (XXX)
+ */
+struct sun5_timer {
+       u64     count0;
+       u64     limit0;
+       u64     count1;
+       u64     limit1;
+};
+
+#define SUN5_LIMIT_ENABLE      0x80000000
+#define SUN5_LIMIT_TOZERO      0x40000000
+#define SUN5_LIMIT_ZRESTART    0x20000000
+#define SUN5_LIMIT_CMASK       0x1fffffff
+
+/* Given a HZ value, set the limit register to so that the timer IRQ
+ * gets delivered that often.
+ */
+#define SUN5_HZ_TO_LIMIT(__hz)  (1000000/(__hz))
+
+#endif /* _SPARC64_TIMER_H */
index ea7a995ac5b3db8b0d9dd5dceee5de489dd1530c..82390ea6449e917dfba29179de4b4a775305c35a 100644 (file)
@@ -53,6 +53,9 @@ struct dentry {
        int (*d_revalidate)(struct dentry *);
 };
 
+/* d_flags entries */
+#define DCACHE_AUTOFS_PENDING 0x0001    /* autofs: "under construction" */
+
 /*
  * d_drop() unhashes the entry from the parent
  * dentry hashes, so that it won't be found through
index 4ccb6d569dff03a3dbed96bdd1835fa262bfea78..665b56c38ae3eab12ca2f0b9e551d6289e931ab7 100644 (file)
@@ -672,7 +672,7 @@ extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag)
 }
 
 extern int check_disk_change(kdev_t dev);
-extern void invalidate_inodes(kdev_t dev);
+extern int invalidate_inodes(kdev_t dev);
 extern void invalidate_inode_pages(struct inode *);
 extern void invalidate_buffers(kdev_t dev);
 extern int floppy_is_wp(int minor);
index c4e9f0aa86e351e498a188dd57b5ff6443d995b8..2100669c087312ac3902d2a08a905fc90dedb935 100644 (file)
@@ -11,6 +11,7 @@
 #define PC110PAD_MINOR 9
 #define RTC_MINOR 135
 #define SUN_OPENPROM_MINOR 139
+#define NVRAM_MINOR 144
 #define MISC_DYNAMIC_MINOR 255
 
 extern int misc_init(void);
index bfde668c71cafff1184c56bfa98b7f8d16656f92..d02a86fefc84f0b54dd72ed44f18804b8477eafc 100644 (file)
@@ -118,9 +118,8 @@ typedef struct page {
        unsigned long offset;
        struct page *next_hash;
        atomic_t count;
+       unsigned int age;
        unsigned long flags;    /* atomic flags, some possibly updated asynchronously */
-       unsigned dirty:16,
-                age:8;
        struct wait_queue *wait;
        struct page **pprev_hash;
        struct buffer_head * buffers;
index fb17117a0dd936edd62041da8574f82c586a5505..a3ea8815edec2c857ec9a6a92bd6e7c38641bf92 100644 (file)
 
 #define MSDOS_FAT12 4078 /* maximum number of clusters in a 12 bit FAT */
 
-#ifdef CONFIG_ATARI
-#define EOF_FAT12 0xFFF                /* Atari GEMDOS fs uses a different EOF */
-#define EOF_FAT16 0xFFFF
-#else
 #define EOF_FAT12 0xFF8                /* standard EOF */
 #define EOF_FAT16 0xFFF8
-#endif
+#define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 16 ? 0xFFF8 : 0xFF8)
 
 /*
  * Inode flags
index bf5ea6345c5545591615306c7fd71d651f164064..4cc224838d45dd514d700f70db336ca227053fe7 100644 (file)
@@ -18,7 +18,8 @@ struct fat_mount_options {
                 isvfat:1,        /* 0=no vfat long filename support, 1=vfat support */
                 unicode_xlate:1, /* create escape sequences for unhandled Unicode */
                 posixfs:1,       /* Allow names like makefile and Makefile to coexist */
-                numtail:1;       /* Does first alias have a numeric '~1' type tail? */
+                numtail:1,       /* Does first alias have a numeric '~1' type tail? */
+                atari:1;         /* Use Atari GEMDOS variation of MS-DOS fs */
 };
 
 
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
new file mode 100644 (file)
index 0000000..9e05db1
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _LINUX_NVRAM_H
+#define _LINUX_NVRAM_H
+
+#include <linux/ioctl.h>
+
+/* /dev/nvram ioctls */
+#define NVRAM_INIT             _IO('p', 0x40) /* initialize NVRAM and set checksum */
+#define        NVRAM_SETCKS    _IO('p', 0x41) /* recalculate checksum */
+
+#ifdef __KERNEL__
+extern unsigned char nvram_read_byte( int i );
+extern void nvram_write_byte( unsigned char c, int i );
+extern int nvram_check_checksum( void );
+extern void nvram_set_checksum( void );
+extern int nvram_init( void );
+#endif
+
+#endif  /* _LINUX_NVRAM_H */
index 1acb56c8c44e7a09fc371a948e82171a545344c6..ad6893bd2765e7bda344701d535f1bf4c2ade2a4 100644 (file)
@@ -335,7 +335,7 @@ struct openpromfs_dev {
 };
 extern struct inode_operations *
 proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
-                      int (*lookup)(struct inode *, struct qstr *, struct inode **),
+                      int (*lookup)(struct inode *, struct dentry *),
                       void (*use)(struct inode *, int),
                       struct openpromfs_dev ***);
 extern void proc_openprom_deregister(void);
index 3779429b45c849a034085e1e52ad3ee672ca1c32..adb896b6c81a67bd2b1d47341b13e1437d634235 100644 (file)
@@ -23,11 +23,11 @@ extern unsigned long get_video_size_row(unsigned int console);
 #define get_video_num_columns(dummy) video_num_columns
 #define get_video_num_lines(dummy) video_num_lines
 #define get_video_size_row(dummy) video_size_row
+#endif
+
 extern unsigned long video_num_columns;
 extern unsigned long video_num_lines;
 extern unsigned long video_size_row;
-#endif
-
 extern unsigned char video_type;
 extern unsigned long video_mem_base;
 extern unsigned long video_mem_term;
@@ -73,8 +73,6 @@ extern void putconsxy(int currcons, char *p);
 
 /* how to access screen memory */
 
-#include <linux/config.h>
-
 #if defined(CONFIG_TGA_CONSOLE)
 
 extern int tga_blitc(unsigned int, unsigned long);
@@ -171,17 +169,25 @@ static inline unsigned char scr_readb(unsigned char * addr)
 
 static inline void scr_writew(unsigned short val, unsigned short * addr)
 {
+#ifdef __powerpc__
+       st_le16(addr, val);
+#else
        if ((long) addr < 0)
                *addr = val;
        else
                writew(val, (unsigned long) addr);
+#endif /* !__powerpc__ */
 }
 
 static inline unsigned short scr_readw(unsigned short * addr)
 {
+#ifdef __powerpc__
+       return ld_le16(addr);
+#else
        if ((long) addr < 0)
                return *addr;
        return readw((unsigned long) addr);
+#endif /* !__powerpc__ */      
 }
 
 #endif /* CONFIG_TGA_CONSOLE */
index 8cfd21b0ec3c6637a7cd41b35f96011e89d26399..e630aba706f5806faaba20746abccdc5a430477d 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  *
- *     $Id: sysrq.h,v 1.2 1997/05/31 18:33:41 mj Exp $
+ *     $Id: sysrq.h,v 1.3 1997/07/17 11:54:33 mj Exp $
  *
  *     Linux Magic System Request Key Hacks
  *
@@ -9,12 +9,25 @@
 
 #include <linux/config.h>
 
+struct pt_regs;
+struct kbd_struct;
+struct tty_struct;
+
+/* Generic SysRq interface -- you may call it from any device driver, supplying
+ * ASCII code of the key, pointer to registers and kbd/tty structs (if they
+ * are available -- else NULL's).
+ */
+
+void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
+
+/* Deferred actions */
+
 extern int emergency_sync_scheduled;
 
 #define EMERG_SYNC 1
 #define EMERG_REMOUNT 2
 
-extern void do_emergency_sync(void);
+void do_emergency_sync(void);
 
 #ifdef CONFIG_MAGIC_SYSRQ
 #define CHECK_EMERGENCY_SYNC                   \
index 8f813c655bd693343b209bfdafbc859ecfffc456..b63f5469c1ac676d4bdfada39ea1498dbe7afe41 100644 (file)
@@ -131,6 +131,9 @@ static char * number(char * str, long num, int base, int size, int precision
        return str;
 }
 
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char * buf, const char *fmt, ...);
+
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
        int len;
@@ -250,6 +253,41 @@ int vsprintf(char *buf, const char *fmt, va_list args)
                        }
                        continue;
 
+               case 'I': /* IPv4 / IPv6 printout */
+                       {
+                         __u8 *ip4;
+                         char sbuf[6];
+                         if (qualifier == 'l') {
+                           __u16 *ip6 = va_arg(args, __u16 *);
+                           i = 6;
+                           for ( ; i > 0; --i, ++ip6)
+                             if (*ip6 != 0)
+                               break;
+                           if (i < 6)
+                             *str++ = ':';
+                           for ( ; i > 0; --i, ++ip6) {
+                             sprintf(sbuf,":%04x",(int)(*ip6));
+                             s = sbuf;
+                             while (*s)
+                               *str++ = *s++;
+                           }
+                           *str++ = ':';
+                           ip4 = (__u8*) ip6;
+                         } else {
+                           ip4 = va_arg(args, __u8 *);
+                         }
+                         for (i = 0; i < 4; ++i, ++ip4) {
+                           if (i == 3)
+                             sprintf(sbuf,"%d", 0xFF & (*ip4));
+                           else
+                             sprintf(sbuf,"%d.", 0xFF & (*ip4));
+                           s = sbuf;
+                           while (*s)
+                             *str++ = *s++;
+                         }
+                       }
+                       continue;
+
                /* integer number formats - set up the flags and "break" */
                case 'o':
                        base = 8;
index 1a43e682daae13d9304563aefdec6245fa66fa38..332cc6447b02a9746f09e320e11c4effff4ea8df 100644 (file)
@@ -64,7 +64,6 @@ void invalidate_inode_pages(struct inode * inode)
                inode->i_nrpages--;
                if ((*p = page->next) != NULL)
                        (*p)->prev = page->prev;
-               page->dirty = 0;
                page->next = NULL;
                page->prev = NULL;
                remove_page_from_hash_queue(page);
@@ -97,7 +96,6 @@ repeat:
                        inode->i_nrpages--;
                        if ((*p = page->next) != NULL)
                                (*p)->prev = page->prev;
-                       page->dirty = 0;
                        page->next = NULL;
                        page->prev = NULL;
                        remove_page_from_hash_queue(page);
index 7959d6a0e6483851abd78109be63744061335d0f..6ad6bc73cf1b4b7ff4cb25da07f2ad2d2877f62c 100644 (file)
--- a/mm/simp.c
+++ b/mm/simp.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/simp.h>
+#include <linux/tasks.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
 #include <asm/spinlock.h>
@@ -207,7 +208,6 @@ static void alloc_header(struct simp * simp)
        simp->usable_list = hdr;
 }
 
-
 /* current x86 memcpy() is horribly moving around registers for nothing,
  * is doing unnecessary work if the size is dividable by a power-of-two,
  * and it clobbers way too many registers.
index 30898803afa846590776b14e85dfd2902fe5b3e3..b6e1d5ea31e176b9f725282a6ca9fcdc10bfed22 100644 (file)
@@ -413,18 +413,20 @@ the frame following the ack. (The assumption being that the acks are
 because a single frame in the data stream has been lost). Given a 
 mathematician with some queue theory you can show this allows you to 
 lose one frame per window full of data without measurable speed loss.
+[done]
 
 4.     RFC1323. These are the extensions for very fast nets.
 RFC1323 will be useful for Linux talking to systems over 100Mb/sec
 ethernet and over ATM as it allows large windows and protects from some
 potential high speed TCP problems.
+[In progress]
 
 6.     Delayed ack. This is mostly supported but not actually set up and
 used yet. Basically ack frames are held back 1/10th of a second in the hope
 that two acks can be merged into one or for interactive use the ack can
 piggyback on the next character typed (great improvement on 2400 baud
 modems). Johannes Stille did some work on this about 0.99.13 but it never
-got merged in. [Pedro Roque]
+got merged in. [Pedro Roque] [Done, but needs fixing]
 
 7.     One on my tempting project list. Add an extra (unofficial - but so
 is SLIP6) SLIP mode that does packet data compression [maybe use the code
@@ -439,7 +441,7 @@ driver but that's for an internal project and its general release is still
 a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is
 Mike McLagan][Fritz Elfert is doing the isdn4linux kit].
  
-11.    IP over SCSI.
+11.    IP over SCSI. [worked on]
 
 14.    Bidirectional PLIP. Also PLIP for the newer style parallel ports.
 
index d26f008dddb7b288193a5a300f2966a6886aa082..3a8594fba94bdc35317c5dfa783ab24894df1bc7 100644 (file)
@@ -165,6 +165,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
        bp[14] |= AX25_EBIT;
        bp[14] |= AX25_SSSID_SPARE;
 
+       skb_pull(skb, AX25_KISS_HEADER_LEN);
+
        if (route->digipeat != NULL) {
                if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
                        kfree_skb(skb, FREE_WRITE);
index 2c7d082a94be6d63176bd2974a01506f972f8e97..911b548343b1266a10d62781d2e679dc47b313fc 100644 (file)
@@ -410,8 +410,6 @@ struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_
        unsigned char *bp;
        int len;
 
-       skb_pull(skb, 1);       /* skip KISS command */
-
        len = digi->ndigi * AX25_ADDR_LEN;
 
        if (skb_headroom(skb) < len) {
index 2b593cbb145cdff56a64e058b2f936934ec94a39..93db2e22009425ea2a69b989bd15aaa05343737d 100644 (file)
@@ -1082,8 +1082,9 @@ int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy
        struct device *dev;
 
 
-       size = sprintf(buffer, "Inter-|   Receive                  |  Transmit\n"
-                           " face |bytes    packets errs drop fifo frame|bytes    packets errs drop fifo colls carrier\n");
+       size = sprintf(buffer, 
+               "Inter-|   Receive                           |  Transmit\n"
+               " face |bytes    packets errs drop fifo frame|bytes    packets errs drop fifo colls carrier\n");
        
        pos+=size;
        len+=size;
index e3b41e2ad54d180b93bf25f9e78bd70f3a68e40c..1184c9f41d7dc6b108ee52f666a5f3286cb9cd7a 100644 (file)
@@ -77,7 +77,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
  *     This was very pretty but didn't work when a socket is destroyed
  *     at the wrong moment (eg a syn recv socket getting a reset), or
  *     a memory timer destroy. Instead of playing with timers we just
- *     concede defeat and cli().
+ *     concede defeat and do a start_bh_atomic().
  */
        SOCKHASH_LOCK();
        sp = pro->sklist_next;
index b43a972ccaa9a6d406d56ff9586c0ae319f093d9..bf0044b5e49ce34128b782fb27a30883b2c2e5f3 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.66 1997/05/31 12:36:39 freitag Exp $
+ * Version:    $Id: tcp.c,v 1.67 1997/07/20 12:46:07 freitag Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Eric Schenk     :       Fix fast close down bug with
  *                                     shutdown() followed by close().
  *                                     
- * To Fix:
- *             Fast path the code. Two things here - fix the window calculation
- *             so it doesn't iterate over the queue, also spot packets with no funny
- *             options arriving in order and process directly.
- *
- *             Rewrite output state machine to use a single queue.
- *             Speed up input assembly algorithm.
- *             RFC1323 - PAWS and window scaling.[Required for IPv6]
- *             User settable/learned rtt/max window/mtu
- *
- *             Change the fundamental structure to a single send queue maintained
- *             by TCP (removing the bogus ip stuff [thus fixing mtu drops on
- *             active routes too]). Cut the queue off in tcp_retransmit/
- *             tcp_transmit.
- *             Change the receive queue to assemble as it goes. This lets us
- *             dispose of most of tcp_sequence, half of tcp_ack and chunks of
- *             tcp_data/tcp_read as well as the window shrink crud.
- *             Separate out duplicated code - tcp_alloc_skb, tcp_build_ack
- *             tcp_queue_skb seem obvious routines to extract.
- *
  *             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
  * for violations and the like.  tcp.c is just too big... If I say something
  * "does?" or "doesn't?", it means I'm not sure, and will have to hash it out
  * with Alan. -- MS 950903
+ * [Note: Most of the TCP code has been rewriten/redesigned since this 
+ *  RFC1122 check. It is probably not correct anymore. It should be redone 
+ *  before 2.2. -AK]
  *
  * Use of PSH (4.2.2.2)
  *   MAY aggregate data sent without the PSH flag. (does)
index d3b0c26c9403b1e4d86888905a3a869896e42e44..1ad720fbbd2c078e0ab05ef65de0a9871f8db778 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.51 1997/07/04 23:35:02 freitag Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.52 1997/07/23 15:19:10 freitag Exp $
  *
  *             IPv4 specific functions
  *
@@ -1205,7 +1205,7 @@ static inline struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb
 
                        /* Check for syn retransmission */
                        flg = *(((u32 *)skb->h.th) + 3);
-                       flg &= __constant_htonl(0x002f0000);
+                       flg &= __constant_htonl(0x001f0000);
                        if ((flg == __constant_htonl(0x00020000)) &&
                            (!after(skb->seq, req->rcv_isn))) {
                                /*      retransmited syn
index b8e6ac4a59466129fb7721d02db80c8d827f992d..ba583645807fb666acdd78d68b95fc403eb577e1 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: route.c,v 1.12 1997/04/29 09:38:50 mj Exp $
+ *     $Id: route.c,v 1.13 1997/07/19 11:11:35 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1427,8 +1427,8 @@ static void rt6_info_node(struct fib6_node *fn, void *p_arg)
                }
                arg->len += sprintf(arg->buffer + arg->len,
                                    " %08lx %08x %08x %08lx %8s\n",
-                                   rt->rt6i_metric, rt->rt6i_use,
-                                   rt->rt6i_ref, rt->rt6i_flags, 
+                                   rt->rt6i_metric, atomic_read(&rt->rt6i_use),
+                                   atomic_read(&rt->rt6i_ref), rt->rt6i_flags, 
                                    rt->rt6i_dev ? rt->rt6i_dev->name : "");
        }
 }
index c2937426459fa2bcb50cee7a9364ad78a4b6a817..9a5e2dfc7af013e64c3cb501dde5901542d7bb2c 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.33 1997/06/06 20:38:10 freitag Exp $
+ *     $Id: tcp_ipv6.c,v 1.35 1997/07/23 15:18:04 freitag Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
@@ -699,7 +699,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
 {
        struct tcp_opt tp;
        struct open_request *req;
-       __u16 req_mss;
        
        /* If the socket is dead, don't accept the connection.  */
        if (sk->dead) {
@@ -1048,7 +1047,7 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
 
                        /* Check for syn retransmission */
                        flg = *(((u32 *)skb->h.th) + 3);
-                       flg &= __constant_htonl(0x002f0000);
+                       flg &= __constant_htonl(0x001f0000);
 
                        if ((flg == __constant_htonl(0x00020000)) &&
                            (!after(skb->seq, req->rcv_isn))) {