Import 2.1.127pre32.1.127pre3
authorLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:06 +0000 (23 15:17 -0500)
committerLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:06 +0000 (23 15:17 -0500)
148 files changed:
Documentation/Configure.help
MAINTAINERS
arch/alpha/kernel/sys_sio.c
arch/i386/kernel/entry.S
arch/i386/mm/fault.c
arch/sparc/boot/Makefile
arch/sparc/defconfig
arch/sparc/kernel/devices.c
arch/sparc/kernel/ebus.c
arch/sparc/kernel/init_task.c
arch/sparc/kernel/irq.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/signal.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sunos_ioctl.c
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/lib/bitops.S
arch/sparc/lib/debuglocks.c
arch/sparc/lib/locks.S
arch/sparc64/Makefile
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/head.S
arch/sparc64/kernel/ioctl32.c
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/psycho.c
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/rtrap.S
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sys_sparc.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/sys_sunos32.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/trampoline.S
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/unaligned.c
arch/sparc64/lib/Makefile
arch/sparc64/lib/VIScopy.S
arch/sparc64/lib/VISsave.S
arch/sparc64/lib/blockops.S
arch/sparc64/lib/debuglocks.c[new file with mode: 0644]
arch/sparc64/lib/locks.S[deleted file]
arch/sparc64/lib/strlen.S
arch/sparc64/math-emu/Makefile
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
arch/sparc64/prom/misc.c
arch/sparc64/prom/p1275.c
arch/sparc64/solaris/Makefile
drivers/char/Makefile
drivers/char/lp.c
drivers/char/mem.c
drivers/char/radio-sf16fmi.c
drivers/net/bmac.c
drivers/sbus/char/pcikbd.c
drivers/sbus/char/sab82532.c
drivers/sbus/char/su.c[moved from drivers/sbus/char/su32.c with 70% similarity]
drivers/sbus/char/sunserial.c
drivers/sbus/char/vfc_dev.c
drivers/sbus/char/zs.c
drivers/sbus/sbus.c
drivers/scsi/Config.in
drivers/scsi/README.tmscsim[new file with mode: 0644]
drivers/scsi/dc390.h
drivers/scsi/scsiiom.c
drivers/scsi/tmscsim.c
drivers/scsi/tmscsim.h
fs/autofs/autofs_i.h
fs/autofs/dir.c
fs/autofs/dirhash.c
fs/autofs/init.c
fs/autofs/inode.c
fs/autofs/root.c
fs/autofs/symlink.c
fs/autofs/waitq.c
fs/binfmt_elf.c
fs/namei.c
fs/nfsd/auth.c
fs/nfsd/export.c
fs/nfsd/nfsfh.c
fs/select.c
include/asm-i386/spinlock.h
include/asm-i386/system.h
include/asm-sparc/asm_offsets.h
include/asm-sparc/dma.h
include/asm-sparc/fcntl.h
include/asm-sparc/hardirq.h
include/asm-sparc/perfctr.h[new file with mode: 0644]
include/asm-sparc/sigcontext.h
include/asm-sparc/softirq.h
include/asm-sparc/spinlock.h
include/asm-sparc/system.h
include/asm-sparc/unistd.h
include/asm-sparc64/asm_offsets.h
include/asm-sparc64/dma.h
include/asm-sparc64/fcntl.h
include/asm-sparc64/floppy.h
include/asm-sparc64/hardirq.h
include/asm-sparc64/ioctl.h
include/asm-sparc64/mmu_context.h
include/asm-sparc64/namei.h
include/asm-sparc64/oplib.h
include/asm-sparc64/page.h
include/asm-sparc64/perfctr.h[new file with mode: 0644]
include/asm-sparc64/pgtable.h
include/asm-sparc64/processor.h
include/asm-sparc64/psrcompat.h
include/asm-sparc64/sab82532.h
include/asm-sparc64/semaphore.h
include/asm-sparc64/sigcontext.h
include/asm-sparc64/smp.h
include/asm-sparc64/smplock.h
include/asm-sparc64/softirq.h
include/asm-sparc64/spinlock.h
include/asm-sparc64/string.h
include/asm-sparc64/system.h
include/asm-sparc64/uaccess.h
include/asm-sparc64/unistd.h
include/linux/if.h
include/linux/kernel.h
include/linux/lp.h
include/linux/sysctl.h
include/net/scm.h
init/main.c
mm/vmscan.c
net/core/scm.c
net/core/sock.c
net/ipv4/arp.c
net/ipv4/icmp.c
net/ipv4/ip_masq_cuseeme.c
net/ipv4/ip_masq_raudio.c
net/ipv4/ip_masq_vdolive.c
net/ipv4/ip_nat_dumb.c
net/ipv4/ipconfig.c
net/ipv4/proc.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_input.c
net/protocols.c

index 043f18a..d546aa9 100644 (file)
@@ -4058,24+4058,46 @@ CONFIG_SCSI_NCR53C406A
   say M here and read Documentation/modules.txt. The module will be
   called NCR53c406.o.
 
-Tekram DC390(T) (AMD PCscsi) SCSI support
+Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support
 CONFIG_SCSI_DC390T
-  This driver supports the Tekram DC390(T) PCI SCSI host adapter with
-  the Am53C974A chip, and perhaps other cards using the same chip.
-  This driver does _not_ support the DC390W/U/F adaptor with the
-  NCR/Symbios chips; use "NCR53C8XX SCSI support" for that one.
+  This driver supports  PCI SCSI host adapters  based on the Am53C974A
+  chip,  e.g.  Tekram DC390(T),  DawiControl 2974  and  some   onboard
+  PCscsi/PCnet (Am53/79C974) solutions.
+  Documentation can be found in linux/drivers/scsi/README.tmscsim.
+  
+  Note that this driver  does NOT support Tekram DC390W/U/F, which are
+  based on NCR/Symbios chips. Use the NCR53C8XX driver for those.
+  Also note, that there is another generic Am53C974 driver.
 
   If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
+  inserted in and removed from the running kernel  whenever you want),
+  say M here  and read Documentation/modules.txt.  The module  will be
   called tmscsim.o.
 
+Skip support for other Am53/79C974 based SCSI adapters
+CONFIG_SCSI_DC390T_NOGENSUPP
+  Normally, the DC390(T) SCSI driver relies on the DC390 EEPROM to get
+  initial values  for its settings,  such as speed,  termination, etc.
+  If  it can't find  this EEPROM, it  will use  defaults  or  the user
+  supplied boot/module parameters. For details on driver configuration
+  see linux/drivers/scsi/README.tmscsim.
+
+  With this option set, if no EEPROM is found, the driver gives up and
+  thus only supports  Tekram DC390(T) adapters.  This can be useful if
+  you have a DC390(T)  and another Am53C974 based adapter,  which, for
+  some reason, you want to drive with the other AM53C974 driver.
+
+  If unsure, say N.
+
 AM53/79C974 PCI SCSI support
 CONFIG_SCSI_AM53C974
   This is support for the AM53/79C974 SCSI host adapters. Please read
   drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
   available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you. 
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you.
+
+  Note that there is another driver for AM53C974 based adapters: The
+  Tekram DC390(T) driver.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
index 15c5242..370d9e1 100644 (file)
@@ -186,6+186,12 @@ W: http://qsl.net/dl1bke/
 L:     linux-hams@vger.rutgers.edu
 S:     Maintained
 
+DC390/AM53C974 SCSI driver
+P:     Kurt Garloff
+M:     K.Garloff@ping.de
+W:     ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+S:     Maintained
+
 DECnet NETWORK LAYER
 P:     Steven Whitehouse
 M:     SteveW@ACM.org
index dfd6ada..b5aaf5d 100644 (file)
@@ -110,6+110,9 @@ alphabook1_init_arch(unsigned long *mem_start, unsigned long *mem_end)
  *
  * This probably ought to be configurable via MILO.  For
  * example, sound boards seem to like using IRQ 9.
+ *
+ * This is NOT how we should do it. PIRQ0-X should have
+ * their own IRQ's, the way intel uses the IO-APIC irq's.
  */
 static unsigned long sio_route_tab __initdata = 0;
 
@@ -238,7+241,7 @@ static inline void __init
 avanti_pci_fixup(void)
 {
        layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE);
-       sio_pci_fixup(noname_map_irq, 0x0b0a090f);
+       sio_pci_fixup(noname_map_irq, 0x0b0a0e0f);
        sio_fixup_irq_levels(sio_collect_irq_levels());
         enable_ide(0x26e);
 }
index 8b26665..aa95a0b 100644 (file)
@@ -107,7+107,7 @@ ENOSYS = 38
 2:     popl %es;       \
        addl $4,%esp;   \
 3:     iret;           \
-.section fixup,"ax";   \
+.section .fixup,"ax";  \
 4:     movl $0,(%esp); \
        jmp 1b;         \
 5:     movl $0,(%esp); \
index a95a732..37bf88e 100644 (file)
@@ -163,7+163,7 @@ good_area:
         * the fault.
         */
        if (!handle_mm_fault(tsk, vma, address, write))
-               goto bad_area;
+               goto do_sigbus;
 
        /*
         * Did it hit the DOS screen memory VA from vm86 mode?
@@ -250,4+250,24 @@ no_context:
        }
        die("Oops", regs, error_code);
        do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+do_sigbus:
+       up(&mm->mmap_sem);
+
+       /*
+        * Send a sigbus, regardless of whether we were in kernel
+        * or user mode.
+        */
+       tsk->tss.cr2 = address;
+       tsk->tss.error_code = error_code;
+       tsk->tss.trap_no = 14;
+       force_sig(SIGBUS, tsk);
+
+       /* Kernel mode? Handle exceptions or die */
+       if (!(error_code & 4))
+               goto no_context;
 }
index 3aec780..b0f7f63 100644 (file)
@@ -1,4+1,4 @@
-# $Id: Makefile,v 1.8 1998/09/16 12:24:51 jj Exp $
+# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $
 # Makefile for the Sparc boot stuff.
 #
 # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6+26,10 @@ BTOBJS := $(HEAD) init/main.o init/version.o \
        $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
        $(NETWORKS) $(DRIVERS)
 
+# I wanted to make this depend upon BTOBJS so that a parallel
+# build would work, but this fails because $(HEAD) cannot work
+# properly as it will cause head.o to be built with the implicit
+# rules not the ones in kernel/Makefile.  Someone please fix. --DaveM
 vmlinux.o: dummy
        $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o
 
index 6c89f74..aa2b6f1 100644 (file)
@@ -21,6+21,7 @@ CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_AP1000 is not set
 # CONFIG_SUN4 is not set
+# CONFIG_PCI is not set
 
 #
 # Console drivers
@@ -67,6+68,7 @@ CONFIG_SUN_MOSTEK_RTC=y
 # CONFIG_SPARCAUDIO is not set
 # CONFIG_SPARCAUDIO_AMD7930 is not set
 # CONFIG_SPARCAUDIO_CS4231 is not set
+# CONFIG_SPARCAUDIO_DBRI is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
@@ -74,7+76,7 @@ CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
+CONFIG_BINFMT_MISC=m
 CONFIG_BINFMT_JAVA=m
 
 #
@@ -82,51+84,32 @@ CONFIG_BINFMT_JAVA=m
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_STRIPED=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
 CONFIG_MD_MIRRORING=m
 CONFIG_MD_RAID5=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_NBD=m
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_FIREWALL=y
-CONFIG_NET_ALIAS=y
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
+# CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
-CONFIG_IP_FIREWALL=y
-# CONFIG_IP_FIREWALL_NETLINK is not set
-# CONFIG_IP_TRANSPARENT_PROXY is not set
-# CONFIG_IP_ALWAYS_DEFRAG is not set
-CONFIG_IP_MASQUERADE=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_ICMP is not set
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_MOD is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_ARPD is not set
+# CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
 
 #
@@ -135,7+118,7 @@ CONFIG_IP_ALIAS=y
 CONFIG_INET_RARP=m
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
-CONFIG_IPV6=y
+CONFIG_IPV6=m
 # CONFIG_IPV6_EUI64 is not set
 
 #
@@ -145,7+128,7 @@ CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
 CONFIG_ATALK=m
-CONFIG_X25=m
+# CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
@@ -154,18+137,7 @@ CONFIG_X25=m
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
-CONFIG_NET_SCHED=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-# CONFIG_NET_SCH_TEQL is not set
-CONFIG_NET_SCH_TBF=y
-# CONFIG_NET_QOS is not set
-# CONFIG_NET_CLS is not set
+# CONFIG_NET_SCHED is not set
 
 #
 # ISDN subsystem
@@ -184,7+156,7 @@ 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=y
+CONFIG_CHR_DEV_SG=m
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -235,21+207,22 @@ CONFIG_MYRI_SBUS=m
 #
 # Filesystems
 #
-CONFIG_QUOTA=y
+# CONFIG_QUOTA is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
+CONFIG_CODA_FS=m
 CONFIG_SMB_FS=m
 CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
@@ -267,13+240,12 @@ CONFIG_AFFS_FS=m
 CONFIG_ROMFS_FS=m
 CONFIG_AUTOFS_FS=m
 CONFIG_AMIGA_PARTITION=y
-CONFIG_UFS_FS=y
+CONFIG_UFS_FS=m
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
-# CONFIG_SOLARIS_X86_PARTITION is not set
+CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_ADFS_FS is not set
-CONFIG_QNX4FS_FS=m
-# CONFIG_QNX4FS_RW is not set
+# CONFIG_QNX4FS_FS is not set
 # CONFIG_MAC_PARTITION is not set
 CONFIG_NLS=y
 
index dd4dbb3..69f3070 100644 (file)
@@ -1,5+1,5 @@
 /* devices.c: Initial scan of the prom device tree for important
- *            Sparc device nodes which we need to find.
+ *           Sparc device nodes which we need to find.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 #include <asm/smp.h>
 #include <asm/system.h>
 
-struct prom_cpuinfo linux_cpus[NR_CPUS];
-int linux_num_cpus;
+struct prom_cpuinfo linux_cpus[32];
+int linux_num_cpus = 0;
 
 extern void cpu_probe(void);
 extern void clock_stop_probe(void); /* tadpole.c */
@@ -25,64+25,55 @@ __initfunc(unsigned long
 device_scan(unsigned long mem_start))
 {
        char node_str[128];
-       int nd, prom_node_cpu, thismid;
-       int cpu_nds[NR_CPUS];  /* One node for each cpu */
-       int cpu_ctr = 0;
+       int thismid;
 
        prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
 
        if(strcmp(node_str, "cpu") == 0) {
-               cpu_nds[0] = prom_root_node;
-               cpu_ctr++;
+               linux_num_cpus++;
        } else {
                int scan;
                scan = prom_getchild(prom_root_node);
                prom_printf("root child is %08lx\n", (unsigned long) scan);
-               nd = 0;
                while((scan = prom_getsibling(scan)) != 0) {
                        prom_getstring(scan, "device_type", node_str, sizeof(node_str));
                        if(strcmp(node_str, "cpu") == 0) {
-                               cpu_nds[cpu_ctr] = scan;
-                               linux_cpus[cpu_ctr].prom_node = scan;
+                               linux_cpus[linux_num_cpus].prom_node = scan;
                                prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
-                               linux_cpus[cpu_ctr].mid = thismid;
+                               linux_cpus[linux_num_cpus].mid = thismid;
                                prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
-                                           cpu_ctr, (unsigned long) scan,
+                                           linux_num_cpus, (unsigned long) scan,
                                            thismid);
-                               cpu_ctr++;
+                               linux_num_cpus++;
                        }
                };
-               if(cpu_ctr == 0) {
+               if(linux_num_cpus == 0) {
                        if (sparc_cpu_model == sun4d) {
                                scan = prom_getchild(prom_root_node);
                                for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
                                     scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
                                        int node = prom_getchild(scan);
-                                       
+
                                        prom_getstring(node, "device_type", node_str, sizeof(node_str));
                                        if (strcmp(node_str, "cpu") == 0) {
                                                prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
-                                               cpu_nds[cpu_ctr] = node;
-                                               linux_cpus[cpu_ctr].prom_node = node;
-                                               linux_cpus[cpu_ctr].mid = thismid;
+                                               linux_cpus[linux_num_cpus].prom_node = node;
+                                               linux_cpus[linux_num_cpus].mid = thismid;
                                                prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
-                                                           cpu_ctr, (unsigned long) node,
+                                                           linux_num_cpus, (unsigned long) node,
                                                            thismid);
-                                               cpu_ctr++;
+                                               linux_num_cpus++;
                                        }
                                }
                        }
                }
-               if(cpu_ctr == 0) {
+               if(linux_num_cpus == 0) {
                        printk("No CPU nodes found, cannot continue.\n");
                        /* Probably a sun4e, Sun is trying to trick us ;-) */
                        halt();
                }
-               printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+               printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
        };
-       prom_node_cpu = cpu_nds[0];
-
-       linux_num_cpus = cpu_ctr;
 
        cpu_probe();
 #ifdef CONFIG_SUN_AUXIO
index 9ad5498..7c3eda8 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: ebus.c,v 1.1 1998/09/18 10:43:43 jj Exp $
+/* $Id: ebus.c,v 1.2 1998/10/07 11:35:16 jj Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -141,6+141,9 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
                       (unsigned long)sparc_alloc_io (dev->base_address[i], 0,
                                                      regs[i].reg_size,
                                                      dev->prom_name, 0, 0);
+                   /* Some drivers call 'check_region', so we release it */
+                    release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE);
+
                    if (dev->base_address[i] == 0 ) {
                        panic("ebus: unable sparc_alloc_io for dev %s",
                              dev->prom_name);
index 506a986..156ed43 100644 (file)
@@ -6,7+6,7 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM;
index ed3d4de..4c8f78c 100644 (file)
@@ -1,4+1,4 @@
-/*  $Id: irq.c,v 1.89 1998/09/21 05:05:12 jj Exp $
+/*  $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -8,6+8,7 @@
  *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com)
  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ *  Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
  */
 
 #include <linux/config.h>
@@ -191,13+192,9 @@ void free_irq(unsigned int irq, void *dev_id)
         restore_flags(flags);
 }
 
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
+/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */
+unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
-#ifdef __SMP__
-atomic_t __sparc_bh_counter = ATOMIC_INIT(0);
-#else
-int __sparc_bh_counter = 0;
-#endif
 
 #ifdef __SMP__
 /* SMP interrupt locking on Sparc. */
@@ -208,14+205,33 @@ 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);
 
+atomic_t global_bh_count = ATOMIC_INIT(0);
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED;
+
 #ifdef DEBUG_IRQLOCK
 
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_bh CPU#%d stuck at %08lx\n", cpu, where); stuck = INIT_STUCK; }
+
+static inline void wait_on_bh(int cpu, unsigned long where)
+{
+       int stuck = INIT_STUCK;
+       do {
+               STUCK;
+               /* nothing .. wait for the other bh's to go away */
+       } while (atomic_read(&global_bh_count) != 0);
+}
+
 static unsigned long previous_irqholder;
 
 #undef INIT_STUCK
@@ -225,36+241,83 @@ static unsigned long previous_irqholder;
 #define STUCK \
 if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
 
+/*
+ * We have to allow irqs to arrive between __sti and __cli
+ */
+#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+
 static inline void wait_on_irq(int cpu, unsigned long where)
 {
        int stuck = INIT_STUCK;
        int local_count = local_irq_count[cpu];
 
-       /* Are we the only one in an interrupt context? */
-       while (local_count != atomic_read(&global_irq_count)) {
+       for (;;) {
+
                /*
-                * No such luck. Now we need to release the lock,
-                * _and_ release our interrupt context, because
-                * otherwise we'd have dead-locks and live-locks
-                * and other fun things.
+                * Wait until all interrupts are gone. Wait
+                * for bottom half handlers unless we're
+                * already executing in one..
                 */
-               atomic_sub(local_count, &global_irq_count);
+               if (!atomic_read(&global_irq_count)) {
+                       if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+                               break;
+               }
+
+               /* Duh, we have to loop. Release the lock to avoid deadlocks */
                spin_unlock(&global_irq_lock);
 
-               /*
-                * Wait for everybody else to go away and release
-                * their things before trying to get the lock again.
-                */
                for (;;) {
                        STUCK;
+
+                       __sti();
+                       SYNC_OTHER_CORES(cpu);
+                       __cli();
+
                        if (atomic_read(&global_irq_count))
                                continue;
                        if (*((unsigned char *)&global_irq_lock))
                                continue;
+                       if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+                               continue;
                        if (spin_trylock(&global_irq_lock))
                                break;
                }
-               atomic_add(local_count, &global_irq_count);
+       }
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler. 
+ */
+void synchronize_bh(void)
+{
+       unsigned long where;
+
+       __asm__("mov %%i7, %0" : "=r" (where));
+
+       if (atomic_read(&global_bh_count) && !in_interrupt()) {
+               int cpu = smp_processor_id();
+               wait_on_bh(cpu, where);
+       }
+}
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+       if (atomic_read(&global_irq_count)) {
+               /* Stupid approach */
+               cli();
+               sti();
        }
 }
 
@@ -281,54+344,106 @@ static inline void get_irqlock(int cpu, unsigned long where)
                        } while (*((volatile unsigned char *)&global_irq_lock));
                } while (!spin_trylock(&global_irq_lock));
        }
-       /*
-        * Ok, we got the lock bit.
-        * But that's actually just the easy part.. Now
-        * we need to make sure that nobody else is running
+       /* 
+        * We also to make sure that nobody else is running
         * in an interrupt context. 
         */
        wait_on_irq(cpu, where);
 
        /*
-        * Finally.
+        * Ok, finally..
         */
        global_irq_holder = cpu;
        previous_irqholder = where;
 }
 
+/*
+ * A global "cli()" while in an interrupt context
+ * turns into just a local cli(). Interrupts
+ * should use spinlocks for the (very unlikely)
+ * case that they ever want to protect against
+ * each other.
+ *
+ * If we already have local interrupts disabled,
+ * this will not turn a local disable into a
+ * global one (problems with spinlocks: this makes
+ * save_flags+cli+sti usable inside a spinlock).
+ */
 void __global_cli(void)
 {
-       int cpu = smp_processor_id();
+       unsigned int flags;
        unsigned long where;
 
        __asm__("mov %%i7, %0" : "=r" (where));
-       __cli();
-       get_irqlock(cpu, where);
+
+       __save_flags(flags);
+
+       if ((flags & PSR_PIL) != PSR_PIL) {
+               int cpu = smp_processor_id();
+               __cli();
+               if (!local_irq_count[cpu])
+                       get_irqlock(cpu, where);
+       }
 }
 
 void __global_sti(void)
 {
-       release_irqlock(smp_processor_id());
+       int cpu = smp_processor_id();
+
+       if (!local_irq_count[cpu])
+               release_irqlock(cpu);
        __sti();
 }
 
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
 unsigned long __global_save_flags(void)
 {
-       return global_irq_holder == (unsigned char) smp_processor_id();
+       int retval;
+       int local_enabled = 0;
+       unsigned long flags;
+
+       __save_flags(flags);
+
+       if ((flags & PSR_PIL) != PSR_PIL)
+               local_enabled = 1;
+
+       /* default to local */
+       retval = 2 + local_enabled;
+
+       /* check for global flags if we're not in an interrupt */
+       if (!local_irq_count[smp_processor_id()]) {
+               if (local_enabled)
+                       retval = 1;
+               if (global_irq_holder == (unsigned char) smp_processor_id())
+                       retval = 0;
+       }
+       return retval;
 }
 
 void __global_restore_flags(unsigned long flags)
 {
-       if(flags & 1) {
+       switch (flags) {
+       case 0:
                __global_cli();
-       } else {
-               /* release_irqlock() */
-               if(global_irq_holder == smp_processor_id()) {
-                       global_irq_holder = NO_PROC_ID;
-                       spin_unlock(&global_irq_lock);
-               }
-               if(!(flags & 2))
-                       __sti();
+               break;
+       case 1:
+               __global_sti();
+               break;
+       case 2:
+               __cli();
+               break;
+       case 3:
+               __sti();
+               break;
+       default:
+               printk("global_restore_flags: %08lx (%08lx)\n",
+                       flags, (&flags)[-1]);
        }
 }
 
@@ -353,7+468,7 @@ void irq_enter(int cpu, int irq, void *_opaque)
        while (*((volatile unsigned char *)&global_irq_lock)) {
                if ((unsigned char) cpu == global_irq_holder) {
                        struct pt_regs *regs = _opaque;
-                       int sbh_cnt = atomic_read(&__sparc_bh_counter);
+                       int sbh_cnt = atomic_read(&global_bh_count);
                        int globl_locked = *((unsigned char *)&global_irq_lock);
                        int globl_icount = atomic_read(&global_irq_count);
                        int local_count = local_irq_count[cpu];
@@ -386,24+501,6 @@ void irq_exit(int cpu, int irq)
 }
 
 #endif /* DEBUG_IRQLOCK */
-
-/* There has to be a better way. */
-void synchronize_irq(void)
-{
-       int cpu = smp_processor_id();
-       int local_count = local_irq_count[cpu];
-
-       if(local_count != atomic_read(&global_irq_count)) {
-               unsigned long flags;
-
-               /* See comment below at __global_save_flags to understand
-                * why we must do it this way on Sparc.
-                */
-               save_and_cli(flags);
-               restore_flags(flags);
-       }
-}
-
 #endif /* __SMP__ */
 
 void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
@@ -511,12+608,13 @@ int request_fast_irq(unsigned int irq,
        /* If this is flagged as statically allocated then we use our
         * private struct which is never freed.
         */
-       if (irqflags & SA_STATIC_ALLOC)
+       if (irqflags & SA_STATIC_ALLOC) {
            if (static_irq_count < MAX_STATIC_ALLOC)
                action = &static_irqaction[static_irq_count++];
            else
                printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
                       irq, devname);
+       }
        
        if (action == NULL)
            action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
@@ -604,11+702,12 @@ int request_irq(unsigned int irq,
        /* If this is flagged as statically allocated then we use our
         * private struct which is never freed.
         */
-       if (irqflags & SA_STATIC_ALLOC)
+       if (irqflags & SA_STATIC_ALLOC) {
            if (static_irq_count < MAX_STATIC_ALLOC)
                action = &static_irqaction[static_irq_count++];
            else
                printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname);
+       }
        
        if (action == NULL)
            action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
index c6e204c..aae13c5 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: pcic.c,v 1.2 1998/09/29 03:21:56 jj Exp $
+/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -83,7+83,7 @@ __initfunc(void pcic_probe(void))
        int node;
        int err;
 
-       if (pci_present()) {
+       if (pcibios_present()) {
                prom_printf("PCIC: called twice!\n");
                prom_halt();
        }
@@ -426,7+426,7 @@ __initfunc(void pci_time_init(void))
        /* A hack until do_gettimeofday prototype is moved to arch specific headers
           and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
        ((unsigned int *)do_gettimeofday)[0] = 
-               0x10800000 | (((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) & 0x003fffff);
+               0x10800000 | ((((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) >> 2) & 0x003fffff);
        ((unsigned int *)do_gettimeofday)[1] =
                0x01000000;
        BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM);
index eb815ee..287ed6c 100644 (file)
@@ -1,4+1,4 @@
-/*  $Id: signal.c,v 1.86 1998/09/29 09:46:04 davem Exp $
+/*  $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -75,6+75,7 @@ struct new_signal_frame {
        __siginfo_fpu_t         *fpu_save;
        unsigned long           insns [2] __attribute__ ((aligned (8)));
        unsigned int            extramask[_NSIG_WORDS - 1];
+       unsigned int            extra_size; /* Should be 0 */
        __siginfo_fpu_t         fpu_state;
 };
 
@@ -86,6+87,7 @@ struct rt_signal_frame {
        __siginfo_fpu_t         *fpu_save;
        unsigned int            insns [2];
        stack_t                 stack;
+       unsigned int            extra_size; /* Should be 0 */
        __siginfo_fpu_t         fpu_state;
 };
 
@@ -203,16+205,19 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 #endif
        current->used_math = 1;
        current->flags &= ~PF_USEDFPU;
+       
+       if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
+               return -EFAULT;
 
-       err = copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
-                      (sizeof(unsigned long) * 32));
+       err = __copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
+                              (sizeof(unsigned long) * 32));
        err |= __get_user(current->tss.fsr, &fpu->si_fsr);
        err |= __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
        if (current->tss.fpqdepth != 0)
-               err |= copy_from_user(&current->tss.fpqueue[0],
-                              &fpu->si_fpqueue[0],
-                              ((sizeof(unsigned long) +
-                              (sizeof(unsigned long *)))*16));
+               err |= __copy_from_user(&current->tss.fpqueue[0],
+                                       &fpu->si_fpqueue[0],
+                                       ((sizeof(unsigned long) +
+                                       (sizeof(unsigned long *)))*16));
        return err;
 }
 
@@ -241,7+246,7 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
 
        /* 2. Restore the state */
        up_psr = regs->psr;
-       err |= copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
+       err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
 
        /* User can only change condition codes and FPU enabling in %psr. */
        regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
@@ -250,14+255,14 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
        err |= __get_user(fpu_save, &sf->fpu_save);
 
        if (fpu_save)
-               err |= restore_fpu_state(regs, sf->fpu_save);
+               err |= restore_fpu_state(regs, fpu_save);
 
        /* This is pretty much atomic, no amount locking would prevent
         * the races which exist anyways.
         */
        err |= __get_user(set.sig[0], &sf->info.si_mask);
-       err |= copy_from_user(&set.sig[1], &sf->extramask,
-                          (_NSIG_WORDS-1) * sizeof(unsigned int));
+       err |= __copy_from_user(&set.sig[1], &sf->extramask,
+                               (_NSIG_WORDS-1) * sizeof(unsigned int));
                           
        if (err)
                goto segv_and_exit;
@@ -270,8+275,6 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
        return;
 
 segv_and_exit:
-       /* Ugh, we need to grab master lock in these rare cases ;-( */
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -305,8+308,8 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
         */
        err |= __get_user(set.sig[0], &scptr->sigc_mask);
        /* Note that scptr + 1 points to extramask */
-       err |= copy_from_user(&set.sig[1], scptr + 1,
-                          (_NSIG_WORDS - 1) * sizeof(unsigned int));
+       err |= __copy_from_user(&set.sig[1], scptr + 1,
+                               (_NSIG_WORDS - 1) * sizeof(unsigned int));
        
        if (err)
                goto segv_and_exit;
@@ -352,7+355,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
           (((unsigned long) sf) & 0x03))
                goto segv;
 
-       err = get_user(pc, &sf->regs.pc);
+       err = __get_user(pc, &sf->regs.pc);
        err |= __get_user(npc, &sf->regs.npc);
        err |= ((pc | npc) & 0x03);
 
@@ -366,8+369,8 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
        err |= __get_user(fpu_save, &sf->fpu_save);
 
        if(fpu_save)
-               err |= restore_fpu_state(regs, &sf->fpu_state);
-       err |= copy_from_user(&set, &sf->mask, sizeof(sigset_t));
+               err |= restore_fpu_state(regs, fpu_save);
+       err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
        
        err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
        
@@ -459,13+462,13 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
                for(window = 0; window < current->tss.w_saved; window++) {
                        sc->sigc_spbuf[window] =
                                (char *)current->tss.rwbuf_stkptrs[window];
-                       err |= copy_to_user(&sc->sigc_wbuf[window],
-                                           &current->tss.reg_window[window],
-                                           sizeof(struct reg_window));
+                       err |= __copy_to_user(&sc->sigc_wbuf[window],
+                                             &current->tss.reg_window[window],
+                                             sizeof(struct reg_window));
                }
        else
-               err |= copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
-                                   sizeof(struct reg_window));
+               err |= __copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
+                                     sizeof(struct reg_window));
 
        current->tss.w_saved = 0; /* So process is allowed to execute. */
        err |= __put_user(signr, &sframep->sig_num);
@@ -490,11+493,8 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        return;
 
 sigill_and_return:
-       /* Ugh, we need to grab master lock in these rare cases ;-( */
-       lock_kernel();
        do_exit(SIGILL);
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -520,13+520,13 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
                regs->psr &= ~(PSR_EF);
        }
 #endif
-       err |= copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
-                           (sizeof(unsigned long) * 32));
+       err |= __copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+                             (sizeof(unsigned long) * 32));
        err |= __put_user(current->tss.fsr, &fpu->si_fsr);
        err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
        if (current->tss.fpqdepth != 0)
-               err |= copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
-                                   ((sizeof(unsigned long) +
+               err |= __copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
+                                     ((sizeof(unsigned long) +
                                      (sizeof(unsigned long *)))*16));
        current->used_math = 0;
        return err;
@@ -560,7+560,9 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
        }
 
        /* 2. Save the current process state */
-       err = copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+       err = __copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+       
+       err |= __put_user(0, &sf->extra_size);
 
        if (current->used_math) {
                err |= save_fpu_state(regs, &sf->fpu_state);
@@ -572,8+574,8 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
        err |= __put_user(oldset->sig[0], &sf->info.si_mask);
        err |= __copy_to_user(sf->extramask, &oldset->sig[1],
                              (_NSIG_WORDS - 1) * sizeof(unsigned int));
-       err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
-                           sizeof (struct reg_window));
+       err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+                             sizeof (struct reg_window));
        if (err)
                goto sigsegv;
        
@@ -606,10+608,8 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
        return;
 
 sigill_and_return:
-       lock_kernel();
        do_exit(SIGILL);
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -620,7+620,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        struct rt_signal_frame *sf;
        int sigframe_size;
        unsigned int psr;
-       int i, err;
+       int err;
 
        synchronize_user_stack();
        sigframe_size = RT_ALIGNEDSZ;
@@ -632,15+632,16 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        if(current->tss.w_saved != 0)
                goto sigill;
 
-       err  = put_user(regs->pc, &sf->regs.pc);
+       err  = __put_user(regs->pc, &sf->regs.pc);
        err |= __put_user(regs->npc, &sf->regs.npc);
        err |= __put_user(regs->y, &sf->regs.y);
        psr = regs->psr;
        if(current->used_math)
                psr |= PSR_EF;
        err |= __put_user(psr, &sf->regs.psr);
-       for(i = 0; i < 16; i++)
-               err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+       err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
+       err |= __put_user(0, &sf->extra_size);
+
        if(psr & PSR_EF) {
                err |= save_fpu_state(regs, &sf->fpu_state);
                err |= __put_user(&sf->fpu_state, &sf->fpu_save);
@@ -654,8+655,8 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
        err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
        
-       err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
-                           sizeof (struct reg_window));        
+       err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+                             sizeof (struct reg_window));      
        if (err)
                goto sigsegv;
 
@@ -685,10+686,8 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        return;
 
 sigill:
-       lock_kernel();
        do_exit(SIGILL);
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -717,7+716,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        }
 
        /* Start with a clean frame pointer and fill it */
-       err = clear_user(sfp, sizeof (*sfp));
+       err = __clear_user(sfp, sizeof (*sfp));
 
        /* Setup convenience variables */
        si = &sfp->si;
@@ -746,8+745,8 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
        
        /* Copy g [1..7] and o [0..7] registers */
-       err |= copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
-       err |= copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
+       err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
+       err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
 
        /* Setup sigaltstack */
        err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
@@ -775,9+774,9 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
         */
        for(window = 0; window < current->tss.w_saved; window++) {
                err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
-               err |= copy_to_user(&gw->win [window],
-                                   &current->tss.reg_window [window],
-                                   sizeof (svr4_rwindow_t));
+               err |= __copy_to_user(&gw->win [window],
+                                     &current->tss.reg_window [window],
+                                     sizeof (svr4_rwindow_t));
                err |= __put_user(0, gw->winptr [window]);
        }
 
@@ -819,10+818,8 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        return;
 
 sigill_and_return:
-       lock_kernel();
        do_exit(SIGILL);
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -839,6+836,8 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
                goto sigsegv_and_return;
 
        err = clear_user(uc, sizeof (*uc));
+       if (err)
+               return -EFAULT;
 
        /* Setup convenience variables */
        mc = &uc->mcontext;
@@ -860,8+859,8 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
        err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
        
        /* Copy g [1..7] and o [0..7] registers */
-       err |= copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
-       err |= copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
+       err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
+       err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
 
        /* Setup sigaltstack */
        err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
@@ -874,7+873,6 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
        return (err ? -EFAULT : 0);
 
 sigsegv_and_return:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -950,14+948,13 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
        regs->psr |= (psr & PSR_ICC);
 
        /* Restore g[1..7] and o[0..7] registers */
-       err |= copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1],
+       err |= __copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1],
                              sizeof (long) * 7);
-       err |= copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0],
+       err |= __copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0],
                              sizeof (long) * 8);
        return (err ? -EFAULT : 0);
 
 sigsegv_and_return:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -1110,7+1107,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
                        case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
                                if(current->binfmt && current->binfmt->core_dump) {
                                        lock_kernel();
-                                       if(current->binfmt->core_dump(signr, regs))
+                                       if(current->binfmt &&
+                                          current->binfmt->core_dump &&
+                                          current->binfmt->core_dump(signr, regs))
                                                exit_code |= 0x80;
                                        unlock_kernel();
                                }
index df5208b..f77d823 100644 (file)
@@ -64,6+64,9 @@ volatile int __cpu_logical_map[NR_CPUS];
 /* Kernel spinlock */
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
+/* Used to make bitops atomic */
+unsigned char bitops_spinlock = 0;
+
 volatile unsigned long ipi_count;
 
 volatile int smp_process_available=0;
index 2e14b5b..a23b84a 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sparc_ksyms.c,v 1.70 1998/09/17 11:04:55 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.72 1998/10/22 15:15:08 ecd Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6+68,10 @@ extern int __ashrdi3(int, int);
 
 extern void dump_thread(struct pt_regs *, struct user *);
 
+#ifdef __SMP__
+extern spinlock_t kernel_flag;
+#endif
+
 /* One thing to note is that the way the symbols of the mul/div
  * support routines are named is a mess, they all start with
  * a '.' which makes it a bitch to export, here is the trick:
@@ -87,33+91,21 @@ __attribute__((section("__ksymtab"))) =                             \
 EXPORT_SYMBOL(sparc_cpu_model);
 EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
 #ifdef SPIN_LOCK_DEBUG
-EXPORT_SYMBOL(_spin_lock);
-EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(_do_spin_lock);
+EXPORT_SYMBOL(_do_spin_unlock);
 EXPORT_SYMBOL(_spin_trylock);
-EXPORT_SYMBOL(_spin_lock_irq);
-EXPORT_SYMBOL(_spin_unlock_irq);
-EXPORT_SYMBOL(_spin_lock_irqsave);
-EXPORT_SYMBOL(_spin_unlock_irqrestore);
-EXPORT_SYMBOL(_read_lock);
-EXPORT_SYMBOL(_read_unlock);
-EXPORT_SYMBOL(_read_lock_irq);
-EXPORT_SYMBOL(_read_unlock_irq);
-EXPORT_SYMBOL(_read_lock_irqsave);
-EXPORT_SYMBOL(_read_unlock_irqrestore);
-EXPORT_SYMBOL(_write_lock);
-EXPORT_SYMBOL(_write_unlock);
-EXPORT_SYMBOL(_write_lock_irq);
-EXPORT_SYMBOL(_write_unlock_irq);
-EXPORT_SYMBOL(_write_lock_irqsave);
-EXPORT_SYMBOL(_write_unlock_irqrestore);
+EXPORT_SYMBOL(_do_read_lock);
+EXPORT_SYMBOL(_do_read_unlock);
+EXPORT_SYMBOL(_do_write_lock);
+EXPORT_SYMBOL(_do_write_unlock);
 #else
 EXPORT_SYMBOL_PRIVATE(_rw_read_enter);
 EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
 EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
 #endif
-EXPORT_SYMBOL(__sparc_bh_counter);
 #ifdef __SMP__
 #ifdef DEBUG_IRQLOCK
+EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_cli);
@@ -142,14+134,19 @@ EXPORT_SYMBOL_PRIVATE(_set_le_bit);
 EXPORT_SYMBOL_PRIVATE(_clear_le_bit);
 
 /* IRQ implementation. */
-EXPORT_SYMBOL(local_irq_count);
 #ifdef __SMP__
+EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(global_irq_lock);
 EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(sparc_bh_lock);
 EXPORT_SYMBOL(global_irq_count);
 EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(synchronize_bh);
 #endif
+EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(local_bh_count);
 
 EXPORT_SYMBOL(udelay);
 EXPORT_SYMBOL(mstk48t02_regs);
index b1a1117..9347471 100644 (file)
@@ -1,4+1,4 @@
-/*  $Id: sun4d_irq.c,v 1.15 1998/09/29 09:46:12 davem Exp $
+/*  $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $
  *  arch/sparc/kernel/sun4d_irq.c:
  *                     SS1000/SC2000 interrupt handling.
  *
@@ -438,8+438,13 @@ __initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct
        int cpu;
 
        /* Map the User Timer registers. */
-       sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0,
+#ifdef __SMP__
+       sun4d_timers = sparc_alloc_io(CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT, 0,
+                                     PAGE_SIZE, "user timer", 0xf, 0x0);
+#else
+       sun4d_timers = sparc_alloc_io(CSR_BASE(0)+BW_TIMER_LIMIT, 0,
                                      PAGE_SIZE, "user timer", 0xf, 0x0);
+#endif
     
        sun4d_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
        master_l10_counter = &sun4d_timers->l10_cur_count;
index deb1aa7..2f0fe9e 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sunos_ioctl.c,v 1.30 1998/01/21 06:17:32 ecd Exp $
+/* $Id: sunos_ioctl.c,v 1.31 1998/10/25 19:31:04 davem Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -218,7+218,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
        }
 
 #if 0
-       if (cmd & 0xff00 == ('k' << 8)){
+       if ((cmd & 0xff00) == ('k' << 8)) {
                printk ("[[KBIO: %8.8x\n", (unsigned int) cmd);
        }
 #endif
index 991e651..e5ea2e9 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sys_sparc.c,v 1.48 1998/09/07 09:19:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -181,6+181,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
        struct file * file = NULL;
        unsigned long retval = -EBADF;
 
+       down(&current->mm->mmap_sem);
        lock_kernel();
        if (!(flags & MAP_ANONYMOUS)) {
                file = fget(fd);
@@ -214,6+215,7 @@ out_putf:
                fput(file);
 out:
        unlock_kernel();
+       up(&current->mm->mmap_sem);
        return retval;
 }
 
index 69d959a..086a473 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sys_sunos.c,v 1.92 1998/08/31 03:40:53 davem Exp $
+/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6+68,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
        struct file * file = NULL;
        unsigned long retval, ret_type;
 
+       down(&current->mm->mmap_sem);
        lock_kernel();
        current->personality |= PER_BSD;
        if(flags & MAP_NORESERVE) {
@@ -128,6+129,7 @@ out_putf:
                fput(file);
 out:
        unlock_kernel();
+       up(&current->mm->mmap_sem);
        return retval;
 }
 
@@ -147,6+149,7 @@ asmlinkage int sunos_brk(unsigned long brk)
        unsigned long rlim;
        unsigned long newbrk, oldbrk;
 
+       down(&current->mm->mmap_sem);
        lock_kernel();
        if(ARCH_SUN4C_SUN4) {
                if(brk >= 0x20000000 && brk < 0xe0000000) {
@@ -213,6+216,7 @@ asmlinkage int sunos_brk(unsigned long brk)
        retval = 0;
 out:
        unlock_kernel();
+       up(&current->mm->mmap_sem);
        return retval;
 }
 
@@ -579,20+583,16 @@ struct sunos_utsname {
 
 asmlinkage int sunos_uname(struct sunos_utsname *name)
 {
-       int ret = -EFAULT;
-
+       int ret;
        down(&uts_sem);
-       if(!name)
-               goto out;
-       if(copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1))
-               goto out;
-       copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
-       put_user('\0', &name->nname[8]);
-       copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
-       copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
-       copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
-       ret = 0;
-out:
+       ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
+       if (!ret) {
+               ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
+               ret |= __put_user('\0', &name->nname[8]);
+               ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+               ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+               ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
+       }
        up(&uts_sem);
        return ret;
 }
@@ -843,7+843,7 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
        strncpy (linux_nfs_mount.hostname, the_name, 254);
        linux_nfs_mount.hostname [255] = 0;
        putname (the_name);
-
+       
        dev = get_unnamed_dev ();
        
        ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
@@ -860,6+860,9 @@ sunos_mount(char *type, char *dir, int flags, void *data)
        int ret = -EINVAL;
        char *dev_fname = 0;
 
+       if (!capable (CAP_SYS_ADMIN))
+               return -EPERM;
+               
        lock_kernel();
        /* We don't handle the integer fs type */
        if ((flags & SMNT_NEWTYPE) == 0)
index 526bf86..253c358 100644 (file)
@@ -26,12+26,26 @@ ___set_bit:
        wr      %g3, PSR_PIL, %psr
        nop; nop; nop
 1:
-       ld      [%g1], %g7
+#ifdef __SMP__
+       set     C_LABEL(bitops_spinlock), %g5
+2:     ldstub  [%g5], %g7              ! Spin on the byte lock for SMP.
+       orcc    %g7, 0x0, %g0           ! Did we get it?
+       bne     2b                      ! Nope...
+#endif
+        ld     [%g1], %g7
        or      %g7, %g2, %g5
-       andcc   %g3, PSR_PIL, %g0
        and     %g7, %g2, %g2
+#ifdef __SMP__
+       st      %g5, [%g1]
+       set     C_LABEL(bitops_spinlock), %g5
+       andcc   %g3, PSR_PIL, %g0
+       bne     1f
+        stb    %g0, [%g5]
+#else
+       andcc   %g3, PSR_PIL, %g0
        bne     1f
         st     %g5, [%g1]
+#endif
        wr      %g3, 0x0, %psr
        nop; nop; nop
 1:
@@ -48,12+62,26 @@ ___clear_bit:
        wr      %g3, PSR_PIL, %psr
        nop; nop; nop
 1:
-       ld      [%g1], %g7
+#ifdef __SMP__
+       set     C_LABEL(bitops_spinlock), %g5
+2:     ldstub  [%g5], %g7              ! Spin on the byte lock for SMP.
+       orcc    %g7, 0x0, %g0           ! Did we get it?
+       bne     2b                      ! Nope...
+#endif
+        ld     [%g1], %g7
        andn    %g7, %g2, %g5
-       andcc   %g3, PSR_PIL, %g0
        and     %g7, %g2, %g2
+#ifdef __SMP__
+       st      %g5, [%g1]
+       set     C_LABEL(bitops_spinlock), %g5
+       andcc   %g3, PSR_PIL, %g0
+       bne     1f
+        stb    %g0, [%g5]
+#else
+       andcc   %g3, PSR_PIL, %g0
        bne     1f
         st     %g5, [%g1]
+#endif
        wr      %g3, 0x0, %psr
        nop; nop; nop
 1:
@@ -70,12+98,26 @@ ___change_bit:
        wr      %g3, PSR_PIL, %psr
        nop; nop; nop
 1:
-       ld      [%g1], %g7
+#ifdef __SMP__
+       set     C_LABEL(bitops_spinlock), %g5
+2:     ldstub  [%g5], %g7              ! Spin on the byte lock for SMP.
+       orcc    %g7, 0x0, %g0           ! Did we get it?
+       bne     2b                      ! Nope...
+#endif
+        ld     [%g1], %g7
        xor     %g7, %g2, %g5
-       andcc   %g3, PSR_PIL, %g0
        and     %g7, %g2, %g2
+#ifdef __SMP__
+       st      %g5, [%g1]
+       set     C_LABEL(bitops_spinlock), %g5
+       andcc   %g3, PSR_PIL, %g0
+       bne     1f
+        stb    %g0, [%g5]
+#else
+       andcc   %g3, PSR_PIL, %g0
        bne     1f
         st     %g5, [%g1]
+#endif
        wr      %g3, 0x0, %psr
        nop; nop; nop
 1:
@@ -92,12+134,26 @@ ___set_le_bit:
        wr      %g3, PSR_PIL, %psr
        nop; nop; nop
 1:
-       ldub    [%g1], %g7
+#ifdef __SMP__
+       set     C_LABEL(bitops_spinlock), %g5
+2:     ldstub  [%g5], %g7              ! Spin on the byte lock for SMP.
+       orcc    %g7, 0x0, %g0           ! Did we get it?
+       bne     2b                      ! Nope...
+#endif
+        ldub   [%g1], %g7
        or      %g7, %g2, %g5
-       andcc   %g3, PSR_PIL, %g0
        and     %g7, %g2, %g2
+#ifdef __SMP__
+       stb     %g5, [%g1]
+       set     C_LABEL(bitops_spinlock), %g5
+       andcc   %g3, PSR_PIL, %g0
+       bne     1f
+        stb    %g0, [%g5]
+#else
+       andcc   %g3, PSR_PIL, %g0
        bne     1f
         stb    %g5, [%g1]
+#endif
        wr      %g3, 0x0, %psr
        nop; nop; nop
 1:
@@ -113,12+169,26 @@ ___clear_le_bit:
        wr      %g3, PSR_PIL, %psr
        nop; nop; nop
 1:
-       ldub    [%g1], %g7
+#ifdef __SMP__
+       set     C_LABEL(bitops_spinlock), %g5
+2:     ldstub  [%g5], %g7              ! Spin on the byte lock for SMP.
+       orcc    %g7, 0x0, %g0           ! Did we get it?
+       bne     2b                      ! Nope...
+#endif
+        ldub   [%g1], %g7
        andn    %g7, %g2, %g5
-       andcc   %g3, PSR_PIL, %g0
        and     %g7, %g2, %g2
+#ifdef __SMP__
+       stb     %g5, [%g1]
+       set     C_LABEL(bitops_spinlock), %g5
+       andcc   %g3, PSR_PIL, %g0
+       bne     1f
+        stb    %g0, [%g5]
+#else
+       andcc   %g3, PSR_PIL, %g0
        bne     1f
         stb    %g5, [%g1]
+#endif
        wr      %g3, 0x0, %psr
        nop; nop; nop
 1:
index ef7d574..8f0941e 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: debuglocks.c,v 1.3 1998/09/29 09:46:22 davem Exp $
+/* $Id: debuglocks.c,v 1.5 1998/10/14 09:19:04 jj Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -120,29+120,17 @@ wlock_again:
        if(val) {
                while(rw->lock & 0xff) {
                        if (!--stuck) {
-                               show(str, (spinlock_t *)rw, caller);
-                               stuck = INIT_STUCK;
-                       }
-                       barrier();
-               }
-               goto wlock_again;
-       }
-clock_again:
-       __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff00) {
-                       if (!--stuck) {
                                show_read(str, rw, caller);
                                stuck = INIT_STUCK;
                        }
                        barrier();
                }
-               goto clock_again;
+               goto wlock_again;
        }
-       (*((unsigned short *)&rw->lock))++;
+
        rw->reader_pc[cpu] = caller;
        barrier();
-       (*(((unsigned short *)&rw->lock)+1)) = 0;
+       rw->lock++;
 }
 
 #undef INIT_STUCK
@@ -157,22+145,22 @@ void _do_read_unlock(rwlock_t *rw, char *str)
 
        STORE_CALLER(caller);
 
-clock_again:
-       __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+wlock_again:
+       __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
        if(val) {
-               while(rw->lock & 0xff00) {
+               while(rw->lock & 0xff) {
                        if (!--stuck) {
                                show_read(str, rw, caller);
                                stuck = INIT_STUCK;
                        }
                        barrier();
                }
-               goto clock_again;
+               goto wlock_again;
        }
-       (*((unsigned short *)&rw->lock))--;
+
        rw->reader_pc[cpu] = 0;
        barrier();
-       (*(((unsigned char *)&rw->lock)+2))=0;
+       rw->lock -= 0x1ff;
 }
 
 #undef INIT_STUCK
@@ -190,7+178,8 @@ void _do_write_lock(rwlock_t *rw, char *str)
 wlock_again:
        __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
        if(val) {
-               while(rw->lock & 0xff) {
+wlock_wait:
+               while(rw->lock) {
                        if (!--stuck) {
                                show_write(str, rw, caller);
                                stuck = INIT_STUCK;
@@ -199,14+188,15 @@ wlock_again:
                }
                goto wlock_again;
        }
-       rw->owner_pc = (cpu & 3) | (caller & ~3);
-       while(rw->lock & ~0xff) {
-               if (!--stuck) {
-                       show_write(str, rw, caller);
-                       stuck = INIT_STUCK;
-               }
+
+       if (rw->lock & ~0xff) {
+               *(((unsigned char *)&rw->lock)+3) = 0;
                barrier();
+               goto wlock_wait;
        }
+
+       barrier();
+       rw->owner_pc = (cpu & 3) | (caller & ~3);
 }
 
 void _do_write_unlock(rwlock_t *rw)
index 8d63470..102541b 100644 (file)
@@ -1,7+1,9 @@
-/* $Id: locks.S,v 1.13 1998/07/30 11:29:28 davem Exp $
+/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $
  * locks.S: SMP low-level lock primitives on Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
 #include <asm/cprefix.h>
@@ -43,52+45,48 @@ ___rw_read_enter_spin_on_wlock:
         ldstub [%g1 + 3], %g2
        b       ___rw_read_enter_spin_on_wlock
         ldub   [%g1 + 3], %g2
+___rw_read_exit_spin_on_wlock:
+       orcc    %g2, 0x0, %g0
+       be,a    ___rw_read_exit
+        ldstub [%g1 + 3], %g2
+       b       ___rw_read_exit_spin_on_wlock
+        ldub   [%g1 + 3], %g2
 ___rw_write_enter_spin_on_wlock:
        orcc    %g2, 0x0, %g0
        be,a    ___rw_write_enter
         ldstub [%g1 + 3], %g2
        b       ___rw_write_enter_spin_on_wlock
-        ldub   [%g1 + 3], %g2
+        ld     [%g1], %g2
 
        .globl  ___rw_read_enter
 ___rw_read_enter:
        orcc    %g2, 0x0, %g0
        bne,a   ___rw_read_enter_spin_on_wlock
         ldub   [%g1 + 3], %g2
-1:
-       ldstub  [%g1 + 2], %g7
-       orcc    %g7, 0x0, %g0
-       bne     1b
-        ldsh   [%g1], %g2
+       ld      [%g1], %g2
        add     %g2, 1, %g2
-       sth     %g2, [%g1]
-       sth     %g0, [%g1 + 2]
+       st      %g2, [%g1]
        retl
         mov    %g4, %o7
 
-       /* We must be careful here to not blow away wlock. */
        .globl  ___rw_read_exit
-___rw_read_exit_spin:
-       ldstub  [%g1 + 2], %g2
 ___rw_read_exit:
        orcc    %g2, 0x0, %g0
-       bne     ___rw_read_exit_spin
-        ldsh   [%g1], %g7
-       sub     %g7, 1, %g7
-       sth     %g7, [%g1]
-       stb     %g0, [%g1 + 2]
+       bne,a   ___rw_read_exit_spin_on_wlock
+        ldub   [%g1 + 3], %g2
+       ld      [%g1], %g2
+       sub     %g2, 0x1ff, %g2
+       st      %g2, [%g1]
        retl
         mov    %g4, %o7
 
        .globl  ___rw_write_enter
 ___rw_write_enter:
        orcc    %g2, 0x0, %g0
-       bne,a   ___rw_write_enter_spin_on_wlock
-        ldub   [%g1 + 3], %g2
-       ld      [%g1], %g2
-1:
-       andncc  %g2, 0xff, %g0
-       bne,a   1b
+       bne     ___rw_write_enter_spin_on_wlock
         ld     [%g1], %g2
+       andncc  %g2, 0xff, %g0
+       bne,a   ___rw_write_enter_spin_on_wlock
+        stb    %g0, [%g1 + 3]
        retl
         mov    %g4, %o7
index 3a60e08..01d44a3 100644 (file)
-# $Id: Makefile,v 1.29 1998/09/16 12:25:20 jj Exp $
+# $Id: Makefile,v 1.33 1998/10/19 07:04:02 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
 # 64-bit Sparc.
 #
-# Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
 #
 
 # If the solaris /bin/sh wasn't so broken, I wouldn't need the following
 # line...
 SHELL  =/bin/bash
 
-CC             = sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
+CC             := sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
 
+CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\|  \)' > /dev/null; then echo y; else echo n; fi)
 IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
 NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
 
+ifneq ($(CC_HAS_ARGS),y)
+MAKEOVERRIDES  := $(shell echo "$(MAKEOVERRIDES)" | sed 's CC=$(CC) CC=$(CC)\\\ -D__KERNEL__\\\ -I$(TOPDIR)/include ')
+override CC    := $(CC) -D__KERNEL__ -I$(TOPDIR)/include
+endif
+
 ifneq ($(NEW_GAS),y)
 AS             = sparc64-linux-as
 LD             = sparc64-linux-ld
@@ -28,7+35,6 @@ LD            := $(LD) -m elf64_sparc
 endif
 ELFTOAOUT      = elftoaout
 
-
 #
 # Uncomment the first CFLAGS if you are doing kgdb source level
 # debugging of the kernel to get the proper debugging information.
@@ -42,6+48,16 @@ else
            -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
 endif
 
+# Uncomment this to get spinlock/rwlock debugging on SMP.
+# DEBUG_SPINLOCK = 1
+
+ifdef SMP
+  ifdef DEBUG_SPINLOCK
+    CFLAGS += -DSPIN_LOCK_DEBUG
+    AFLAGS += -DSPIN_LOCK_DEBUG
+  endif
+endif
+
 LINKFLAGS = -T arch/sparc64/vmlinux.lds
 
 HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
index e971467..3a0e0c6 100644 (file)
@@ -27,6+27,7 @@ CONFIG_VT_CONSOLE=y
 CONFIG_PROM_CONSOLE=y
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_MATROX is not set
 CONFIG_FB_SBUS=y
 CONFIG_FB_CREATOR=y
 CONFIG_FB_CGSIX=y
@@ -86,10+87,11 @@ CONFIG_BINFMT_ELF32=y
 CONFIG_BINFMT_MISC=m
 CONFIG_BINFMT_JAVA=m
 CONFIG_SOLARIS_EMUL=m
-CONFIG_PARPORT=y
-CONFIG_PARPORT_AX=y
+CONFIG_PARPORT=m
+CONFIG_PARPORT_AX=m
+CONFIG_PARPORT_LOWLEVEL_MODULE=y
 # CONFIG_PARPORT_OTHER is not set
-CONFIG_PRINTER=y
+CONFIG_PRINTER=m
 CONFIG_PRINTER_READBACK=y
 CONFIG_ENVCTRL=m
 
@@ -122,11+124,9 @@ CONFIG_BLK_DEV_CMD646=y
 # Networking options
 #
 CONFIG_PACKET=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
+# CONFIG_NET_ALIAS is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -136,8+136,7 @@ CONFIG_INET=y
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_ARPD is not set
+# CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
 
 #
@@ -165,18+164,7 @@ CONFIG_ATALK=m
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
-CONFIG_NET_SCHED=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-# CONFIG_NET_QOS is not set
-# CONFIG_NET_CLS is not set
+# CONFIG_NET_SCHED is not set
 
 #
 # SCSI support
@@ -249,7+237,7 @@ CONFIG_SUNLANCE=y
 CONFIG_HAPPYMEAL=y
 CONFIG_SUNQE=m
 CONFIG_MYRI_SBUS=m
-CONFIG_DE4X5=y
+CONFIG_DE4X5=m
 CONFIG_VORTEX=m
 
 #
@@ -258,18+246,19 @@ CONFIG_VORTEX=m
 # CONFIG_QUOTA is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
+CONFIG_CODA_FS=m
 CONFIG_SMB_FS=m
 CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
@@ -292,8+281,7 @@ CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_ADFS_FS is not set
-CONFIG_QNX4FS_FS=m
-# CONFIG_QNX4FS_RW is not set
+# CONFIG_QNX4FS_FS is not set
 # CONFIG_MAC_PARTITION is not set
 CONFIG_NLS=y
 
index 7a3ee40..4d1b1eb 100644 (file)
@@ -1,4+1,4 @@
-# $Id: Makefile,v 1.40 1998/09/17 11:05:03 jj Exp $
+# $Id: Makefile,v 1.41 1998/10/11 06:58:14 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -89,6+89,8 @@ check_asm: dummy
        @echo "" >> asm_offsets.h
        @echo "#else /* __SMP__ */" >> asm_offsets.h
        @echo "" >> asm_offsets.h
+       @echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h
+       @echo "" >> asm_offsets.h
        @echo "#include <linux/sched.h>" > tmp.c
        $(CC) -D__SMP__ -E tmp.c -o tmp.i
        @echo "/* Automatically generated. Do not edit. */" > check_asm.c
@@ -111,6+113,31 @@ check_asm: dummy
        ./check_asm >> asm_offsets.h
        @rm -f check_asm check_asm.c
        @echo "" >> asm_offsets.h
+       @echo "#else /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#include <linux/sched.h>" > tmp.c
+       $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
+       @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/sched.h>" >> check_asm.c
+       @echo 'struct task_struct _task;' >> check_asm.c
+       @echo 'struct mm_struct _mm;' >> check_asm.c
+       @echo 'struct thread_struct _thread;' >> check_asm.c
+       @echo 'int main(void) {' >> check_asm.c
+       $(SH) ./check_asm.sh task tmp.i check_asm.c
+       $(SH) ./check_asm.sh mm tmp.i check_asm.c
+       $(SH) ./check_asm.sh thread tmp.i check_asm.c
+       @echo 'return 0; }' >> check_asm.c
+       @rm -f tmp.[ci]
+       #$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c
+       # <hack> Until we can do this natively, a hack has to take place
+       $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
+       $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
+       @rm -f check_asm.s
+       # </hack>
+       ./check_asm >> asm_offsets.h
+       @rm -f check_asm check_asm.c
+       @echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
        @echo "#endif /* __SMP__ */" >> asm_offsets.h
        @echo "" >> asm_offsets.h
        @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
index cfabbfc..7c0d80e 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: entry.S,v 1.90 1998/09/25 01:09:05 davem Exp $
+/* $Id: entry.S,v 1.91 1998/10/07 01:27:08 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -730,7+730,7 @@ sys_clone:  flushw
                 mov            %l5, %o7
 ret_from_syscall:
                /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in
-                * %o7 for us.
+                * %o7 for us.  Check performance counter stuff too.
                 */
                andn            %o7, 0x100, %o7
                sth             %o7, [%g6 + AOFF_task_tss + AOFF_thread_flags]
@@ -739,7+739,13 @@ ret_from_syscall:
                membar          #StoreStore | #LoadStore
                stb             %g0, [%o4 + %lo(scheduler_lock)]
 #endif
-               b,pt            %xcc, ret_sys_call
+               andcc           %o7, 0x200, %g0
+               be,pt           %icc, 1f
+                nop
+               ldx             [%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7
+               wr              %g0, %o7, %pcr
+               wr              %g0, %g0, %pic
+1:             b,pt            %xcc, ret_sys_call
                 ldx            [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
 sparc_exit:    rdpr            %otherwin, %g1
                rdpr            %pstate, %g2
index f1e9c62..8c92688 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: head.S,v 1.53 1998/06/15 16:59:35 jj Exp $
+/* $Id: head.S,v 1.54 1998/10/06 20:48:30 ecd Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -380,6+380,9 @@ setup_tba:
        or      %g5, %lo(ivector_to_mask), %g1  /* IVECTOR table */
        mov     0x40, %g2                       /* INTR data 0 register */
 
+       /* Kill PROM timer */
+       wr      %g0, 0, %tick_cmpr
+
        /* Ok, we're done setting up all the state our trap mechanims needs,
         * now get back into normal globals and let the PROM know what is up.
         */
index d0a0d6c..10a0115 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: ioctl32.c,v 1.52 1998/09/25 17:09:22 jj Exp $
+/* $Id: ioctl32.c,v 1.53 1998/10/26 08:01:01 jj Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -1532,8+1532,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
                error = loop_status(fd, cmd, arg);
                goto out;
 
-       case AUTOFS_IOC_SETTIMEOUT:
-               error = rw_long(fd, cmd, arg);
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+       case AUTOFS_IOC_SETTIMEOUT32:
+               error = rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
                goto out;
                
        case PIO_FONTX:
index eaa7ad7..d870726 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: irq.c,v 1.61 1998/08/02 14:51:38 ecd Exp $
+/* $Id: irq.c,v 1.66 1998/10/21 15:02:25 ecd Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
 #include <linux/malloc.h>
 #include <linux/random.h> /* XXX ADD add_foo_randomness() calls... -DaveM */
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -208,7+209,7 @@ unsigned char psycho_ino_to_pil[] = {
        13, /* Audio Record */
        14, /* Audio Playback */
        15, /* PowerFail */
-       9,  /* Keyboard/Mouse/Serial */
+       3,  /* second SCSI */
        11, /* Floppy */
        2,  /* Spare Hardware */
        9,  /* Keyboard */
@@ -573,22+574,18 @@ out:
        restore_flags(flags);
 }
 
-/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu
- * structure for cache reasons.
+/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it
+ * lives in the per-cpu structure for cache reasons.
  */
 #ifndef __SMP__
 unsigned int local_irq_count;
-#endif
-
-#ifndef __SMP__
-int __sparc64_bh_counter = 0;
+unsigned int local_bh_count;
 
 #define irq_enter(cpu, irq)    (local_irq_count++)
 #define irq_exit(cpu, irq)     (local_irq_count--)
-
 #else
-
-atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED;
 
 /* Who has global_irq_lock. */
 unsigned char global_irq_holder = NO_PROC_ID;
@@ -596,136+593,163 @@ 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 unsigned long previous_irqholder;
+#define irq_enter(cpu, irq)                    \
+do {   hardirq_enter(cpu);                     \
+       spin_unlock_wait(&global_irq_lock);     \
+} while(0)
+#define irq_exit(cpu, irq)     hardirq_exit(cpu)
 
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+static void show(char * str)
+{
+       int cpu = smp_processor_id();
 
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+       printk("\n%s, CPU %d:\n", str, cpu);
+       printk("irq:  %d [%d %d]\n",
+              atomic_read(&global_irq_count),
+              cpu_data[0].irq_count, cpu_data[1].irq_count);
+       printk("bh:   %d [%d %d]\n",
+              (spin_is_locked(&global_bh_count) ? 1 : 0),
+              cpu_data[0].bh_count, cpu_data[1].bh_count);
+}
+
+#define MAXCOUNT 100000000
 
-static inline void wait_on_irq(int cpu, unsigned long where)
+static inline void wait_on_bh(void)
 {
-       int stuck = INIT_STUCK;
-       int local_count = local_irq_count;
+       int count = MAXCOUNT;
+       do {
+               if(!--count) {
+                       show("wait_on_bh");
+                       count = 0;
+               }
+               membar("#LoadLoad");
+       } while(spin_is_locked(&global_bh_count));
+}
+
+#define SYNC_OTHER_ULTRAS(x)   udelay(x+1)
 
-       while(local_count != atomic_read(&global_irq_count)) {
-               atomic_sub(local_count, &global_irq_count);
-               spin_unlock(&global_irq_lock);
+static inline void wait_on_irq(int cpu)
+{
+       int count = MAXCOUNT;
+       for(;;) {
+               membar("#LoadLoad");
+               if (!atomic_read (&global_irq_count)) {
+                       if (local_bh_count || ! spin_is_locked(&global_bh_count))
+                               break;
+               }
+               spin_unlock (&global_irq_lock);
+               membar("#StoreLoad | #StoreStore");
                for(;;) {
-                       STUCK;
-                       membar("#StoreLoad | #LoadLoad");
+                       if (!--count) {
+                               show("wait_on_irq");
+                               count = ~0;
+                       }
+                       __sti();
+                       SYNC_OTHER_ULTRAS(cpu);
+                       __cli();
                        if (atomic_read(&global_irq_count))
                                continue;
-                       if (*((volatile unsigned char *)&global_irq_lock))
+                       if (spin_is_locked (&global_irq_lock))
+                               continue;
+                       if (!local_bh_count && spin_is_locked (&global_bh_count))
                                continue;
-                       membar("#LoadLoad | #LoadStore");
                        if (spin_trylock(&global_irq_lock))
                                break;
                }
-               atomic_add(local_count, &global_irq_count);
        }
 }
 
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+void synchronize_bh(void)
+{
+       if (spin_is_locked (&global_bh_count) && !in_interrupt())
+               wait_on_bh();
+}
 
-static inline void get_irqlock(int cpu, unsigned long where)
+void synchronize_irq(void)
 {
-       int stuck = INIT_STUCK;
+       if (atomic_read(&global_irq_count)) {
+               cli();
+               sti();
+       }
+}
 
-       if (!spin_trylock(&global_irq_lock)) {
-               membar("#StoreLoad | #LoadLoad");
+static inline void get_irqlock(int cpu)
+{
+       if (! spin_trylock(&global_irq_lock)) {
                if ((unsigned char) cpu == global_irq_holder)
                        return;
                do {
-                       do {
-                               STUCK;
+                       while (spin_is_locked (&global_irq_lock))
                                membar("#LoadLoad");
-                       } while(*((volatile unsigned char *)&global_irq_lock));
-               } while (!spin_trylock(&global_irq_lock));
+               } while(! spin_trylock(&global_irq_lock));
        }
-       wait_on_irq(cpu, where);
+       wait_on_irq(cpu);
        global_irq_holder = cpu;
-       previous_irqholder = where;
 }
 
 void __global_cli(void)
 {
-       int cpu = smp_processor_id();
-       unsigned long where;
+       unsigned long flags;
 
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (where));
-       __cli();
-       get_irqlock(cpu, where);
+       __save_flags(flags);
+       if(flags == 0) {
+               int cpu = smp_processor_id();
+               __cli();
+               if (! local_irq_count)
+                       get_irqlock(cpu);
+       }
 }
 
 void __global_sti(void)
 {
-       release_irqlock(smp_processor_id());
+       int cpu = smp_processor_id();
+
+       if (! local_irq_count)
+               release_irqlock(cpu);
        __sti();
 }
 
-void __global_restore_flags(unsigned long flags)
+unsigned long __global_save_flags(void)
 {
-       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();
+       unsigned long flags, local_enabled, retval;
+
+       __save_flags(flags);
+       local_enabled = ((flags == 0) ? 1 : 0);
+       retval = 2 + local_enabled;
+       if (! local_irq_count) {
+               if (local_enabled)
+                       retval = 1;
+               if (global_irq_holder == (unsigned char) smp_processor_id())
+                       retval = 0;
        }
+       return retval;
 }
 
-#undef INIT_STUCK
-#define INIT_STUCK 200000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
-
-void irq_enter(int cpu, int irq)
+void __global_restore_flags(unsigned long flags)
 {
-       int stuck = INIT_STUCK;
-
-       hardirq_enter(cpu);
-       while (*((volatile unsigned char *)&global_irq_lock)) {
-               if ((unsigned char) cpu == global_irq_holder)
-                       printk("irq_enter: Frosted Lucky Charms, "
-                              "they're magically delicious!\n");
-               STUCK;
-               membar("#LoadLoad");
+       switch (flags) {
+       case 0:
+               __global_cli();
+               break;
+       case 1:
+               __global_sti();
+               break;
+       case 2:
+               __cli();
+               break;
+       case 3:
+               __sti();
+               break;
+       default:
+       {
+               unsigned long pc;
+               __asm__ __volatile__("mov %%i7, %0" : "=r" (pc));
+               printk("global_restore_flags: Bogon flags(%016lx) caller %016lx\n",
+                      flags, pc);
        }
-}
-
-void irq_exit(int cpu, int irq)
-{
-       hardirq_exit(cpu);
-       release_irqlock(cpu);
-}
-
-void synchronize_irq(void)
-{
-       int local_count = local_irq_count;
-       unsigned long flags;
-
-       if (local_count != atomic_read(&global_irq_count)) {
-               save_and_cli(flags);
-               restore_flags(flags);
        }
 }
 
@@ -787,7+811,7 @@ void handler_irq(int irq, struct pt_regs *regs)
        /*
         * Check for TICK_INT on level 14 softint.
         */
-       if ((irq == 14) && get_softint() & (1UL << 0))
+       if ((irq == 14) && (get_softint() & (1UL << 0)))
                irq = 0;
 #endif
        clear_softint(1 << irq);
@@ -1004,12+1028,15 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
 /* Called from smp_commence, when we know how many cpus are in the system
  * and can have device IRQ's directed at them.
  */
+/* #define SMP_IRQ_VERBOSE */
 void distribute_irqs(void)
 {
        unsigned long flags;
        int cpu, level;
 
+#ifdef SMP_IRQ_VERBOSE
        printk("SMP: redistributing interrupts...\n");
+#endif
        save_and_cli(flags);
        cpu = 0;
        for(level = 0; level < NR_IRQS; level++) {
@@ -1020,16+1047,18 @@ void distribute_irqs(void)
                                struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
                                unsigned int *imap = __imap(bucket);
                                unsigned int val;
-                               unsigned long tid = __cpu_logical_map[cpu] << 9;
+                               unsigned long tid = __cpu_logical_map[cpu] << 26;
 
                                val = *imap;
                                *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
 
+#ifdef SMP_IRQ_VERBOSE
                                printk("SMP: Redirecting IGN[%x] INO[%x] "
                                       "to cpu %d [%s]\n",
                                       (val & SYSIO_IMAP_IGN) >> 6,
                                       (val & SYSIO_IMAP_INO), cpu,
                                       p->name);
+#endif
 
                                cpu++;
                                if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1)
@@ -1114,12+1143,17 @@ void enable_prom_timer(void)
 
 __initfunc(void init_IRQ(void))
 {
-       int i;
+       static int called = 0;
+
+       if (called == 0) {
+               int i;
 
-       map_prom_timers();
-       kill_prom_timer();
-       for(i = 0; i < NUM_IVECS; i++)
-               ivector_to_mask[i] = 0;
+               called = 1;
+               map_prom_timers();
+               kill_prom_timer();
+               for(i = 0; i < NUM_IVECS; i++)
+                       ivector_to_mask[i] = 0;
+       }
 
        /* We need to clear any IRQ's pending in the soft interrupt
         * registers, a spurious one could be left around from the
index 5dced02..c5c7061 100644 (file)
@@ -1,4+1,4 @@
-/*  $Id: process.c,v 1.75 1998/09/23 02:05:15 davem Exp $
+/*  $Id: process.c,v 1.82 1998/10/19 21:52:23 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -71,13+71,16 @@ asmlinkage int cpu_idle(void)
 {
        current->priority = 0;
        while(1) {
+               struct task_struct *p;
+
                check_pgt_cache();
                run_task_queue(&tq_scheduler);
-               barrier();
                current->counter = 0;
-               if(current->need_resched)
+               if (current->need_resched != 0 ||
+                   ((p = init_task.next_run) != NULL &&
+                    (p->processor == smp_processor_id() ||
+                     (p->tss.flags & SPARC_FLAG_NEWCHILD) != 0)))
                        schedule();
-               barrier();
        }
 }
 
@@ -386,12+389,32 @@ void exit_thread(void)
                else
                        current->tss.utraps[0]--;
        }
+
+       /* Turn off performance counters if on. */
+       if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+               current->tss.user_cntd0 =
+                       current->tss.user_cntd1 = NULL;
+               current->tss.pcr_reg = 0;
+               current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+               write_pcr(0);
+       }
 }
 
 void flush_thread(void)
 {
+       if (!(current->tss.flags & SPARC_FLAG_KTHREAD))
+               flush_user_windows();
        current->tss.w_saved = 0;
 
+       /* Turn off performance counters if on. */
+       if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+               current->tss.user_cntd0 =
+                       current->tss.user_cntd1 = NULL;
+               current->tss.pcr_reg = 0;
+               current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+               write_pcr(0);
+       }
+
        /* No new signal delivery by default. */
        current->tss.new_signal = 0;
        current->tss.fpsaved[0] = 0;
@@ -399,18+422,14 @@ void flush_thread(void)
        /* Now, this task is no longer a kernel thread. */
        current->tss.current_ds = USER_DS;
        if(current->tss.flags & SPARC_FLAG_KTHREAD) {
-               extern spinlock_t scheduler_lock;
-
                current->tss.flags &= ~SPARC_FLAG_KTHREAD;
 
                /* exec_mmap() set context to NO_CONTEXT, here is
                 * where we grab a new one.
                 */
-               spin_lock(&scheduler_lock);
                current->mm->cpu_vm_mask = 0;
                activate_context(current);
                current->mm->cpu_vm_mask = (1UL<<smp_processor_id());
-               spin_unlock(&scheduler_lock);
        }
        if (current->tss.flags & SPARC_FLAG_32BIT)
                __asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -524,7+543,6 @@ void fault_in_user_windows(struct pt_regs *regs)
        current->tss.w_saved = 0;
        return;
 barf:
-       lock_kernel();
        do_exit(SIGILL);
 }
 
@@ -552,7+570,19 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
        p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
        p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
        p->tss.fpsaved[0] = 0;
+       p->mm->segments = (void *) 0;
        if(regs->tstate & TSTATE_PRIV) {
+               /* Special case, if we are spawning a kernel thread from
+                * a userspace task (via KMOD, NFS, or similar) we must
+                * disable performance counters in the child because the
+                * address space and protection realm are changing.
+                */
+               if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+                       p->tss.user_cntd0 =
+                               p->tss.user_cntd1 = NULL;
+                       p->tss.pcr_reg = 0;
+                       p->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+               }
                p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
                p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD);
                p->tss.current_ds = KERNEL_DS;
index 149c893..0934b3a 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: psycho.c,v 1.64 1998/09/01 07:24:24 jj Exp $
+/* $Id: psycho.c,v 1.65 1998/10/20 14:41:28 ecd Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1639,17+1639,8 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev,
                return;
        }
 
-       /* See if we find a matching interrupt-map entry. */
-       if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
-               pdev->irq = psycho_irq_build(pbm, pdev,
-                                            (pbm->parent->upa_portid << 6)
-                                            | prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
-               dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
-                       prom_irq, pdev->irq);
-#endif
        /* See if fully specified already (ie. for onboard devices like hme) */
-       } else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
+       if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
                pdev->irq = psycho_irq_build(pbm, pdev, prom_irq);
 #ifdef FIXUP_IRQ_DEBUG
                dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
@@ -1664,6+1655,15 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev,
                dprintf("partially specified prom_irq[%x] pdev->irq[%x]",
                        prom_irq, pdev->irq);
 #endif
+       /* See if we find a matching interrupt-map entry. */
+       } else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
+               pdev->irq = psycho_irq_build(pbm, pdev,
+                                            (pbm->parent->upa_portid << 6)
+                                            | prom_irq);
+#ifdef FIXUP_IRQ_DEBUG
+               dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
+                       prom_irq, pdev->irq);
+#endif
        } else {
                unsigned int bus, slot, line;
 
index 07ee212..4063a1e 100644 (file)
@@ -43,6+43,12 @@ static pte_t *get_page(struct task_struct * tsk,
 
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
+
+       /* Seems non-intuitive but the page copy/clear routines always
+        * check current's value.
+        */
+       current->mm->segments = (void *) (addr & PAGE_SIZE);
+
        if (pgd_none(*pgdir)) {
                handle_mm_fault(tsk, vma, addr, write);
                goto repeat;
@@ -574,7+580,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                goto out;
        }
 #endif
-       if(!(child = find_task_by_pid(pid))) {
+       read_lock(&tasklist_lock);
+       child = find_task_by_pid(pid);
+       read_unlock(&tasklist_lock);
+
+       if(!child) {
                pt_error_return(regs, ESRCH);
                goto out;
        }
@@ -604,9+614,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                }
                child->flags |= PF_PTRACED;
                if(child->p_pptr != current) {
+                       unsigned long flags;
+
+                       write_lock_irqsave(&tasklist_lock, flags);
                        REMOVE_LINKS(child);
                        child->p_pptr = current;
                        SET_LINKS(child);
+                       write_unlock_irqrestore(&tasklist_lock, flags);
                }
                send_sig(SIGSTOP, child, 1);
                pt_succ_return(regs, 0);
@@ -781,11+795,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                        cregs->tnpc = npc;
                }
                cregs->y = y;
-               for(i = 1; i < 16; i++)
+               for(i = 1; i < 16; i++) {
                        if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
                                pt_error_return(regs, EFAULT);
                                goto out;
                        }
+               }
                pt_succ_return(regs, 0);
                goto out;
        }
@@ -814,11+829,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                        cregs->tnpc = tnpc;
                }
                cregs->y = y;
-               for(i = 1; i < 16; i++)
+               for(i = 1; i < 16; i++) {
                        if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
                                pt_error_return(regs, EFAULT);
                                goto out;
                        }
+               }
                pt_succ_return(regs, 0);
                goto out;
        }
@@ -1055,23+1071,29 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                        pt_succ_return(regs, 0);
                        goto out;
                }
-               wake_up_process(child);
                child->exit_code = SIGKILL;
+               wake_up_process(child);
                pt_succ_return(regs, 0);
                goto out;
        }
 
        case PTRACE_SUNDETACH: { /* detach a process that was attached. */
+               unsigned long flags;
+
                if ((unsigned long) data > _NSIG) {
                        pt_error_return(regs, EIO);
                        goto out;
                }
                child->flags &= ~(PF_PTRACED|PF_TRACESYS);
-               wake_up_process(child);
                child->exit_code = data;
+
+               write_lock_irqsave(&tasklist_lock, flags);
                REMOVE_LINKS(child);
                child->p_pptr = child->p_opptr;
                SET_LINKS(child);
+               write_unlock_irqrestore(&tasklist_lock, flags);
+
+               wake_up_process(child);
                pt_succ_return(regs, 0);
                goto out;
        }
index 4784b3c..0088d21 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: rtrap.S,v 1.40 1998/09/23 02:05:18 davem Exp $
+/* $Id: rtrap.S,v 1.44 1998/10/21 22:27:22 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -46,13+46,15 @@ rtrap:              sethi                   %hi(bh_active), %l2
                ldub                    [%l6 + %o0], %l2
                sub                     %l5, 2, %l5
                add                     %g6, AOFF_task_tss + AOFF_thread_gsr, %o1
-               andcc                   %l2, FPRS_FEF, %g0
+               andcc                   %l2, (FPRS_FEF|FPRS_DU), %g0
                be,pt                   %icc, 2f
                 and                    %l2, FPRS_DL, %l6
+               andcc                   %l2, FPRS_FEF, %g0
+               be,pn                   %icc, 5f
+                sll                    %o0, 3, %o5
                rd                      %fprs, %g5
                wr                      %g5, FPRS_FEF, %fprs
                ldub                    [%o1 + %o0], %g5
-               sll                     %o0, 3, %o5
                add                     %g6, AOFF_task_tss + AOFF_thread_xfsr, %o1
                membar                  #StoreLoad | #LoadLoad
                sll                     %o0, 8, %o2
@@ -130,25+132,49 @@ to_user:  ldx                     [%g6 + AOFF_task_need_resched], %l0
                 nop
                lduw                    [%g6 + AOFF_task_sigpending], %l0
 check_signal:  brz,a,pt                %l0, check_user_wins
-                lduh                   [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+                nop
                clr                     %o0
                mov                     %l5, %o2  
                mov                     %l6, %o3
                call                    do_signal
                 add                    %sp, STACK_BIAS + REGWIN_SZ, %o1
-               lduh                    [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
                clr                     %l6
-check_user_wins:brz,pt                 %o2, 1f
+
+               /* We must not take any traps between here and the actual
+                * return to user-space.  If we do we risk having windows
+                * saved to the thread struct between the test and the
+                * actual return from trap.  --DaveM
+                */
+check_user_wins:
+               wrpr                    %l7, 0x0, %pstate
+               lduh                    [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+               brz,pt                  %o2, 1f
                 sethi                  %hi(TSTATE_PEF), %l6
 
+               wrpr                    %l7, PSTATE_IE, %pstate
                call                    fault_in_user_windows
                 add                    %sp, STACK_BIAS + REGWIN_SZ, %o0
-
+               /* It is OK to leave interrupts on now because if
+                * fault_in_user_windows has returned it has left us
+                * with a clean user stack state.
+                */
 1:
 #if 0
                call                    rtrap_check
                 add                    %sp, STACK_BIAS + REGWIN_SZ, %o0
 #endif
+               lduh                    [%g6 + AOFF_task_tss + AOFF_thread_flags], %l5
+               andcc                   %l5, 0x200, %g0
+               be,pt                   %xcc, 1f
+                nop
+
+               /* Don't forget to preserve user window invariants. */
+               wrpr                    %l7, PSTATE_IE, %pstate
+               call                    update_perfctrs
+                nop
+               ba,a,pt                 %xcc, check_user_wins
+
+1:
                andcc                   %l1, %l6, %g0
                be,pt                   %xcc, rt_continue
                 stb                    %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
@@ -160,4+186,16 @@ check_user_wins:brz,pt                     %o2, 1f
                ba,pt                   %xcc, rt_continue+4
                 lduh                   [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
 
+5:             wr                      %g0, FPRS_FEF, %fprs
+               membar                  #StoreLoad | #LoadLoad
+               sll                     %o0, 8, %o2
+               add                     %g6, AOFF_task_fpregs+0x80, %o3
+               add                     %g6, AOFF_task_fpregs+0xc0, %o4
+               ldda                    [%o3 + %o2] ASI_BLK_P, %f32
+               ldda                    [%o4 + %o2] ASI_BLK_P, %f48
+1:             membar                  #Sync
+               wr                      %g0, FPRS_DU, %fprs
+               ba,pt                   %xcc, rt_continue
+                stb                    %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth]
+
 #undef PTREGS_OFF
index a7274ca..570322e 100644 (file)
@@ -1,4+1,4 @@
-/*  $Id: setup.c,v 1.32 1998/09/24 03:21:37 davem Exp $
+/*  $Id: setup.c,v 1.37 1998/10/14 15:49:09 ecd Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -62,38+62,207 @@ struct screen_info screen_info = {
  * prints out pretty messages and returns.
  */
 
-extern unsigned long sparc64_ttable_tl0;
 #if CONFIG_SUN_CONSOLE
 void (*prom_palette)(int);
 #endif
 asmlinkage void sys_sync(void);        /* it's really int */
 
+static void
+prom_console_write(struct console *con, const char *s, unsigned n)
+{
+       prom_printf("%s", s);
+}
+
+static struct console prom_console = {
+       "prom",
+       prom_console_write,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       CON_CONSDEV | CON_ENABLED,
+       -1,
+       0,
+       NULL
+};
+
+#define PROM_TRUE      -1
+#define PROM_FALSE     0
+
 /* Pretty sick eh? */
-void prom_sync_me(long *args)
+int prom_callback(long *args)
 {
-       unsigned long prom_tba, flags;
+       struct console *cons, *saved_console = NULL;
+       unsigned long flags;
+       char *cmd;
 
-       save_and_cli(flags);
-       __asm__ __volatile__("flushw; rdpr %%tba, %0\n\t" : "=r" (prom_tba));
-       __asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0));
+       if (!args)
+               return -1;
+       if (!(cmd = (char *)args[0]))
+               return -1;
 
-#ifdef CONFIG_SUN_CONSOLE
-       if (prom_palette)
-               prom_palette (1);
-#endif
-       prom_printf("PROM SYNC COMMAND...\n");
-       show_free_areas();
-       if(current->pid != 0) {
-               sti();
-               sys_sync();
-               cli();
+       save_and_cli(flags);
+       cons = console_drivers;
+       while (cons) {
+               unregister_console(cons);
+               cons->flags &= ~(CON_PRINTBUFFER);
+               cons->next = saved_console;
+               saved_console = cons;
+               cons = console_drivers;
        }
-       prom_printf("Returning to prom\n");
+       register_console(&prom_console);
+       if (!strcmp(cmd, "sync")) {
+               prom_printf("PROM `%s' command...\n", cmd);
+               show_free_areas();
+               if(current->pid != 0) {
+                       sti();
+                       sys_sync();
+                       cli();
+               }
+               args[2] = 0;
+               args[args[1] + 3] = -1;
+               prom_printf("Returning to PROM\n");
+       } else if (!strcmp(cmd, "va>tte-data")) {
+               unsigned long ctx, va;
+               unsigned long tte = 0;
+               long res = PROM_FALSE;
+
+               ctx = args[3];
+               va = args[4];
+               if (ctx) {
+                       /*
+                        * Find process owning ctx, lookup mapping.
+                        */
+                       struct task_struct *p;
+                       pgd_t *pgdp;
+                       pmd_t *pmdp;
+                       pte_t *ptep;
+
+                       for_each_task(p)
+                               if (p->tss.ctx == ctx)
+                                       break;
+                       if (p->tss.ctx != ctx)
+                               goto done;
+
+                       pgdp = pgd_offset(p->mm, va);
+                       if (pgd_none(*pgdp))
+                               goto done;
+                       pmdp = pmd_offset(pgdp, va);
+                       if (pmd_none(*pmdp))
+                               goto done;
+                       ptep = pte_offset(pmdp, va);
+                       if (!pte_present(*ptep))
+                               goto done;
+                       tte = pte_val(*ptep);
+                       res = PROM_TRUE;
+                       goto done;
+               }
 
-       __asm__ __volatile__("flushw; wrpr %0, 0x0, %%tba\n\t" : : "r" (prom_tba));
-       restore_flags(flags);
+               if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
+                       /*
+                        * Locked down tlb entry 63.
+                        */
+                       tte = spitfire_get_dtlb_data(63);
+                       res = PROM_TRUE;
+                       goto done;
+               }
+
+               if (va < PGDIR_SIZE) {
+                       /*
+                        * vmalloc or prom_inherited mapping.
+                        */
+                       pgd_t *pgdp;
+                       pmd_t *pmdp;
+                       pte_t *ptep;
+
+                       pgdp = pgd_offset_k(va);
+                       if (pgd_none(*pgdp))
+                               goto done;
+                       pmdp = pmd_offset(pgdp, va);
+                       if (pmd_none(*pmdp))
+                               goto done;
+                       ptep = pte_offset(pmdp, va);
+                       if (!pte_present(*ptep))
+                               goto done;
+                       tte = pte_val(*ptep);
+                       res = PROM_TRUE;
+                       goto done;
+               }
+
+               if (va < PAGE_OFFSET) {
+                       /*
+                        * No mappings here.
+                        */
+                       goto done;
+               }
 
-       return;
+               if (va & (1UL << 40)) {
+                       /*
+                        * I/O page.
+                        */
+
+                       tte = (__pa(va) & _PAGE_PADDR) |
+                             _PAGE_VALID | _PAGE_SZ4MB |
+                             _PAGE_E | _PAGE_P | _PAGE_W;
+                       res = PROM_TRUE;
+                       goto done;
+               }
+
+               /*
+                * Normal page.
+                */
+               tte = (__pa(va) & _PAGE_PADDR) |
+                     _PAGE_VALID | _PAGE_SZ4MB |
+                     _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W;
+               res = PROM_TRUE;
+
+       done:
+               if (res == PROM_TRUE) {
+                       args[2] = 3;
+                       args[args[1] + 3] = 0;
+                       args[args[1] + 4] = res;
+                       args[args[1] + 5] = tte;
+               } else {
+                       args[2] = 2;
+                       args[args[1] + 3] = 0;
+                       args[args[1] + 4] = res;
+               }
+       } else if (!strcmp(cmd, ".soft1")) {
+               unsigned long tte;
+
+               tte = args[3];
+               prom_printf("%lx:\"%s%s%s%s%s\" ",
+                           (tte & _PAGE_SOFT) >> 7,
+                           tte & _PAGE_MODIFIED ? "M" : "-",
+                           tte & _PAGE_ACCESSED ? "A" : "-",
+                           tte & _PAGE_READ     ? "W" : "-",
+                           tte & _PAGE_WRITE    ? "R" : "-",
+                           tte & _PAGE_PRESENT  ? "P" : "-");
+
+               args[2] = 2;
+               args[args[1] + 3] = 0;
+               args[args[1] + 4] = PROM_TRUE;
+       } else if (!strcmp(cmd, ".soft2")) {
+               unsigned long tte;
+
+               tte = args[3];
+               prom_printf("%lx ", (tte & _PAGE_SOFT2) >> 50);
+
+               args[2] = 2;
+               args[args[1] + 3] = 0;
+               args[args[1] + 4] = PROM_TRUE;
+       } else {
+               prom_printf("unknown PROM `%s' command...\n", cmd);
+       }
+       unregister_console(&prom_console);
+       while (saved_console) {
+               cons = saved_console;
+               saved_console = cons->next;
+               register_console(cons);
+       }
+       restore_flags(flags);
+       return 0;
 }
 
 extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
@@ -250,28+419,6 @@ static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
 
 extern struct consw sun_serial_con;
 
-#ifdef PROM_DEBUG_CONSOLE
-static void
-prom_console_write(struct console *con, const char *s, unsigned n)
-{
-       prom_printf("%s", s);
-}
-
-static struct console prom_console = {
-       "prom",
-       prom_console_write,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       CON_PRINTBUFFER,
-       -1,
-       0,
-       NULL
-};
-#endif
-
 __initfunc(void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
@@ -279,10+426,6 @@ __initfunc(void setup_arch(char **cmdline_p,
        unsigned long lowest_paddr, end_of_phys_memory = 0;
        int total, i;
 
-#ifdef PROM_DEBUG_CONSOLE
-       register_console(&prom_console);
-#endif
-
        /* Initialize PROM console and command line. */
        *cmdline_p = prom_getbootargs();
        strcpy(saved_command_line, *cmdline_p);
@@ -316,7+459,13 @@ __initfunc(void setup_arch(char **cmdline_p,
                        }
                }
        }
-       prom_setsync(prom_sync_me);
+       prom_setcallback(prom_callback);
+       prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
+                  "' linux-va>tte-data to va>tte-data");
+       prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
+                  "' linux-.soft1 to .soft1");
+       prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
+                  "' linux-.soft2 to .soft2");
 
        /* In paging_init() we tip off this value to see if we need
         * to change init_mm.pgd to point to the real alias mapping.
@@ -439,8+588,6 @@ extern int smp_info(char *);
 extern int smp_bogo(char *);
 extern int mmu_info(char *);
 
-unsigned long dcache_aliases_found = 0;
-
 int get_cpuinfo(char *buffer)
 {
        int cpuid=smp_processor_id();
@@ -454,7+601,6 @@ int get_cpuinfo(char *buffer)
             "type\t\t: sun4u\n"
            "ncpus probed\t: %d\n"
            "ncpus active\t: %d\n"
-           "d-aliases\t: %lu\n"
 #ifndef __SMP__
             "BogoMips\t: %lu.%02lu\n"
 #endif
@@ -462,7+608,7 @@ int get_cpuinfo(char *buffer)
             sparc_cpu_type[cpuid],
             sparc_fpu_type[cpuid],
             prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
-           linux_num_cpus, smp_num_cpus, dcache_aliases_found
+           linux_num_cpus, smp_num_cpus
 #ifndef __SMP__
             , loops_per_sec/500000, (loops_per_sec/5000) % 100
 #endif
index 3fc95ad..91dc722 100644 (file)
@@ -1,4+1,4 @@
-/*  $Id: signal.c,v 1.37 1998/09/25 01:09:22 davem Exp $
+/*  $Id: signal.c,v 1.38 1998/10/16 03:19:04 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -53,7+53,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
        unsigned char fenab;
        int err;
 
-       __asm__ __volatile__("flushw");
+       flush_user_windows();
        if(tp->w_saved                                          ||
           (((unsigned long)ucp) & (sizeof(unsigned long)-1))   ||
           (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
index a8f0c2f..d425132 100644 (file)
@@ -1,4+1,4 @@
-/*  $Id: signal32.c,v 1.44 1998/09/25 01:09:17 davem Exp $
+/*  $Id: signal32.c,v 1.47 1998/10/13 09:07:40 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -76,6+76,9 @@ struct new_signal_frame32 {
        /* __siginfo_fpu32_t * */ u32 fpu_save;
        unsigned int            insns [2];
        unsigned                extramask[_NSIG_WORDS32 - 1];
+       unsigned                extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
+       /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
+       siginfo_extra_v8plus_t  v8plus;
        __siginfo_fpu_t         fpu_state;
 };
 
@@ -87,6+90,9 @@ struct rt_signal_frame32 {
        /* __siginfo_fpu32_t * */ u32 fpu_save;
        unsigned int            insns [2];
        stack_t32               stack;
+       unsigned                extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
+       /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
+       siginfo_extra_v8plus_t  v8plus;
        __siginfo_fpu_t         fpu_state;
 };
 
@@ -209,7+215,7 @@ void do_new_sigreturn32(struct pt_regs *regs)
        unsigned pc, npc, fpu_save;
        sigset_t set;
        unsigned seta[_NSIG_WORDS32];
-       int err;
+       int err, i;
        
        regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
        sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
@@ -232,24+238,18 @@ void do_new_sigreturn32(struct pt_regs *regs)
        err = __get_user(regs->y, &sf->info.si_regs.y);
        err |= __get_user(psr, &sf->info.si_regs.psr);
 
-       err |= __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]);
-       err |= __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]);
-       err |= __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]);
-       err |= __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]);
-       err |= __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]);
-       err |= __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]);
-       err |= __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]);
-       err |= __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]);
-       err |= __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]);
-       err |= __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]);
-       err |= __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]);
-       err |= __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]);
-       err |= __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]);
-       err |= __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]);
-       err |= __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]);
+       for (i = UREG_G1; i <= UREG_I7; i++)
+               err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+       if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
+               err |= __get_user(i, &sf->v8plus.g_upper[0]);
+               if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
+                       for (i = UREG_G1; i <= UREG_I7; i++)
+                               err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+               }
+       }
 
        /* User can only change condition codes in %tstate. */
-       regs->tstate &= ~(TSTATE_ICC);
+       regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
        regs->tstate |= psr_to_tstate_icc(psr);
 
        err |= __get_user(fpu_save, &sf->fpu_save);
@@ -273,7+273,6 @@ void do_new_sigreturn32(struct pt_regs *regs)
        return;
 
 segv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -329,12+328,11 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
        err |= __get_user(psr, &scptr->sigc_psr);
        if (err)
                goto segv;
-       regs->tstate &= ~(TSTATE_ICC);
+       regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
        regs->tstate |= psr_to_tstate_icc(psr);
        return;
 
 segv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -346,7+344,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
        sigset_t set;
        sigset_t32 seta;
        stack_t st;
-       int err;
+       int err, i;
        
        synchronize_user_stack();
        regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
@@ -369,25+367,19 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
        /* 2. Restore the state */
        err = __get_user(regs->y, &sf->regs.y);
        err |= __get_user(psr, &sf->regs.psr);
-
-       err |= __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]);
-       err |= __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]);
-       err |= __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]);
-       err |= __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]);
-       err |= __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]);
-       err |= __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]);
-       err |= __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]);
-       err |= __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]);
-       err |= __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]);
-       err |= __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]);
-       err |= __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]);
-       err |= __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]);
-       err |= __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]);
-       err |= __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]);
-       err |= __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]);
+       
+       for (i = UREG_G1; i <= UREG_I7; i++)
+               err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+       if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
+               err |= __get_user(i, &sf->v8plus.g_upper[0]);
+               if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
+                       for (i = UREG_G1; i <= UREG_I7; i++)
+                               err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+               }
+       }
 
        /* User can only change condition codes in %tstate. */
-       regs->tstate &= ~(TSTATE_ICC);
+       regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
        regs->tstate |= psr_to_tstate_icc(psr);
 
        err |= __get_user(fpu_save, &sf->fpu_save);
@@ -417,7+409,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
        spin_unlock_irq(&current->sigmask_lock);
        return;
 segv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -472,7+463,6 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
                /* Don't change signal code and address, so that
                 * post mortem debuggers can have a look.
                 */
-               lock_kernel ();
                do_exit(SIGILL);
        }
 
@@ -544,7+534,6 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        return;
 
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -614,6+603,10 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
        err |= __put_user(psr, &sf->info.si_regs.psr);
        for (i = 0; i < 16; i++)
                err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+       err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
+       err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
+       for (i = 1; i < 16; i++)
+               err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
 
        if (psr & PSR_EF) {
                err |= save_fpu_state32(regs, &sf->fpu_state);
@@ -682,10+675,8 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
        return;
 
 sigill:
-       lock_kernel();
        do_exit(SIGILL);
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -717,7+708,6 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
 #ifdef DEBUG_SIGNALS
                printk ("Invalid stack frame\n");
 #endif
-               lock_kernel ();
                do_exit(SIGILL);
        }
 
@@ -833,7+823,6 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        return;
 
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -850,7+839,6 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
        
        if (current->tss.w_saved){
                printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved);
-               lock_kernel();
                do_exit (SIGSEGV);
        }
        err = clear_user(uc, sizeof (*uc));
@@ -968,7+956,7 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
        regs->tnpc = npc | 1;
        err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
        err |= __get_user(psr, &((*gr) [SVR4_PSR]));
-       regs->tstate &= ~(TSTATE_ICC);
+       regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
        regs->tstate |= psr_to_tstate_icc(psr);
 #if 0  
        if(psr & PSR_EF)
@@ -984,7+972,6 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
 
        return -EINTR;
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -1034,6+1021,10 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
        err |= __put_user(psr, &sf->regs.psr);
        for (i = 0; i < 16; i++)
                err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+       err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
+       err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
+       for (i = 1; i < 16; i++)
+               err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
 
        if (psr & PSR_EF) {
                err |= save_fpu_state32(regs, &sf->fpu_state);
@@ -1107,10+1098,8 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
        return;
 
 sigill:
-       lock_kernel();
        do_exit(SIGILL);
 sigsegv:
-       lock_kernel();
        do_exit(SIGSEGV);
 }
 
@@ -1304,14+1293,19 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
                        case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
                                if(current->binfmt && current->binfmt->core_dump) {
                                        lock_kernel();
-                                       if(current->binfmt->core_dump(signr, regs))
+                                       if(current->binfmt &&
+                                          current->binfmt->core_dump &&
+                                          current->binfmt->core_dump(signr, regs))
                                                exit_code |= 0x80;
                                        unlock_kernel();
                                }
 #ifdef DEBUG_SIGNALS
                                /* Very useful to debug dynamic linker problems */
                                printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
-                               show_regs (regs);
+                               /* On SMP we are only interested in the current
+                                * CPU's registers.
+                                */
+                               __show_regs (regs);
 #ifdef DEBUG_SIGNALS_TLB
                                do {
                                        extern void sparc_ultra_dump_itlb(void);
index c9e5495..4bdfca1 100644 (file)
@@ -41,7+41,9 @@ int smp_threads_ready = 0;
 
 struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
 
-static unsigned char boot_cpu_id __initdata = 0;
+/* Please don't make this initdata!!!  --DaveM */
+static unsigned char boot_cpu_id = 0;
+
 static int smp_activated = 0;
 
 volatile int cpu_number_map[NR_CPUS];
@@ -82,12+84,16 @@ int smp_bogo(char *buf)
 
 __initfunc(void smp_store_cpu_info(int id))
 {
-       cpu_data[id].udelay_val                 = loops_per_sec;
        cpu_data[id].irq_count                  = 0;
+       cpu_data[id].bh_count                   = 0;
+       /* multiplier and counter set by
+          smp_setup_percpu_timer()  */
+       cpu_data[id].udelay_val                 = loops_per_sec;
+
        cpu_data[id].pgcache_size               = 0;
+       cpu_data[id].pte_cache                  = NULL;
        cpu_data[id].pgdcache_size              = 0;
        cpu_data[id].pgd_cache                  = NULL;
-       cpu_data[id].pte_cache                  = NULL;
 }
 
 extern void distribute_irqs(void);
@@ -137,6+143,11 @@ __initfunc(void smp_callin(void))
        __asm__ __volatile__("membar #Sync\n\t"
                             "flush  %%g6" : : : "memory");
 
+       /* Clear this or we will die instantly when we
+        * schedule back to this idler...
+        */
+       current->tss.flags &= ~(SPARC_FLAG_NEWCHILD);
+
        while(!smp_processors_ready)
                membar("#LoadLoad");
 }
@@ -396,6+407,8 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 {
        u32 ctx = mm->context & 0x3ff;
 
+       start &= PAGE_MASK;
+       end   &= PAGE_MASK;
        if(mm == current->mm && atomic_read(&mm->count) == 1) {
                if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
                        goto local_flush_and_out;
@@ -404,8+417,6 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
        smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
 
 local_flush_and_out:
-       start &= PAGE_MASK;
-       end &= PAGE_MASK;
        __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start));
 }
 
@@ -413,6+424,7 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
 {
        u32 ctx = mm->context & 0x3ff;
 
+       page &= PAGE_MASK;
        if(mm == current->mm && atomic_read(&mm->count) == 1) {
                if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
                        goto local_flush_and_out;
@@ -433,11+445,11 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
        smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
 
 local_flush_and_out:
-       __flush_tlb_page(ctx, (page & PAGE_MASK), SECONDARY_CONTEXT);
+       __flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
 }
 
 /* CPU capture. */
-#define CAPTURE_DEBUG
+/* #define CAPTURE_DEBUG */
 extern unsigned long xcall_capture;
 
 static atomic_t smp_capture_depth = ATOMIC_INIT(0);
@@ -446,37+458,42 @@ static unsigned long penguins_are_doing_time = 0;
 
 void smp_capture(void)
 {
-       int result = atomic_add_return(1, &smp_capture_depth);
+       if (smp_processors_ready) {
+               int result = atomic_add_return(1, &smp_capture_depth);
 
-       membar("#StoreStore | #LoadStore");
-       if(result == 1) {
-               int ncpus = smp_num_cpus;
+               membar("#StoreStore | #LoadStore");
+               if(result == 1) {
+                       int ncpus = smp_num_cpus;
 
 #ifdef CAPTURE_DEBUG
-               printk("CPU[%d]: Sending penguins to jail...", smp_processor_id());
+                       printk("CPU[%d]: Sending penguins to jail...",
+                              smp_processor_id());
 #endif
-               penguins_are_doing_time = 1;
-               membar("#StoreStore | #LoadStore");
-               atomic_inc(&smp_capture_registry);
-               smp_cross_call(&xcall_capture, 0, 0, 0);
-               while(atomic_read(&smp_capture_registry) != ncpus)
-                       membar("#LoadLoad");
+                       penguins_are_doing_time = 1;
+                       membar("#StoreStore | #LoadStore");
+                       atomic_inc(&smp_capture_registry);
+                       smp_cross_call(&xcall_capture, 0, 0, 0);
+                       while(atomic_read(&smp_capture_registry) != ncpus)
+                               membar("#LoadLoad");
 #ifdef CAPTURE_DEBUG
-               printk("done\n");
+                       printk("done\n");
 #endif
+               }
        }
 }
 
 void smp_release(void)
 {
-       if(atomic_dec_and_test(&smp_capture_depth)) {
+       if(smp_processors_ready) {
+               if(atomic_dec_and_test(&smp_capture_depth)) {
 #ifdef CAPTURE_DEBUG
-               printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
-                      smp_processor_id());
+                       printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
+                              smp_processor_id());
 #endif
-               penguins_are_doing_time = 0;
-               membar("#StoreStore | #StoreLoad");
-               atomic_dec(&smp_capture_registry);
+                       penguins_are_doing_time = 0;
+                       membar("#StoreStore | #StoreLoad");
+                       atomic_dec(&smp_capture_registry);
+               }
        }
 }
 
@@ -539,8+556,12 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
                if(!--prof_counter(cpu))
                {
                        if (cpu == boot_cpu_id) {
-                               extern void irq_enter(int, int);
-                               extern void irq_exit(int, int);
+/* XXX Keep this in sync with irq.c --DaveM */
+#define irq_enter(cpu, irq)                    \
+do {   hardirq_enter(cpu);                     \
+       spin_unlock_wait(&global_irq_lock);     \
+} while(0)
+#define irq_exit(cpu, irq)     hardirq_exit(cpu)
 
                                irq_enter(cpu, 0);
                                kstat.irqs[cpu][0]++;
@@ -548,6+569,9 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
                                timer_tick_interrupt(regs);
 
                                irq_exit(cpu, 0);
+
+#undef irq_enter
+#undef irq_exit
                        }
 
                        if(current->pid) {
index d06b749..d68f489 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.42 1998/10/05 03:18:50 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.48 1998/10/20 03:09:08 jj Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/sched.h>
 #include <linux/in6.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
 
 #include <asm/oplib.h>
 #include <asm/delay.h>
@@ -55,7+57,6 @@ extern void die_if_kernel(char *str, struct pt_regs *regs);
 extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
                                unsigned long, unsigned long, unsigned long);
 void _sigpause_common (unsigned int set, struct pt_regs *);
-extern void *__bzero_1page(void *);
 extern void *__bzero(void *, size_t);
 extern void *__bzero_noasi(void *, size_t);
 extern void *__memscan_zero(void *, size_t);
@@ -63,6+64,7 @@ extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 extern __kernel_size_t __strlen(const char *);
+extern __kernel_size_t strlen(const char *);
 extern char saved_command_line[];
 extern char *getname32(u32 name);
 extern void linux_sparc_syscall(void);
@@ -87,6+89,17 @@ extern void dump_thread(struct pt_regs *, struct user *);
 
 #ifdef __SMP__
 extern spinlock_t scheduler_lock;
+extern spinlock_t kernel_flag;
+extern int smp_num_cpus;
+#ifdef SPIN_LOCK_DEBUG
+extern void _do_spin_lock (spinlock_t *lock, char *str);
+extern void _do_spin_unlock (spinlock_t *lock);
+extern int _spin_trylock (spinlock_t *lock);
+extern void _do_read_lock(rwlock_t *rw, char *str);
+extern void _do_read_unlock(rwlock_t *rw, char *str);
+extern void _do_write_lock(rwlock_t *rw, char *str);
+extern void _do_write_unlock(rwlock_t *rw);
+#endif
 #endif
 
 /* One thing to note is that the way the symbols of the mul/div
@@ -102,19+115,46 @@ __attribute__((section("__ksymtab"))) =                           \
 
 /* used by various drivers */
 #ifdef __SMP__
+/* Kernel wide locking */
 EXPORT_SYMBOL(scheduler_lock);
+EXPORT_SYMBOL(kernel_flag);
+
+/* Software-IRQ BH locking */
 EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(synchronize_bh);
+
+/* Hard IRQ locking */
 EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
 EXPORT_SYMBOL(synchronize_irq);
-EXPORT_SYMBOL(cpu_data);
 EXPORT_SYMBOL_PRIVATE(global_cli);
 EXPORT_SYMBOL_PRIVATE(global_sti);
+EXPORT_SYMBOL_PRIVATE(global_save_flags);
 EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+
+/* Per-CPU information table */
+EXPORT_SYMBOL(cpu_data);
+
+/* Misc SMP information */
+EXPORT_SYMBOL(smp_num_cpus);
+
+/* Spinlock debugging library, optional. */
+#ifdef SPIN_LOCK_DEBUG
+EXPORT_SYMBOL(_do_spin_lock);
+EXPORT_SYMBOL(_do_spin_unlock);
+EXPORT_SYMBOL(_spin_trylock);
+EXPORT_SYMBOL(_do_read_lock);
+EXPORT_SYMBOL(_do_read_unlock);
+EXPORT_SYMBOL(_do_write_lock);
+EXPORT_SYMBOL(_do_write_unlock);
+#endif
+
 #else
 EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(local_bh_count);
 #endif
-EXPORT_SYMBOL_PRIVATE(_lock_kernel);
-EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 
@@ -124,7+164,6 @@ EXPORT_SYMBOL(mstk48t02_regs);
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(__sparc64_bh_counter);
 EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
 EXPORT_SYMBOL(mmu_get_scsi_sgl);
 EXPORT_SYMBOL(mmu_get_scsi_one);
@@ -185,6+224,9 @@ EXPORT_SYMBOL(__prom_getsibling);
 /* sparc library symbols */
 EXPORT_SYMBOL(bcopy);
 EXPORT_SYMBOL(__strlen);
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
+EXPORT_SYMBOL(strlen);
+#endif
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
@@ -220,7+262,7 @@ EXPORT_SYMBOL(sys32_ioctl);
 /* Special internal versions of library functions. */
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memset);
-EXPORT_SYMBOL(__bzero_1page);
+EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(__bzero);
 EXPORT_SYMBOL(__memscan_zero);
 EXPORT_SYMBOL(__memscan_generic);
index 8e0269d..08ce072 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sys_sparc.c,v 1.22 1998/09/25 01:09:27 davem Exp $
+/* $Id: sys_sparc.c,v 1.25 1998/10/21 03:21:15 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 #include <asm/utrap.h>
+#include <asm/perfctr.h>
 
 /* XXX Make this per-binary type, this way we can detect the type of
  * XXX a binary.  Every Sparc executable calls this very early on.
@@ -151,6+152,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
        struct file * file = NULL;
        unsigned long retval = -EBADF;
 
+       down(&current->mm->mmap_sem);
        lock_kernel();
        if (!(flags & MAP_ANONYMOUS)) {
                file = fget(fd);
@@ -189,6+191,7 @@ out_putf:
                fput(file);
 out:
        unlock_kernel();
+       up(&current->mm->mmap_sem);
        return retval;
 }
 
@@ -378,3+381,105 @@ sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
 
        return ret;
 }
+
+/* Invoked by rtrap code to update performance counters in
+ * user space.
+ */
+asmlinkage void
+update_perfctrs(void)
+{
+       unsigned long pic, tmp;
+
+       read_pic(pic);
+       tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
+       __put_user(tmp, current->tss.user_cntd0);
+       tmp = (current->tss.kernel_cntd1 += (pic >> 32));
+       __put_user(tmp, current->tss.user_cntd1);
+       reset_pic();
+}
+
+asmlinkage int
+sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2)
+{
+       int err = 0;
+
+       switch(opcode) {
+       case PERFCTR_ON:
+               current->tss.pcr_reg = arg2;
+               current->tss.user_cntd0 = (u64 *) arg0;
+               current->tss.user_cntd1 = (u64 *) arg1;
+               current->tss.kernel_cntd0 =
+                       current->tss.kernel_cntd1 = 0;
+               write_pcr(arg2);
+               reset_pic();
+               current->tss.flags |= SPARC_FLAG_PERFCTR;
+               break;
+
+       case PERFCTR_OFF:
+               err = -EINVAL;
+               if ((current->tss.flags & SPARC_FLAG_PERFCTR) != 0) {
+                       current->tss.user_cntd0 =
+                               current->tss.user_cntd1 = NULL;
+                       current->tss.pcr_reg = 0;
+                       write_pcr(0);
+                       current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+                       err = 0;
+               }
+               break;
+
+       case PERFCTR_READ: {
+               unsigned long pic, tmp;
+
+               if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+                       err = -EINVAL;
+                       break;
+               }
+               read_pic(pic);
+               tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
+               err |= __put_user(tmp, current->tss.user_cntd0);
+               tmp = (current->tss.kernel_cntd1 += (pic >> 32));
+               err |= __put_user(tmp, current->tss.user_cntd1);
+               reset_pic();
+               break;
+       }
+
+       case PERFCTR_CLRPIC:
+               if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+                       err = -EINVAL;
+                       break;
+               }
+               current->tss.kernel_cntd0 =
+                       current->tss.kernel_cntd1 = 0;
+               reset_pic();
+               break;
+
+       case PERFCTR_SETPCR: {
+               u64 *user_pcr = (u64 *)arg0;
+               if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+                       err = -EINVAL;
+                       break;
+               }
+               err |= __get_user(current->tss.pcr_reg, user_pcr);
+               write_pcr(current->tss.pcr_reg);
+               current->tss.kernel_cntd0 =
+                       current->tss.kernel_cntd1 = 0;
+               reset_pic();
+               break;
+       }
+
+       case PERFCTR_GETPCR: {
+               u64 *user_pcr = (u64 *)arg0;
+               if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+                       err = -EINVAL;
+                       break;
+               }
+               err |= __put_user(current->tss.pcr_reg, user_pcr);
+               break;
+       }
+
+       default:
+               err = -EINVAL;
+               break;
+       };
+       return err;
+}
index 7d80404..bca09a5 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sys_sparc32.c,v 1.95 1998/09/07 09:20:50 davem Exp $
+/* $Id: sys_sparc32.c,v 1.98 1998/10/26 20:01:11 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -224,9+224,6 @@ struct shmid_ds32 {
         __kernel_ipc_pid_t32    shm_cpid; 
         __kernel_ipc_pid_t32    shm_lpid; 
         unsigned short          shm_nattch;
-        unsigned short          shm_npages;
-        u32                    shm_pages;
-        u32                    attaches; 
 };
                                                         
 /*
@@ -1394,7+1391,7 @@ asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned
                else if(is_smb)
                        do_smb_super_data_conv((void *)data_page);
                else
-                       panic("Tell DaveM he fucked up...");
+                       panic("The problem is here...");
                old_fs = get_fs();
                set_fs(KERNEL_DS);
                err = sys_mount((char *)dev_page, (char *)dir_page,
@@ -2707,10+2704,53 @@ struct module_info32 {
 
 /* Query various bits about modules.  */
 
-extern long get_mod_name(const char *user_name, char **buf);
-extern void put_mod_name(char *buf);
-extern struct module *find_module(const char *name);
-extern struct module kernel_module;
+static inline long
+get_mod_name(const char *user_name, char **buf)
+{
+       unsigned long page;
+       long retval;
+
+       if ((unsigned long)user_name >= TASK_SIZE
+           && !segment_eq(get_fs (), KERNEL_DS))
+               return -EFAULT;
+
+       page = __get_free_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
+
+       retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
+       if (retval > 0) {
+               if (retval < PAGE_SIZE) {
+                       *buf = (char *)page;
+                       return retval;
+               }
+               retval = -ENAMETOOLONG;
+       } else if (!retval)
+               retval = -EINVAL;
+
+       free_page(page);
+       return retval;
+}
+
+static inline void
+put_mod_name(char *buf)
+{
+       free_page((unsigned long)buf);
+}
+
+static __inline__ struct module *find_module(const char *name)
+{
+       struct module *mod;
+
+       for (mod = module_list; mod ; mod = mod->next) {
+               if (mod->flags & MOD_DELETED)
+                       continue;
+               if (!strcmp(mod->name, name))
+                       break;
+       }
+
+       return mod;
+}
 
 static int
 qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
@@ -2720,7+2760,7 @@ qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
 
        nmod = space = 0;
 
-       for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) {
+       for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) {
                len = strlen(mod->name)+1;
                if (len > bufsize)
                        goto calc_space_needed;
@@ -2738,7+2778,7 @@ qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
 
 calc_space_needed:
        space += len;
-       while ((mod = mod->next) != &kernel_module)
+       while ((mod = mod->next)->next != NULL)
                space += strlen(mod->name)+1;
 
        if (put_user(space, ret))
@@ -2752,7+2792,7 @@ qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
 {
        size_t i, space, len;
 
-       if (mod == &kernel_module)
+       if (mod->next == NULL)
                return -EINVAL;
        if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
                if (put_user(0, ret))
@@ -2796,7+2836,7 @@ qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
        size_t nrefs, space, len;
        struct module_ref *ref;
 
-       if (mod == &kernel_module)
+       if (mod->next == NULL)
                return -EINVAL;
        if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
                if (put_user(0, ret))
@@ -2898,7+2938,7 @@ qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
 {
        int error = 0;
 
-       if (mod == &kernel_module)
+       if (mod->next == NULL)
                return -EINVAL;
 
        if (sizeof(struct module_info32) <= bufsize) {
@@ -2926,9+2966,11 @@ asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kerne
        int err;
 
        lock_kernel();
-       if (name_user == 0)
-               mod = &kernel_module;
-       else {
+       if (name_user == 0) {
+               /* This finds "kernel_module" which is not exported. */
+               for(mod = module_list; mod->next != NULL; mod = mod->next)
+                       ;
+       } else {
                long namelen;
                char *name;
 
@@ -2937,9+2979,11 @@ asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kerne
                        goto out;
                }
                err = -ENOENT;
-               if (namelen == 0)
-                       mod = &kernel_module;
-               else if ((mod = find_module(name)) == NULL) {
+               if (namelen == 0) {
+                       /* This finds "kernel_module" which is not exported. */
+                       for(mod = module_list; mod->next != NULL; mod = mod->next)
+                               ;
+               } else if ((mod = find_module(name)) == NULL) {
                        put_mod_name(name);
                        goto out;
                }
index c0cc42c..82701cc 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sys_sunos32.c,v 1.18 1998/08/31 03:41:01 davem Exp $
+/* $Id: sys_sunos32.c,v 1.22 1998/10/26 20:01:13 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6+68,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
        struct file *file = NULL;
        unsigned long retval, ret_type;
 
+       down(&current->mm->mmap_sem);
        lock_kernel();
        current->personality |= PER_BSD;
        if(flags & MAP_NORESERVE) {
@@ -117,6+118,7 @@ out_putf:
                fput(file);
 out:
        unlock_kernel();
+       up(&current->mm->mmap_sem);
        return (u32) retval;
 }
 
@@ -131,6+133,7 @@ asmlinkage int sunos_brk(u32 baddr)
        unsigned long rlim;
        unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
 
+       down(&current->mm->mmap_sem);
        lock_kernel();
        if (brk < current->mm->end_code)
                goto out;
@@ -178,6+181,7 @@ asmlinkage int sunos_brk(u32 baddr)
        retval = 0;
 out:
        unlock_kernel();
+       up(&current->mm->mmap_sem);
        return retval;
 }
 
@@ -538,27+542,17 @@ struct sunos_utsname {
        char mach[9];
 };
 
-asmlinkage int sunos_uname(u32 u_name)
+asmlinkage int sunos_uname(struct sunos_utsname *name)
 {
-       struct sunos_utsname *name = (struct sunos_utsname *)A(u_name);
-       int ret = -EFAULT;
+       int ret;
 
        down(&uts_sem);
-       if(!name)
-               goto out;
-       if(copy_to_user(&name->sname[0],
-                       &system_utsname.sysname[0],
-                       sizeof(name->sname) - 1))
-               goto out;
-       copy_to_user(&name->nname[0],
-                    &system_utsname.nodename[0],
-                    sizeof(name->nname) - 1);
-       put_user('\0', &name->nname[8]);
-       copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
-       copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
-       copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
-       ret = 0;
-out:
+       ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
+       ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
+       ret |= put_user('\0', &name->nname[8]);
+       ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+       ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+       ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
        up(&uts_sem);
        return ret;
 }
@@ -837,6+831,8 @@ sunos_mount(char *type, char *dir, int flags, void *data)
        int ret = -EINVAL;
        char *dev_fname = 0;
 
+       if (!capable (CAP_SYS_ADMIN))
+               return -EPERM;
        lock_kernel();
        /* We don't handle the integer fs type */
        if ((flags & SMNT_NEWTYPE) == 0)
@@ -1211,9+1207,6 @@ struct shmid_ds32 {
         __kernel_ipc_pid_t32    shm_cpid; 
         __kernel_ipc_pid_t32    shm_lpid; 
         unsigned short          shm_nattch;
-        unsigned short          shm_npages;
-        u32                    shm_pages;
-        u32                    attaches; 
 };
                                                         
 static inline int sunos_shmid_get(struct shmid_ds32 *user,
@@ -1230,8+1223,7 @@ static inline int sunos_shmid_get(struct shmid_ds32 *user,
           __get_user(kern->shm_ctime, &user->shm_ctime)                ||
           __get_user(kern->shm_cpid, &user->shm_cpid)                  ||
           __get_user(kern->shm_lpid, &user->shm_lpid)                  ||
-          __get_user(kern->shm_nattch, &user->shm_nattch)              ||
-          __get_user(kern->shm_npages, &user->shm_npages))
+          __get_user(kern->shm_nattch, &user->shm_nattch))
                return -EFAULT;
        return 0;
 }
@@ -1250,8+1242,7 @@ static inline int sunos_shmid_put(struct shmid_ds32 *user,
           __put_user(kern->shm_ctime, &user->shm_ctime)                ||
           __put_user(kern->shm_cpid, &user->shm_cpid)                  ||
           __put_user(kern->shm_lpid, &user->shm_lpid)                  ||
-          __put_user(kern->shm_nattch, &user->shm_nattch)              ||
-          __put_user(kern->shm_npages, &user->shm_npages))
+          __put_user(kern->shm_nattch, &user->shm_nattch))
                return -EFAULT;
        return 0;
 }
index 55b41b3..11c86ef 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: systbls.S,v 1.49 1998/09/13 04:30:32 davem Exp $
+/* $Id: systbls.S,v 1.50 1998/10/07 01:27:27 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -20,7+20,7 @@ sys_call_table32:
 /*0*/  .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
 /*5*/  .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod
-/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_nis_syscall, sys32_lseek
+/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek
 /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
 /*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -79,7+79,7 @@ sys_call_table:
 /*0*/  .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
 /*5*/  .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod
-/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek
+/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_perfctr, sys_lseek
 /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall
 /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
index 797d404..9c04983 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: trampoline.S,v 1.5 1998/05/25 05:31:45 davem Exp $
+/* $Id: trampoline.S,v 1.6 1998/10/11 06:58:23 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -27,6+27,7 @@ sparc64_cpu_startup:
        stxa    %g1, [%g0] ASI_LSU_CONTROL
        membar  #Sync
        wrpr    %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+       wr      %g0, 0, %fprs
        wrpr    %g0, 15, %pil
 
        sethi   %uhi(PAGE_OFFSET), %g4
index 4c7b931..cb5180f 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: traps.c,v 1.54 1998/09/25 01:09:02 davem Exp $
+/* $Id: traps.c,v 1.55 1998/10/11 06:58:22 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -661,7+661,7 @@ void cache_flush_trap(struct pt_regs *regs)
 #ifndef __SMP__
        unsigned node = linux_cpus[get_cpuid()].prom_node;
 #else
-#error SMP not supported on sparc64 yet
+#error cache_flush_trap not supported on sparc64/SMP yet
 #endif
 
 #if 0
index 40494ca..d32309b 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: unaligned.c,v 1.11 1998/09/22 03:24:52 davem Exp $
+/* $Id: unaligned.c,v 1.13 1998/10/07 22:43:13 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -58,9+58,10 @@ static inline int decode_access_size(unsigned int insn)
 {
        unsigned int tmp;
 
-       if (((insn >> 19) & 0xf) == 14)
-               return 8;       /* stx* */
-       tmp = (insn >> 19) & 3;
+       tmp = ((insn >> 19) & 0xf);
+       if (tmp == 11 || tmp == 14) /* ldx/stx */
+               return 8;
+       tmp &= 3;
        if(!tmp)
                return 4;
        else if(tmp == 3)
index a580f7a..2a3c63e 100644 (file)
-# $Id: Makefile,v 1.16 1998/06/12 14:53:53 jj Exp $
+# $Id: Makefile,v 1.18 1998/10/13 09:07:24 davem Exp $
 # Makefile for Sparc library files..
 #
 
 CFLAGS := $(CFLAGS)
 
-OBJS  = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \
+OBJS  = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
        memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
        VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o
 
@@ -16,10+16,10 @@ VIScopy.o: VIScopy.S VIS.h
 VISbzero.o: VISbzero.S VIS.h
 
 .S.s:
-       $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+       $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
 
 .S.o:
-       $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
 
 dep:
 
index 7f2f497..cdabf5c 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: VIScopy.S,v 1.18 1998/06/12 14:53:55 jj Exp $
+/* $Id: VIScopy.S,v 1.19 1998/10/19 21:52:19 davem Exp $
  * VIScopy.S: High speed copy operations utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -480,7+480,7 @@ vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis
 vis01:FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_SYNC(o0, f48) membar #Sync
       FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)  STORE_JUMP(o0, f48, finish_f0) membar #Sync
 vis02:FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)  STORE_SYNC(o0, f48) membar #Sync
-      FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, check_finish_f16) add %o2, %g3, %g7
+      FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, finish_f16) membar #Sync
 vis03:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_SYNC(o0, f48) membar #Sync
       FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_JUMP(o0, f48, finish_f32) membar #Sync
       VISLOOP_PAD
@@ -569,18+569,7 @@ finish_f8: FINISH_VISCHUNK(o0, f8,  f10, g3)
 finish_f10:    FINISH_VISCHUNK(o0, f10, f12, g3)
 finish_f12:    FINISH_VISCHUNK(o0, f12, f14, g3)
 finish_f14:    UNEVEN_VISCHUNK(o0, f14, f0,  g3)
-/* This is a special hack to speed up 8K page copy */
-check_finish_f16:
-               andcc           %g1, 7, %g0
-               bne,pn          %icc, finish_f16
-                cmp            %g7, 0x40
-               bne,pn          %icc, finish_f16
-                FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-               membar #Sync
-               EXVIS1(STBLK    %f48, [%o0] ASIBLK)
-               b,pt            %xcc, vis_ret
-finish_f16:     membar         #Sync
-               FINISH_VISCHUNK(o0, f16, f18, g3)
+finish_f16:    FINISH_VISCHUNK(o0, f16, f18, g3)
 finish_f18:    FINISH_VISCHUNK(o0, f18, f20, g3)
 finish_f20:    FINISH_VISCHUNK(o0, f20, f22, g3)
 finish_f22:    FINISH_VISCHUNK(o0, f22, f24, g3)
index 10d127b..a189d0d 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: VISsave.S,v 1.2 1998/06/19 12:14:25 jj Exp $
+/* $Id: VISsave.S,v 1.3 1998/10/21 10:36:39 jj Exp $
  * VISsave.S: Code for saving FPU register state for
  *            VIS routines. One should not call this directly,
  *            but use macros provided in <asm/visasm.h>.
@@ -76,11+76,13 @@ vis1:       ldub            [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3
 
        sll             %g1, 5, %g1
        add             %g6, AOFF_task_fpregs+0xc0, %g3
+       wr              %g0, FPRS_FEF, %fprs
        membar          #StoreStore | #LoadStore
        stda            %f32, [%g2 + %g1] ASI_BLK_P
        stda            %f48, [%g3 + %g1] ASI_BLK_P
        membar          #Sync
        jmpl            %g7 + %g0, %g0
+
         nop
 
        .align          32
index c57f0ae..cc189ce 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: blockops.S,v 1.14 1998/06/12 14:53:46 jj Exp $
+/* $Id: blockops.S,v 1.16 1998/10/20 03:09:04 jj Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6+7,9 @@
 
 #include "VIS.h"
 #include <asm/visasm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/asm_offsets.h>
 
 #define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7)  \
        fmovd   %reg0, %f48;    fmovd   %reg1, %f50;            \
        fmovd   %reg4, %f56;    fmovd   %reg5, %f58;            \
        fmovd   %reg6, %f60;    fmovd   %reg7, %f62;
 
+#define        TLBTEMP_BASE    (8 * 1024 * 1024)
+#define        DCACHE_SIZE     (PAGE_SIZE * 2)
+#define TLBTEMP_ENT1   (61 << 3)
+#define TLBTEMP_ENT2   (62 << 3)
+#define TLBTEMP_ENTSZ  (1 << 3)
+
        .text
        .align          32
        .globl          copy_page
        .type           copy_page,@function
 copy_page: /* %o0=dest, %o1=src */
        VISEntry
+       ldx             [%g6 + AOFF_task_mm], %o2
+       sub             %o0, %g4, %g1
+       sethi           %uhi(_PAGE_VALID), %g3
+       sub             %o1, %g4, %g2
+       sllx            %g3, 32, %g3
+       ldx             [%o2 + AOFF_mm_segments], %o0
+       or              %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
+       or              %g1, %g3, %g1
+       or              %g2, %g3, %g2
+       mov             TLB_TAG_ACCESS, %o2
+       sethi           %hi(TLBTEMP_BASE), %o3
+       sethi           %hi(DCACHE_SIZE), %o1
+       add             %o0, %o3, %o0
+       add             %o0, %o1, %o1
+       sethi           %hi(TLBTEMP_ENT1), %o3
+       rdpr            %pstate, %g3
+       wrpr            %g3, PSTATE_IE, %pstate
+       ldxa            [%o3] ASI_DTLB_TAG_READ, %o4
+       ldxa            [%o3] ASI_DTLB_DATA_ACCESS, %o5
+       stxa            %o0, [%o2] ASI_DMMU
+       stxa            %g1, [%o3] ASI_DTLB_DATA_ACCESS
+       membar          #Sync
+       add             %o3, (TLBTEMP_ENTSZ), %o3
+       ldxa            [%o3] ASI_DTLB_TAG_READ, %g5
+       ldxa            [%o3] ASI_DTLB_DATA_ACCESS, %g7
+       stxa            %o1, [%o2] ASI_DMMU
+       stxa            %g2, [%o3] ASI_DTLB_DATA_ACCESS
+       membar          #Sync
+
        membar          #LoadStore | #StoreStore | #StoreLoad
        ldda            [%o1] ASI_BLK_P, %f0
        add             %o1, 0x40, %o1
@@ -50,15+88,44 @@ copy_page: /* %o0=dest, %o1=src */
        stda            %f0, [%o0] ASI_BLK_P
        add             %o0, 0x40, %o0
        stda            %f16, [%o0] ASI_BLK_P
-       membar          #StoreStore | #StoreLoad
+       membar          #Sync
+       VISExit
+
+       mov             TLB_TAG_ACCESS, %o2
+       stxa            %g5, [%o2] ASI_DMMU
+       stxa            %g7, [%o3] ASI_DTLB_DATA_ACCESS
+       membar          #Sync
+       sub             %o3, (TLBTEMP_ENTSZ), %o3
+       stxa            %o4, [%o2] ASI_DMMU
+       stxa            %o5, [%o3] ASI_DTLB_DATA_ACCESS
+       membar          #Sync
        jmpl            %o7 + 0x8, %g0
-        VISExit
+        wrpr           %g3, 0x0, %pstate
 
        .align          32
-       .globl          __bzero_1page
-       .type           __bzero_1page,@function
-__bzero_1page: /* %o0=dest */
+       .globl          clear_page
+       .type           clear_page,@function
+clear_page:            /* %o0=dest */
        VISEntryHalf
+       ldx             [%g6 + AOFF_task_mm], %o2
+       sub             %o0, %g4, %g1
+       sethi           %uhi(_PAGE_VALID), %g3
+       sllx            %g3, 32, %g3
+       or              %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
+       ldx             [%o2 + AOFF_mm_segments], %o0
+       or              %g1, %g3, %g1
+       mov             TLB_TAG_ACCESS, %o2
+       sethi           %hi(TLBTEMP_BASE), %o3
+       add             %o0, %o3, %o0
+       sethi           %hi(TLBTEMP_ENT2), %o3
+       rdpr            %pstate, %g3
+       wrpr            %g3, PSTATE_IE, %pstate
+       ldxa            [%o3] ASI_DTLB_TAG_READ, %g5
+       ldxa            [%o3] ASI_DTLB_DATA_ACCESS, %g7
+       stxa            %o0, [%o2] ASI_DMMU
+       stxa            %g1, [%o3] ASI_DTLB_DATA_ACCESS
+       membar          #Sync
+
        fzero           %f0                             ! FPA   Group
        mov             32, %o1                         ! IEU0
        fzero           %f2                             ! FPA   Group
@@ -79,6+146,11 @@ __bzero_1page:      /* %o0=dest */
        subcc           %o1, 1, %o1                     ! IEU1
        bne,pt          %icc, 1b                        ! CTI
         add            %o0, 0x100, %o0                 ! IEU0  Group
-       membar          #StoreStore | #StoreLoad        ! LSU   Group
-       jmpl            %o7 + 0x8, %g0                  ! CTI   Group brk forced
-        VISExitHalf
+       membar          #Sync                           ! LSU   Group
+       VISExitHalf
+
+       stxa            %g5, [%o2] ASI_DMMU
+       stxa            %g7, [%o3] ASI_DTLB_DATA_ACCESS
+       membar          #Sync
+       jmpl            %o7 + 0x8, %g0
+        wrpr           %g3, 0x0, %pstate
diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c
new file mode 100644 (file)
index 0000000..69286c4
--- /dev/null
@@ -0,0 +1,278 @@
+/* $Id: debuglocks.c,v 1.2 1998/10/13 09:07:27 davem Exp $
+ * debuglocks.c: Debugging versions of SMP locking primitives.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+#ifdef __SMP__
+
+/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
+#ifdef SPIN_LOCK_DEBUG
+
+#define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
+
+static inline void show (char *str, spinlock_t *lock, unsigned long caller)
+{
+       int cpu = smp_processor_id();
+
+       printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n",
+              str, lock, cpu, (unsigned int) caller,
+              lock->owner_pc, lock->owner_cpu);
+}
+
+static inline void show_read (char *str, rwlock_t *lock, unsigned long caller)
+{
+       int cpu = smp_processor_id();
+
+       printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n",
+              str, lock, cpu, (unsigned int) caller,
+              lock->writer_pc, lock->writer_cpu);
+}
+
+static inline void show_write (char *str, rwlock_t *lock, unsigned long caller)
+{
+       int cpu = smp_processor_id();
+
+       printk("%s(%p) CPU#%d stuck at %08x\n",
+              str, lock, cpu, (unsigned int) caller);
+       printk("Writer: PC(%08x):CPU(%x)\n",
+              lock->writer_pc, lock->writer_cpu);
+       printk("Readers: 0[%08x] 1[%08x] 2[%08x] 4[%08x]\n",
+              lock->reader_pc[0], lock->reader_pc[1],
+              lock->reader_pc[2], lock->reader_pc[3]);
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+void _do_spin_lock(spinlock_t *lock, char *str)
+{
+       unsigned long caller, val;
+       int stuck = INIT_STUCK;
+       int cpu = smp_processor_id();
+
+       GET_CALLER(caller);
+again:
+       __asm__ __volatile__("ldstub [%1], %0"
+                            : "=r" (val)
+                            : "r" (&(lock->lock))
+                            : "memory");
+       membar("#StoreLoad | #StoreStore");
+       if (val) {
+               while (lock->lock) {
+                       if (!--stuck) {
+                               show(str, lock, caller);
+                               stuck = INIT_STUCK;
+                       }
+                       membar("#LoadLoad");
+               }
+               goto again;
+       }
+       lock->owner_pc = ((unsigned int)caller);
+       lock->owner_cpu = cpu;
+}
+
+int _spin_trylock(spinlock_t *lock)
+{
+       unsigned long val, caller;
+       int cpu = smp_processor_id();
+
+       GET_CALLER(caller);
+       __asm__ __volatile__("ldstub [%1], %0"
+                            : "=r" (val)
+                            : "r" (&(lock->lock))
+                            : "memory");
+       membar("#StoreLoad | #StoreStore");
+       if (!val) {
+               lock->owner_pc = ((unsigned int)caller);
+               lock->owner_cpu = cpu;
+       }
+       return val == 0;
+}
+
+void _do_spin_unlock(spinlock_t *lock)
+{
+       lock->owner_pc = 0;
+       lock->owner_cpu = NO_PROC_ID;
+       membar("#StoreStore | #LoadStore");
+       lock->lock = 0;
+}
+
+/* Keep INIT_STUCK the same... */
+
+void _do_read_lock (rwlock_t *rw, char *str)
+{
+       unsigned long caller, val;
+       int stuck = INIT_STUCK;
+       int cpu = smp_processor_id();
+
+       GET_CALLER(caller);
+wlock_again:
+       /* Wait for any writer to go away.  */
+       while (((long)(rw->lock)) < 0) {
+               if (!--stuck) {
+                       show_read(str, rw, caller);
+                       stuck = INIT_STUCK;
+               }
+               membar("#LoadLoad");
+       }
+       /* Try once to increment the counter.  */
+       __asm__ __volatile__("
+       ldx             [%0], %%g5
+       brlz,a,pn       %%g5, 2f
+        mov            1, %0
+       add             %%g5, 1, %%g7
+       casx            [%0], %%g5, %%g7
+       sub             %%g5, %%g7, %0
+2:"    : "=r" (val)
+       : "0" (&(rw->lock))
+       : "g5", "g7", "memory");
+       membar("#StoreLoad | #StoreStore");
+       if (val)
+               goto wlock_again;
+       rw->reader_pc[cpu] = ((unsigned int)caller);
+}
+
+void _do_read_unlock (rwlock_t *rw, char *str)
+{
+       unsigned long caller, val;
+       int stuck = INIT_STUCK;
+       int cpu = smp_processor_id();
+
+       GET_CALLER(caller);
+
+       /* Drop our identity _first_. */
+       rw->reader_pc[cpu] = 0;
+runlock_again:
+       /* Spin trying to decrement the counter using casx.  */
+       __asm__ __volatile__("
+       ldx     [%0], %%g5
+       sub     %%g5, 1, %%g7
+       casx    [%0], %%g5, %%g7
+       membar  #StoreLoad | #StoreStore
+       sub     %%g5, %%g7, %0
+"      : "=r" (val)
+       : "0" (&(rw->lock))
+       : "g5", "g7", "memory");
+       if (val) {
+               if (!--stuck) {
+                       show_read(str, rw, caller);
+                       stuck = INIT_STUCK;
+               }
+               goto runlock_again;
+       }
+}
+
+void _do_write_lock (rwlock_t *rw, char *str)
+{
+       unsigned long caller, val;
+       int stuck = INIT_STUCK;
+       int cpu = smp_processor_id();
+
+       GET_CALLER(caller);
+wlock_again:
+       /* Spin while there is another writer. */
+       while (((long)rw->lock) < 0) {
+               if (!--stuck) {
+                       show_write(str, rw, caller);
+                       stuck = INIT_STUCK;
+               }
+               membar("#LoadLoad");
+       }
+
+       /* Try to acuire the write bit.  */
+       __asm__ __volatile__("
+       mov     1, %%g3
+       sllx    %%g3, 63, %%g3
+       ldx     [%0], %%g5
+       brlz,pn %%g5, 1f
+        or     %%g5, %%g3, %%g7
+       casx    [%0], %%g5, %%g7
+       membar  #StoreLoad | #StoreStore
+       ba,pt   %%xcc, 2f
+        sub    %%g5, %%g7, %0
+1:     mov     1, %0
+2:"    : "=r" (val)
+       : "0" (&(rw->lock))
+       : "g3", "g5", "g7", "memory");
+       if (val) {
+               /* We couldn't get the write bit. */
+               if (!--stuck) {
+                       show_write(str, rw, caller);
+                       stuck = INIT_STUCK;
+               }
+               goto wlock_again;
+       }
+       if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) {
+               /* Readers still around, drop the write
+                * lock, spin, and try again.
+                */
+               if (!--stuck) {
+                       show_write(str, rw, caller);
+                       stuck = INIT_STUCK;
+               }
+               __asm__ __volatile__("
+               mov     1, %%g3
+               sllx    %%g3, 63, %%g3
+1:             ldx     [%0], %%g5
+               andn    %%g5, %%g3, %%g7
+               casx    [%0], %%g5, %%g7
+               cmp     %%g5, %%g7
+               bne,pn  %%xcc, 1b
+                membar #StoreLoad | #StoreStore"
+               : /* no outputs */
+               : "r" (&(rw->lock))
+               : "g3", "g5", "g7", "cc", "memory");
+               while(rw->lock != 0) {
+                       if (!--stuck) {
+                               show_write(str, rw, caller);
+                               stuck = INIT_STUCK;
+                       }
+                       membar("#LoadLoad");
+               }
+               goto wlock_again;
+       }
+
+       /* We have it, say who we are. */
+       rw->writer_pc = ((unsigned int)caller);
+       rw->writer_cpu = cpu;
+}
+
+void _do_write_unlock(rwlock_t *rw)
+{
+       unsigned long caller, val;
+       int stuck = INIT_STUCK;
+
+       GET_CALLER(caller);
+
+       /* Drop our identity _first_ */
+       rw->writer_pc = 0;
+       rw->writer_cpu = NO_PROC_ID;
+wlock_again:
+       __asm__ __volatile__("
+       mov     1, %%g3
+       sllx    %%g3, 63, %%g3
+       ldx     [%0], %%g5
+       andn    %%g5, %%g3, %%g7
+       casx    [%0], %%g5, %%g7
+       membar  #StoreLoad | #StoreStore
+       sub     %%g5, %%g7, %0
+"      : "=r" (val)
+       : "0" (&(rw->lock))
+       : "g3", "g5", "g7", "memory");
+       if (val) {
+               if (!--stuck) {
+                       show_write("write_unlock", rw, caller);
+                       stuck = INIT_STUCK;
+               }
+               goto wlock_again;
+       }
+}
+
+#endif /* SPIN_LOCK_DEBUG */
+#endif /* __SMP__ */
diff --git a/arch/sparc64/lib/locks.S b/arch/sparc64/lib/locks.S
deleted file mode 100644 (file)
index 7b2bdba..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 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          32
-
-___lk_busy_spin:
-       ldub            [%g1 + 0], %g2
-       brnz,pt         %g2, ___lk_busy_spin
-        membar         #LoadLoad
-       b,pt            %xcc, 1f
-        ldstub         [%g1 + 0], %g2
-
-       .globl          ___lock_kernel
-___lock_kernel:
-       addcc           %g2, -1, %g2
-       rdpr            %pil, %g3
-       bcs,a,pn        %icc, 9f
-        stw            %g2, [%g6 + AOFF_task_lock_depth]
-       wrpr            %g0, 15, %pil
-       ldstub          [%g1 + 0], %g2
-1:     brnz,pn         %g2, ___lk_busy_spin
-        membar         #StoreLoad | #StoreStore
-       lduw            [%g6 + AOFF_task_processor], %g2
-       stb             %g2, [%g1 + 1]
-2:     mov             -1, %g2
-       stw             %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
-       stw             %g2, [%g6 + AOFF_task_lock_depth]
-       ldstub          [%g1 + 0], %g2
-1:     brz,pt          %g2, 3f
-        membar         #StoreLoad | #StoreStore
-2:     ldub            [%g1 + 0], %g2
-       brnz,pt         %g2, 2b
-        membar         #LoadLoad
-       b,pt            %xcc, 1b
-        ldstub         [%g1 + 0], %g2
-3:     lduw            [%g6 + AOFF_task_processor], %g2
-       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
-___unlock_kernel:
-       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 61207dd..55527f6 100644 (file)
@@ -9,7+9,8 @@
 #define HI_MAGIC 0x80808080
 
        .align  32
-       .global __strlen
+       .global strlen, __strlen
+strlen:
 __strlen:
        mov     %o0, %o1
        andcc   %o0, 3, %g0
index 8f695b1..1f5a194 100644 (file)
@@ -16,10+16,4 @@ O_OBJS   := math.o fabsq.o faddq.o fdivq.o fdmulq.o fitoq.o          \
                fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o                \
                fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o
 
-.S.s:
-       $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
-
-.S.o:
-       $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-
 include $(TOPDIR)/Rules.make
index 851a856..a4cf4aa 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: fault.c,v 1.24 1998/09/22 03:27:33 davem Exp $
+/* $Id: fault.c,v 1.25 1998/10/19 21:52:26 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -154,6+154,7 @@ good_area:
                if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
+       current->mm->segments = (void *) (address & PAGE_SIZE);
        handle_mm_fault(current, vma, address, write);
        up(&mm->mmap_sem);
        return;
index 27908c2..236c866 100644 (file)
@@ -1,4+1,4 @@
-/*  $Id: init.c,v 1.98 1998/09/28 06:18:39 davem Exp $
+/*  $Id: init.c,v 1.103 1998/10/20 03:09:12 jj Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -45,7+45,6 @@ extern char __init_begin, __init_end, etext, __bss_start;
 
 int do_check_pgt_cache(int low, int high)
 {
-        struct page *page, *page2;
         int freed = 0;
 
        if(pgtable_cache_size > high) {
@@ -60,6+59,7 @@ int do_check_pgt_cache(int low, int high)
        }
 #ifndef __SMP__ 
         if (pgd_cache_size > high / 4) {
+               struct page *page, *page2;
                 for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) {
                         if ((unsigned long)page->pprev_hash == 3) {
                                 if (page2)
@@ -537,7+537,7 @@ static inline void inherit_prom_mappings(void)
                                if (pgd_none(*pgdp)) {
                                        pmdp = sparc_init_alloc(&mempool,
                                                         PMD_TABLE_SIZE);
-                                       clear_page(pmdp);
+                                       memset(pmdp, 0, PAGE_SIZE);
                                        pgd_set(pgdp, pmdp);
                                }
                                pmdp = pmd_offset(pgdp, vaddr);
@@ -591,12+591,17 @@ static void __flush_nucleus_vptes(void)
 }
 
 static int prom_ditlb_set = 0;
-int prom_itlb_ent, prom_dtlb_ent;
-unsigned long prom_itlb_tag, prom_itlb_data;
-unsigned long prom_dtlb_tag, prom_dtlb_data;
+struct prom_tlb_entry {
+       int             tlb_ent;
+       unsigned long   tlb_tag;
+       unsigned long   tlb_data;
+};
+struct prom_tlb_entry prom_itlb[8], prom_dtlb[8];
 
 void prom_world(int enter)
 {
+       int i;
+
        if (!prom_ditlb_set)
                return;
        if (enter) {
@@ -604,29+609,44 @@ void prom_world(int enter)
                __flush_nucleus_vptes();
 
                /* Install PROM world. */
-               __asm__ __volatile__("stxa %0, [%1] %2"
-                                       : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS),
+               for (i = 0; i < 8; i++) {
+                       if (prom_dtlb[i].tlb_ent != -1) {
+                               __asm__ __volatile__("stxa %0, [%1] %2"
+                                       : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
                                        "i" (ASI_DMMU));
-               membar("#Sync");
-               spitfire_put_dtlb_data(62, prom_dtlb_data);
-               membar("#Sync");
-               __asm__ __volatile__("stxa %0, [%1] %2"
-                                       : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS),
+                               membar("#Sync");
+                               spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
+                                                      prom_dtlb[i].tlb_data);
+                               membar("#Sync");
+                       }
+
+                       if (prom_itlb[i].tlb_ent != -1) {
+                               __asm__ __volatile__("stxa %0, [%1] %2"
+                                       : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
                                        "i" (ASI_IMMU));
-               membar("#Sync");
-               spitfire_put_itlb_data(62, prom_itlb_data);
-               membar("#Sync");
+                               membar("#Sync");
+                               spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
+                                                      prom_itlb[i].tlb_data);
+                               membar("#Sync");
+                       }
+               }
        } else {
-               __asm__ __volatile__("stxa %%g0, [%0] %1"
+               for (i = 0; i < 8; i++) {
+                       if (prom_dtlb[i].tlb_ent != -1) {
+                               __asm__ __volatile__("stxa %%g0, [%0] %1"
                                        : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-               membar("#Sync");
-               spitfire_put_dtlb_data(62, 0x0UL);
-               membar("#Sync");
-               __asm__ __volatile__("stxa %%g0, [%0] %1"
+                               membar("#Sync");
+                               spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
+                               membar("#Sync");
+                       }
+                       if (prom_itlb[i].tlb_ent != -1) {
+                               __asm__ __volatile__("stxa %%g0, [%0] %1"
                                        : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
-               membar("#Sync");
-               spitfire_put_itlb_data(62, 0x0UL);
-               membar("#Sync");
+                               membar("#Sync");
+                               spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL);
+                               membar("#Sync");
+                       }
+               }
        }
 }
 
@@ -640,8+660,8 @@ void inherit_locked_prom_mappings(int save_p)
         * it (conveniently) fails to mention any of these in the
         * translations property.  The only ones that matter are
         * the locked PROM tlb entries, so we impose the following
-        * irrecovable rule on the PROM, it is allowed 1 locked
-        * entry in the ITLB and 1 in the DTLB.
+        * irrecovable rule on the PROM, it is allowed 8 locked
+        * entries in the ITLB and 8 in the DTLB.
         *
         * Supposedly the upper 16GB of the address space is
         * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED
@@ -650,17+670,23 @@ void inherit_locked_prom_mappings(int save_p)
         * systems to coordinate mmu mappings is also COMPLETELY
         * UNDOCUMENTED!!!!!! Thanks S(t)un!
         */
+       if (save_p) {
+               for(i = 0; i < 8; i++) {
+                       prom_dtlb[i].tlb_ent = -1;
+                       prom_itlb[i].tlb_ent = -1;
+               }
+       }
        for(i = 0; i < 63; i++) {
                unsigned long data;
 
                data = spitfire_get_dtlb_data(i);
-               if(!dtlb_seen && (data & _PAGE_L)) {
+               if(data & _PAGE_L) {
                        unsigned long tag = spitfire_get_dtlb_tag(i);
 
                        if(save_p) {
-                               prom_dtlb_ent = i;
-                               prom_dtlb_tag = tag;
-                               prom_dtlb_data = data;
+                               prom_dtlb[dtlb_seen].tlb_ent = i;
+                               prom_dtlb[dtlb_seen].tlb_tag = tag;
+                               prom_dtlb[dtlb_seen].tlb_data = data;
                        }
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
                                             : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
@@ -668,18+694,22 @@ void inherit_locked_prom_mappings(int save_p)
                        spitfire_put_dtlb_data(i, 0x0UL);
                        membar("#Sync");
 
-                       dtlb_seen = 1;
-                       if(itlb_seen)
+                       dtlb_seen++;
+                       if(dtlb_seen > 7)
                                break;
                }
+       }
+       for(i = 0; i < 63; i++) {
+               unsigned long data;
+
                data = spitfire_get_itlb_data(i);
-               if(!itlb_seen && (data & _PAGE_L)) {
+               if(data & _PAGE_L) {
                        unsigned long tag = spitfire_get_itlb_tag(i);
 
                        if(save_p) {
-                               prom_itlb_ent = i;
-                               prom_itlb_tag = tag;
-                               prom_itlb_data = data;
+                               prom_itlb[itlb_seen].tlb_ent = i;
+                               prom_itlb[itlb_seen].tlb_tag = tag;
+                               prom_itlb[itlb_seen].tlb_data = data;
                        }
                        __asm__ __volatile__("stxa %%g0, [%0] %1"
                                             : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
@@ -687,15+717,8 @@ void inherit_locked_prom_mappings(int save_p)
                        spitfire_put_itlb_data(i, 0x0UL);
                        membar("#Sync");
 
-                       /* Re-install it. */
-                       __asm__ __volatile__("stxa %0, [%1] %2"
-                                            : : "r" (tag), "r" (TLB_TAG_ACCESS),
-                                                "i" (ASI_IMMU));
-                       membar("#Sync");
-                       spitfire_put_itlb_data(62, data);
-                       membar("#Sync");
-                       itlb_seen = 1;
-                       if(dtlb_seen)
+                       itlb_seen++;
+                       if(itlb_seen > 7)
                                break;
                }
        }
@@ -706,19+729,29 @@ void inherit_locked_prom_mappings(int save_p)
 /* Give PROM back his world, done during reboots... */
 void prom_reload_locked(void)
 {
-       __asm__ __volatile__("stxa %0, [%1] %2"
-                            : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS),
-                            "i" (ASI_DMMU));
-       membar("#Sync");
-       spitfire_put_dtlb_data(prom_dtlb_ent, prom_dtlb_data);
-       membar("#Sync");
+       int i;
 
-       __asm__ __volatile__("stxa %0, [%1] %2"
-                            : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS),
-                            "i" (ASI_IMMU));
-       membar("#Sync");
-       spitfire_put_itlb_data(prom_itlb_ent, prom_itlb_data);
-       membar("#Sync");
+       for (i = 0; i < 8; i++) {
+               if (prom_dtlb[i].tlb_ent != -1) {
+                       __asm__ __volatile__("stxa %0, [%1] %2"
+                               : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
+                               "i" (ASI_DMMU));
+                       membar("#Sync");
+                       spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
+                                              prom_dtlb[i].tlb_data);
+                       membar("#Sync");
+               }
+
+               if (prom_itlb[i].tlb_ent != -1) {
+                       __asm__ __volatile__("stxa %0, [%1] %2"
+                               : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
+                               "i" (ASI_IMMU));
+                       membar("#Sync");
+                       spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
+                                              prom_itlb[i].tlb_data);
+                       membar("#Sync");
+               }
+       }
 }
 
 void __flush_dcache_range(unsigned long start, unsigned long end)
@@ -844,7+877,7 @@ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
 
        pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
        if(pmd) {
-               clear_page(pmd);
+               memset(pmd, 0, PAGE_SIZE);
                pgd_set(pgd, pmd);
                return pmd + offset;
        }
@@ -857,7+890,7 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
 
        pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
        if(pte) {
-               clear_page(pte);
+               memset(pte, 0, PAGE_SIZE);
                pmd_set(pmd, pte);
                return pte + offset;
        }
@@ -875,13+908,13 @@ allocate_ptable_skeleton(unsigned long start, unsigned long end))
                pgdp = pgd_offset(init_task.mm, start);
                if (pgd_none(*pgdp)) {
                        pmdp = sparc_init_alloc(&mempool, PAGE_SIZE);
-                       clear_page(pmdp);
+                       memset(pmdp, 0, PAGE_SIZE);
                        pgd_set(pgdp, pmdp);
                }
                pmdp = pmd_offset(pgdp, start);
                if (pmd_none(*pmdp)) {
                        ptep = sparc_init_alloc(&mempool, PAGE_SIZE);
-                       clear_page(ptep);
+                       memset(ptep, 0, PAGE_SIZE);
                        pmd_set(pmdp, ptep);
                }
                start = (start + PMD_SIZE) & PMD_MASK;
index fcf458f..c836f62 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: ultra.S,v 1.27 1998/09/28 06:18:42 davem Exp $
+/* $Id: ultra.S,v 1.29 1998/10/22 03:05:51 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -125,34+125,39 @@ __flush_tlb_range_pbp_slow:
        retl
         wrpr           %g1, 0x0, %pstate
 
-       /* Unfortunately, it is necessary. */
-       .globl          flush_page_to_ram
-flush_page_to_ram:     /* %o0 = page */
-       rdpr            %pstate, %g5
-       wrpr            %g5, PSTATE_IE, %pstate
-       sethi           %hi(dcache_aliases_found), %g1
-       ldx             [%g1 + %lo(dcache_aliases_found)], %g2
-       sub             %o0, %g4, %o0           ! Get phys_page
-       clr             %o2                     ! This dcache area begin
-       sethi           %hi(1<<14), %o1         ! This dcache area end
-1:     ldxa            [%o2] ASI_DCACHE_TAG, %o3
-       andcc           %o3, 0x3, %g0           ! Valid bits set?
-       be,pn           %xcc, 2f                ! Nope, skip this one
-        andn           %o3, 0x3, %o3           ! Mask out valid bits
-       sllx            %o3, (13 - 2), %o3      ! Shift into physaddr
-       cmp             %o3, %o0                ! Match?
-       bne,pt          %xcc, 2f                ! Nope, skip to next
+       .align          32
+       .globl          flush_icache_page
+flush_icache_page:     /* %o0 = phys_page */
+       sethi           %hi(1 << 13), %o2       ! I-cache valid/set bit
+       srlx            %o0, 5, %o0             ! phys-addr comparitor
+       clr             %o1                     ! I-cache address
+1:     ldda            [%o1] ASI_IC_TAG, %o4
+       andcc           %o5, %o2, %g0
+       be,pn           %xcc, 2f
+        andn           %o5, %o2, %o5
+       cmp             %o5, %o0
+
+       be,pn           %xcc, iflush1
+2:      ldda           [%o1 + %o2] ASI_IC_TAG, %o4
+4:     andcc           %o5, %o2, %g0
+       be,pn           %xcc, 3f
+        andn           %o5, %o2, %o5
+       cmp             %o5, %o0
+       be,pn           %xcc, iflush2
         nop
-       stxa            %g0, [%o2] ASI_DCACHE_TAG
-       membar          #Sync
-       add             %g2, 1, %g2             ! Increment alias counter
-2:     add             %o2, (1<<5), %o2        ! 32-bytes per full line
-       cmp             %o2, %o1
+
+3:     add             %o1, 0x20, %o1
+       cmp             %o1, %o2
        bne,pt          %xcc, 1b
         nop
-       stx             %g2, [%g1 + %lo(dcache_aliases_found)]
        retl
-        wrpr           %g5, 0x0, %pstate
+        nop
+iflush1:stxa           %g0, [%o1] ASI_IC_TAG
+       membar          #Sync
+       ba,a,pt         %xcc, 4b
+iflush2:stxa           %g0, [%o1 + %o2] ASI_IC_TAG
+       membar          #Sync
+       ba,a,pt         %xcc, 3b
 
 #ifdef __SMP__
        /* These are all called by the slaves of a cross call, at
index 8e7ff77..340c272 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: misc.c,v 1.10 1998/07/21 10:36:29 jj Exp $
+/* $Id: misc.c,v 1.13 1998/10/13 14:03:49 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -40,25+40,18 @@ extern int serial_console;
 /* Drop into the prom, with the chance to continue with the 'go'
  * prom command.
  */
-/* XXX Fix the pre and post calls as it locks up my Ultra at the moment -DaveM */
 void
 prom_cmdline(void)
 {
-       extern void kernel_enter_debugger(void);
-       /* extern void install_obp_ticker(void); */
-       /* extern void install_linux_ticker(void); */
        unsigned long flags;
     
-       /* kernel_enter_debugger(); */
 #ifdef CONFIG_SUN_CONSOLE
        if(!serial_console && prom_palette)
                prom_palette (1);
 #endif
-       /* install_obp_ticker(); */
-       save_flags(flags); cli();
+       __save_and_cli(flags);
        p1275_cmd ("enter", P1275_INOUT(0,0));
-       restore_flags(flags);
-       /* install_linux_ticker(); */
+       __restore_flags(flags);
 #ifdef CONFIG_SUN_CONSOLE
        if(!serial_console && prom_palette)
                prom_palette (0);
@@ -78,7+71,7 @@ again:
 
 /* Set prom sync handler to call function 'funcp'. */
 void
-prom_setsync(sync_func_t funcp)
+prom_setcallback(callback_func_t funcp)
 {
        if(!funcp) return;
        p1275_cmd ("set-callback", P1275_ARG(0,P1275_ARG_IN_FUNCTION)|
index 722243e..9b1fafa 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: p1275.c,v 1.13 1998/04/24 15:45:35 jj Exp $
+/* $Id: p1275.c,v 1.15 1998/10/13 14:03:47 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 #include <asm/system.h>
 #include <asm/spitfire.h>
 #include <asm/pstate.h>
+#include <asm/spinlock.h>
 
 struct {
-       long prom_sync_routine;                 /* 0x00 */
+       long prom_callback;                     /* 0x00 */
        void (*prom_cif_handler)(long *);       /* 0x08 */
        unsigned long prom_cif_stack;           /* 0x10 */
        unsigned long prom_args [23];           /* 0x18 */
@@ -31,29+32,262 @@ void prom_cif_interface (void)
        __asm__ __volatile__ ("
        mov     %0, %%o0
        ldx     [%%o0 + 0x010], %%o1    ! prom_cif_stack
-       save    %%o1, -0xc0, %%sp
+       save    %%o1, -0x190, %%sp
        ldx     [%%i0 + 0x008], %%l2    ! prom_cif_handler
        rdpr    %%pstate, %%l4
-       mov     %%g4, %%l0
-       mov     %%g6, %%l1
-       wrpr    %%l4, %1, %%pstate      ! turn on address masking
+       wrpr    %%g0, 0x15, %%pstate    ! save alternate globals
+       stx     %%g1, [%%sp + 2047 + 0x0b0]
+       stx     %%g2, [%%sp + 2047 + 0x0b8]
+       stx     %%g3, [%%sp + 2047 + 0x0c0]
+       stx     %%g4, [%%sp + 2047 + 0x0c8]
+       stx     %%g5, [%%sp + 2047 + 0x0d0]
+       stx     %%g6, [%%sp + 2047 + 0x0d8]
+       stx     %%g7, [%%sp + 2047 + 0x0e0]
+       wrpr    %%g0, 0x814, %%pstate   ! save interrupt globals
+       stx     %%g1, [%%sp + 2047 + 0x0e8]
+       stx     %%g2, [%%sp + 2047 + 0x0f0]
+       stx     %%g3, [%%sp + 2047 + 0x0f8]
+       stx     %%g4, [%%sp + 2047 + 0x100]
+       stx     %%g5, [%%sp + 2047 + 0x108]
+       stx     %%g6, [%%sp + 2047 + 0x110]
+       stx     %%g7, [%%sp + 2047 + 0x118]
+       wrpr    %%g0, 0x14, %%pstate    ! save normal globals
+       stx     %%g1, [%%sp + 2047 + 0x120]
+       stx     %%g2, [%%sp + 2047 + 0x128]
+       stx     %%g3, [%%sp + 2047 + 0x130]
+       stx     %%g4, [%%sp + 2047 + 0x138]
+       stx     %%g5, [%%sp + 2047 + 0x140]
+       stx     %%g6, [%%sp + 2047 + 0x148]
+       stx     %%g7, [%%sp + 2047 + 0x150]
+       wrpr    %%g0, 0x414, %%pstate   ! save mmu globals
+       stx     %%g1, [%%sp + 2047 + 0x158]
+       stx     %%g2, [%%sp + 2047 + 0x160]
+       stx     %%g3, [%%sp + 2047 + 0x168]
+       stx     %%g4, [%%sp + 2047 + 0x170]
+       stx     %%g5, [%%sp + 2047 + 0x178]
+       stx     %%g6, [%%sp + 2047 + 0x180]
+       stx     %%g7, [%%sp + 2047 + 0x188]
+       mov     %%g1, %%l0              ! also save to locals, so we can handle
+       mov     %%g2, %%l1              ! tlb faults later on, when accessing
+       mov     %%g3, %%l3              ! the stack.
+       mov     %%g7, %%l5
+       wrpr    %%l4, %1, %%pstate      ! turn off interrupts
        call    %%l2
         add    %%i0, 0x018, %%o0       ! prom_args
-       wrpr    %%l4, 0, %%pstate       ! put pstate back
-       mov     %%l0, %%g4
+       wrpr    %%g0, 0x414, %%pstate   ! restore mmu globals
+       mov     %%l0, %%g1
+       mov     %%l1, %%g2
+       mov     %%l3, %%g3
+       mov     %%l5, %%g7
+       wrpr    %%g0, 0x14, %%pstate    ! restore normal globals
+       ldx     [%%sp + 2047 + 0x120], %%g1
+       ldx     [%%sp + 2047 + 0x128], %%g2
+       ldx     [%%sp + 2047 + 0x130], %%g3
+       ldx     [%%sp + 2047 + 0x138], %%g4
+       ldx     [%%sp + 2047 + 0x140], %%g5
+       ldx     [%%sp + 2047 + 0x148], %%g6
+       ldx     [%%sp + 2047 + 0x150], %%g7
+       wrpr    %%g0, 0x814, %%pstate   ! restore interrupt globals
+       ldx     [%%sp + 2047 + 0x0e8], %%g1
+       ldx     [%%sp + 2047 + 0x0f0], %%g2
+       ldx     [%%sp + 2047 + 0x0f8], %%g3
+       ldx     [%%sp + 2047 + 0x100], %%g4
+       ldx     [%%sp + 2047 + 0x108], %%g5
+       ldx     [%%sp + 2047 + 0x110], %%g6
+       ldx     [%%sp + 2047 + 0x118], %%g7
+       wrpr    %%g0, 0x15, %%pstate    ! restore alternate globals
+       ldx     [%%sp + 2047 + 0x0b0], %%g1
+       ldx     [%%sp + 2047 + 0x0b8], %%g2
+       ldx     [%%sp + 2047 + 0x0c0], %%g3
+       ldx     [%%sp + 2047 + 0x0c8], %%g4
+       ldx     [%%sp + 2047 + 0x0d0], %%g5
+       ldx     [%%sp + 2047 + 0x0d8], %%g6
+       ldx     [%%sp + 2047 + 0x0e0], %%g7
+       wrpr    %%l4, 0, %%pstate       ! restore original pstate
        ret
-        restore %%l1, 0, %%g6
-       save    %%sp, -0xc0, %%sp       ! If you change the offset of the save 
-       rdpr    %%pstate, %%l4          ! here, please change the 0x8038 
-       andn    %%l4, %1, %%l3          ! constant below as well
-       wrpr    %%l3, %%pstate
-       ldx     [%%o0 + 0x000], %%l2
+        restore
+       " : : "r" (&p1275buf), "i" (PSTATE_IE));
+}
+
+void prom_cif_callback(void)
+{
+       __asm__ __volatile__ ("
+       mov     %0, %%o1
+       save    %%sp, -0x270, %%sp
+       rdpr    %%pstate, %%l4
+       wrpr    %%g0, 0x15, %%pstate    ! save PROM alternate globals
+       stx     %%g1, [%%sp + 2047 + 0x0b0]
+       stx     %%g2, [%%sp + 2047 + 0x0b8]
+       stx     %%g3, [%%sp + 2047 + 0x0c0]
+       stx     %%g4, [%%sp + 2047 + 0x0c8]
+       stx     %%g5, [%%sp + 2047 + 0x0d0]
+       stx     %%g6, [%%sp + 2047 + 0x0d8]
+       stx     %%g7, [%%sp + 2047 + 0x0e0]
+                                       ! restore Linux alternate globals
+       ldx     [%%sp + 2047 + 0x190], %%g1
+       ldx     [%%sp + 2047 + 0x198], %%g2
+       ldx     [%%sp + 2047 + 0x1a0], %%g3
+       ldx     [%%sp + 2047 + 0x1a8], %%g4
+       ldx     [%%sp + 2047 + 0x1b0], %%g5
+       ldx     [%%sp + 2047 + 0x1b8], %%g6
+       ldx     [%%sp + 2047 + 0x1c0], %%g7
+       wrpr    %%g0, 0x814, %%pstate   ! save PROM interrupt globals
+       stx     %%g1, [%%sp + 2047 + 0x0e8]
+       stx     %%g2, [%%sp + 2047 + 0x0f0]
+       stx     %%g3, [%%sp + 2047 + 0x0f8]
+       stx     %%g4, [%%sp + 2047 + 0x100]
+       stx     %%g5, [%%sp + 2047 + 0x108]
+       stx     %%g6, [%%sp + 2047 + 0x110]
+       stx     %%g7, [%%sp + 2047 + 0x118]
+                                       ! restore Linux interrupt globals
+       ldx     [%%sp + 2047 + 0x1c8], %%g1
+       ldx     [%%sp + 2047 + 0x1d0], %%g2
+       ldx     [%%sp + 2047 + 0x1d8], %%g3
+       ldx     [%%sp + 2047 + 0x1e0], %%g4
+       ldx     [%%sp + 2047 + 0x1e8], %%g5
+       ldx     [%%sp + 2047 + 0x1f0], %%g6
+       ldx     [%%sp + 2047 + 0x1f8], %%g7
+       wrpr    %%g0, 0x14, %%pstate    ! save PROM normal globals
+       stx     %%g1, [%%sp + 2047 + 0x120]
+       stx     %%g2, [%%sp + 2047 + 0x128]
+       stx     %%g3, [%%sp + 2047 + 0x130]
+       stx     %%g4, [%%sp + 2047 + 0x138]
+       stx     %%g5, [%%sp + 2047 + 0x140]
+       stx     %%g6, [%%sp + 2047 + 0x148]
+       stx     %%g7, [%%sp + 2047 + 0x150]
+                                       ! restore Linux normal globals
+       ldx     [%%sp + 2047 + 0x200], %%g1
+       ldx     [%%sp + 2047 + 0x208], %%g2
+       ldx     [%%sp + 2047 + 0x210], %%g3
+       ldx     [%%sp + 2047 + 0x218], %%g4
+       ldx     [%%sp + 2047 + 0x220], %%g5
+       ldx     [%%sp + 2047 + 0x228], %%g6
+       ldx     [%%sp + 2047 + 0x230], %%g7
+       wrpr    %%g0, 0x414, %%pstate   ! save PROM mmu globals
+       stx     %%g1, [%%sp + 2047 + 0x158]
+       stx     %%g2, [%%sp + 2047 + 0x160]
+       stx     %%g3, [%%sp + 2047 + 0x168]
+       stx     %%g4, [%%sp + 2047 + 0x170]
+       stx     %%g5, [%%sp + 2047 + 0x178]
+       stx     %%g6, [%%sp + 2047 + 0x180]
+       stx     %%g7, [%%sp + 2047 + 0x188]
+                                       ! restore Linux mmu globals
+       ldx     [%%sp + 2047 + 0x238], %%o0
+       ldx     [%%sp + 2047 + 0x240], %%o1
+       ldx     [%%sp + 2047 + 0x248], %%l2
+       ldx     [%%sp + 2047 + 0x250], %%l3
+       ldx     [%%sp + 2047 + 0x258], %%l5
+       ldx     [%%sp + 2047 + 0x260], %%l6
+       ldx     [%%sp + 2047 + 0x268], %%l7
+                                       ! switch to Linux tba
+       sethi   %%hi(sparc64_ttable_tl0), %%l1
+       rdpr    %%tba, %%l0             ! save PROM tba
+       mov     %%o0, %%g1
+       mov     %%o1, %%g2
+       mov     %%l2, %%g3
+       mov     %%l3, %%g4
+       mov     %%l5, %%g5
+       mov     %%l6, %%g6
+       mov     %%l7, %%g7
+       wrpr    %%l1, %%tba             ! install Linux tba
+       wrpr    %%l4, 0, %%pstate       ! restore PSTATE
+       call    prom_world
+        mov    %%g0, %%o0
+       ldx     [%%i1 + 0x000], %%l2
        call    %%l2
-        nop
+        mov    %%i0, %%o0
+       mov     %%o0, %%l1
+       call    prom_world
+        or     %%g0, 1, %%o0
+       wrpr    %%g0, 0x14, %%pstate    ! interrupts off
+                                       ! restore PROM mmu globals
+       ldx     [%%sp + 2047 + 0x158], %%o0
+       ldx     [%%sp + 2047 + 0x160], %%o1
+       ldx     [%%sp + 2047 + 0x168], %%l2
+       ldx     [%%sp + 2047 + 0x170], %%l3
+       ldx     [%%sp + 2047 + 0x178], %%l5
+       ldx     [%%sp + 2047 + 0x180], %%l6
+       ldx     [%%sp + 2047 + 0x188], %%l7
+       wrpr    %%g0, 0x414, %%pstate   ! restore PROM mmu globals
+       mov     %%o0, %%g1
+       mov     %%o1, %%g2
+       mov     %%l2, %%g3
+       mov     %%l3, %%g4
+       mov     %%l5, %%g5
+       mov     %%l6, %%g6
+       mov     %%l7, %%g7
+       wrpr    %%l0, %%tba             ! restore PROM tba
+       wrpr    %%g0, 0x14, %%pstate    ! restore PROM normal globals
+       ldx     [%%sp + 2047 + 0x120], %%g1
+       ldx     [%%sp + 2047 + 0x128], %%g2
+       ldx     [%%sp + 2047 + 0x130], %%g3
+       ldx     [%%sp + 2047 + 0x138], %%g4
+       ldx     [%%sp + 2047 + 0x140], %%g5
+       ldx     [%%sp + 2047 + 0x148], %%g6
+       ldx     [%%sp + 2047 + 0x150], %%g7
+       wrpr    %%g0, 0x814, %%pstate   ! restore PROM interrupt globals
+       ldx     [%%sp + 2047 + 0x0e8], %%g1
+       ldx     [%%sp + 2047 + 0x0f0], %%g2
+       ldx     [%%sp + 2047 + 0x0f8], %%g3
+       ldx     [%%sp + 2047 + 0x100], %%g4
+       ldx     [%%sp + 2047 + 0x108], %%g5
+       ldx     [%%sp + 2047 + 0x110], %%g6
+       ldx     [%%sp + 2047 + 0x118], %%g7
+       wrpr    %%g0, 0x15, %%pstate    ! restore PROM alternate globals
+       ldx     [%%sp + 2047 + 0x0b0], %%g1
+       ldx     [%%sp + 2047 + 0x0b8], %%g2
+       ldx     [%%sp + 2047 + 0x0c0], %%g3
+       ldx     [%%sp + 2047 + 0x0c8], %%g4
+       ldx     [%%sp + 2047 + 0x0d0], %%g5
+       ldx     [%%sp + 2047 + 0x0d8], %%g6
+       ldx     [%%sp + 2047 + 0x0e0], %%g7
        wrpr    %%l4, 0, %%pstate
        ret
-        restore
-       " : : "r" (&p1275buf), "i" (0 /* PSTATE_AM */));
+        restore %%l1, 0, %%o0
+       " : : "r" (&p1275buf), "i" (PSTATE_PRIV));
+}
+
+/* We need some SMP protection here.  But be careful as
+ * prom callback code can call into here too, this is why
+ * the counter is needed.  -DaveM
+ */
+static int prom_entry_depth = 0;
+#ifdef __SMP__
+static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
+extern void smp_capture(void);
+extern void smp_release(void);
+#endif
+
+static __inline__ unsigned long prom_get_lock(void)
+{
+       unsigned long flags;
+
+       __save_and_cli(flags);
+       if (prom_entry_depth == 0) {
+               spin_lock(&prom_entry_lock);
+
+#if 1 /* DEBUGGING */
+               if (prom_entry_depth != 0)
+                       panic("prom_get_lock");
+#endif
+#ifdef __SMP__
+               smp_capture();
+#endif
+       }
+       prom_entry_depth++;
+
+       return flags;
+}
+
+static __inline__ void prom_release_lock(unsigned long flags)
+{
+       if (--prom_entry_depth == 0) {
+#ifdef __SMP__
+               smp_release();
+#endif
+               spin_unlock(&prom_entry_lock);
+       }
+       __restore_flags(flags);
 }
 
 long p1275_cmd (char *service, long fmt, ...)
@@ -66,13+300,15 @@ long p1275_cmd (char *service, long fmt, ...)
        long ctx = 0;
        
        p = p1275buf.prom_buffer;
-       __save_and_cli(flags);
        ctx = spitfire_get_primary_context ();
        if (ctx) {
                flushw_user ();
                spitfire_set_primary_context (0);
        }
-       p1275buf.prom_args[0] = (unsigned long)p;                       /* service */
+
+       flags = prom_get_lock();
+
+       p1275buf.prom_args[0] = (unsigned long)p;               /* service */
        strcpy (p, service);
        p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
        p1275buf.prom_args[1] = nargs = (fmt & 0x0f);           /* nargs */
@@ -82,7+318,9 @@ long p1275_cmd (char *service, long fmt, ...)
        for (i = 0; i < nargs; i++, attrs >>= 3) {
                switch (attrs & 0x7) {
                case P1275_ARG_NUMBER:
-                       p1275buf.prom_args[i + 3] = (unsigned)va_arg(list, long); break;
+                       p1275buf.prom_args[i + 3] =
+                                               (unsigned)va_arg(list, long);
+                       break;
                case P1275_ARG_IN_STRING:
                        strcpy (p, va_arg(list, char *));
                        p1275buf.prom_args[i + 3] = (unsigned long)p;
@@ -111,16+349,16 @@ long p1275_cmd (char *service, long fmt, ...)
                        p += 32;
                        break;
                case P1275_ARG_IN_FUNCTION:
-                       p1275buf.prom_args[i + 3] = (unsigned long)prom_cif_interface + 0x38;
-                       p1275buf.prom_sync_routine = va_arg(list, long); break;
+                       p1275buf.prom_args[i + 3] =
+                                       (unsigned long)prom_cif_callback;
+                       p1275buf.prom_callback = va_arg(list, long);
+                       break;
                }
        }
        va_end(list);
 
        prom_world(1);
-       
        prom_cif_interface();
-       
        prom_world(0);
 
        attrs = fmt >> 8;
@@ -128,11+366,14 @@ long p1275_cmd (char *service, long fmt, ...)
        for (i = 0; i < nargs; i++, attrs >>= 3) {
                switch (attrs & 0x7) {
                case P1275_ARG_NUMBER:
-                       (void) va_arg(list, long); break;
+                       (void) va_arg(list, long);
+                       break;
                case P1275_ARG_IN_STRING:
-                       (void) va_arg(list, char *); break;
+                       (void) va_arg(list, char *);
+                       break;
                case P1275_ARG_IN_FUNCTION:
-                       (void) va_arg(list, long); break;
+                       (void) va_arg(list, long);
+                       break;
                case P1275_ARG_IN_BUF:
                        (void) va_arg(list, char *);
                        (void) va_arg(list, long);
@@ -152,10+393,12 @@ long p1275_cmd (char *service, long fmt, ...)
        }
        va_end(list);
        x = p1275buf.prom_args [nargs + 3];
-       
+
+       prom_release_lock(flags);
+
        if (ctx)
                spitfire_set_primary_context (ctx);
-       __restore_flags(flags);
+
        return x;
 }
 
index 691601a..57af750 100644 (file)
@@ -15,10+15,10 @@ CPPFLAGS = $(MODFLAGS)
 endif
 
 .S.s:
-       $(CPP) -D__ASSEMBLY__ $(CPPFLAGS) -ansi $< -o $*.s
+       $(CPP) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s
 
 .S.o:
-       $(CC) -D__ASSEMBLY__ $(CPPFLAGS) -ansi -c $< -o $*.o
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o
 
 ifneq ($(CONFIG_SOLARIS_EMUL),y)
 do_it_all:
index 1b711f4..0f080db 100644 (file)
@@ -240,12+240,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_SUN_OPENPROMIO),y)
-else
-  ifeq ($(CONFIG_SUN_OPENPROMIO),m)
-  endif
-endif
-
 ifeq ($(CONFIG_WDT),y)
 L_OBJS += wdt.o
 else
index 9ae8f60..dc26e44 100644 (file)
  * Parport sharing hacking by Andrea Arcangeli
  * Fixed kernel_(to/from)_user memory copy to check for errors
  *                             by Riccardo Facchetti <fizban@tin.it>
- * Interrupt handling workaround for printers with buggy handshake
- *                             by Andrea Arcangeli, 11 May 98
+ * Redesigned interrupt handling for handle printers with buggy handshake
+ *                             by Andrea Arcangeli, 11 May 1998
+ * Full efficient handling of printer with buggy irq handshake (now I have
+ * understood the meaning of the strange handshake). This is done sending new
+ * characters if the interrupt is just happened, even if the printer say to
+ * be still BUSY. This is needed at least with Epson Stylus Color.
+ * I also fixed the irq on the rising edge of the strobe problem.
+ *                             Andrea Arcangeli, 15 Oct 1998
  */
 
 /* This driver should, in theory, work with any parallel port that has an
  *
  *     ftp://e-mind.com/pub/linux/pscan/
  *
- *                                     11 May 98, Andrea Arcangeli
+ * My printer scanner run on an Epson Stylus Color show that such printer
+ * generates the irq on the _rising_ edge of the STROBE. Now lp handle
+ * this case fine too.
+ *
+ * I also understood that on such printer we are just allowed to send
+ * new characters after the interrupt even if the BUSY line is still active.
+ *
+ *                                     15 Oct 1998, Andrea Arcangeli
  */
 
 #include <linux/module.h>
 
 #include <linux/parport.h>
 #undef LP_STATS
-#undef LP_NEED_CAREFUL
 #include <linux/lp.h>
 
 #include <asm/irq.h>
@@ -115,16+127,21 @@ struct lp_struct lp_table[LP_NO] =
                           NULL, 0, 0, 0}
 };
 
-/* Test if printer is ready (and optionally has no error conditions) */
-#ifdef LP_NEED_CAREFUL
-#define LP_READY(minor, status) \
-  ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : ((status) & LP_PBUSY))
-#define _LP_CAREFUL_READY(status) \
+/*
+ * Test if printer is ready.
+ */
+#define LP_READY(status) \
    ((status) & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
       (LP_PBUSY|LP_PSELECD|LP_PERRORP)
-#else
-#define LP_READY(minor, status) ((status) & LP_PBUSY)
-#endif
+
+/*
+ * Test if the printer has error conditions.
+ */
+#define LP_NO_ERROR(status) \
+   ((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
+      (LP_PSELECD|LP_PERRORP)
+
+#define LP_NO_ACKING(status) ((status) & LP_PACK)
 
 #undef LP_DEBUG
 #undef LP_READ_DEBUG
@@ -187,52+204,88 @@ static int lp_reset(int minor)
        return retval;
 }
 
-static inline int lp_char(char lpchar, int minor)
+static inline void lp_wait(int minor)
 {
        unsigned int wait = 0;
+#ifndef __sparc__
+        /* FIXME: should be function(time) */
+       while (wait++ != LP_WAIT(minor));
+#else
+       udelay(1);
+#endif
+
+}
+
+static inline int lp_char(char lpchar, int minor)
+{
        unsigned long count = 0;
 #ifdef LP_STATS
        struct lp_stats *stats;
 #endif
 
+       if (signal_pending(current))
+               return 0;
+
        for (;;)
        {
+               unsigned char status;
                lp_yield(minor);
-               if (LP_READY(minor, r_str(minor)))
+
+               status = r_str(minor);
+               /*
+                * On Epson Stylus Color we must continue even if LP_READY()
+                * is false to be efficient. This way is backwards
+                * compatible with old not-buggy printers. -arca
+                */
+               if (LP_NO_ERROR(status) &&
+                   ((lp_table[minor].irq_detected && LP_NO_ACKING(status)) ||
+                    LP_READY(status)))
                        break;
-               if (++count == LP_CHAR(minor) || signal_pending(current))
-                       return 0;
+               /*
+                * To have a chance to sleep on the interrupt we should break
+                * the polling loop ASAP. Unfortunately there seems to be
+                * some hardware that underperform so we leave this
+                * configurable at runtime. So when printing with irqs
+                * `tunelp /dev/lp0 -c 1' is a must to take the full
+                * advantage of the irq. -arca
+                */
+               if (++count == LP_CHAR(minor))
+                       return 0;
        }
 
        w_dtr(minor, lpchar);
+
 #ifdef LP_STATS
        stats = &LP_STAT(minor);
        stats->chars++;
 #endif
+
+       /*
+        * Epson Stylus Color generate the IRQ on the rising edge of
+        * strobe so clean the irq's information before playing with
+        * the strobe. -arca
+        */
+       lp_table[minor].irq_detected = 0;
+       lp_table[minor].irq_missed = 0;
+       /*
+        * Be sure that the CPU doesn' t reorder instruction. I am not sure
+        * if it' s needed also before an outb(). If not tell me ;-). -arca
+        */
+       mb();
+
        /* must wait before taking strobe high, and after taking strobe
           low, according spec.  Some printers need it, others don't. */
-#ifndef __sparc__
-       while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */
-               wait++;
-#else
-       udelay(1);
-#endif
+       lp_wait(minor);
+
        /* control port takes strobe high */
-       w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
-#ifndef __sparc__
-       while (wait)                    /* FIXME: should be a udelay() */
-               wait--;
-#else
-       udelay(1);
-#endif
-       /* take strobe low */
        if (LP_POLLED(minor))
-               /* take strobe low */
-               w_ctr(minor, LP_PSELECP | LP_PINITP);
-       else
        {
-               lp_table[minor].irq_detected = 0;
-               lp_table[minor].irq_missed = 0;
+               w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
+               lp_wait(minor);
+               w_ctr(minor, LP_PSELECP | LP_PINITP);
+       } else {
+               w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE | LP_PINTEN);
+               lp_wait(minor);
                w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
        }
 
@@ -240,7+293,8 @@ static inline int lp_char(char lpchar, int minor)
        /* update waittime statistics */
        if (count > stats->maxwait) {
 #ifdef LP_DEBUG
-               printk(KERN_DEBUG "lp%d success after %d counts.\n", minor, count);
+               printk(KERN_DEBUG "lp%d success after %d counts.\n",
+                      minor, count);
 #endif
                stats->maxwait = count;
        }
@@ -325,8+379,12 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count)
        lp_table[minor].last_error = 0;
        lp_table[minor].irq_detected = 0;
        lp_table[minor].irq_missed = 1;
+       LP_POLLED(minor) = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE;
 
-       w_ctr(minor, LP_PSELECP | LP_PINITP);
+       if (LP_POLLED(minor))
+               w_ctr(minor, LP_PSELECP | LP_PINITP);
+       else
+               w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
 
        do {
                bytes_written = 0;
@@ -649,14+707,6 @@ static int lp_ioctl(struct inode *inode, struct file *file,
                        else
                                LP_F(minor) &= ~LP_ABORTOPEN;
                        break;
-#ifdef LP_NEED_CAREFUL
-               case LPCAREFUL:
-                       if (arg)
-                               LP_F(minor) |= LP_CAREFUL;
-                       else
-                               LP_F(minor) &= ~LP_CAREFUL;
-                       break;
-#endif
                case LPWAIT:
                        LP_WAIT(minor) = arg;
                        break;
index ba5f825..71577f3 100644 (file)
@@ -35,6+35,9 @@ void soundcard_init(void);
 void dmasound_init(void);
 #endif
 #endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
 #ifdef CONFIG_ISDN
 int isdn_init(void);
 #endif
@@ -571,6+574,9 @@ __initfunc(int chr_dev_init(void))
        dmasound_init();
 #endif 
 #endif
+#ifdef CONFIG_SPARCAUDIO
+       sparcaudio_init();
+#endif
 #ifdef CONFIG_JOYSTICK
        /*
         *      Some joysticks only appear when the sound card they are
index efc6738..f82166b 100644 (file)
@@ -43,7+43,7 @@ static int users = 0;
  * 92.7400017 -> 92.75
  */
 #define RSF16_ENCODE(x)        ((x)/800+214)
-#define RSF16_MINFREQ 88*16000
+#define RSF16_MINFREQ 87*16000
 #define RSF16_MAXFREQ 108*16000
 
 static void outbits(int bits, unsigned int data, int port)
@@ -64,27+64,32 @@ static void outbits(int bits, unsigned int data, int port)
        }
 }
 
-static void fmi_mute(int port)
+static inline void fmi_mute(int port)
 {
        outb(0x00, port);
 }
 
-static void fmi_unmute(int port)
+static inline void fmi_unmute(int port)
 {
        outb(0x08, port);
 }
 
-static int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
+static inline int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
 {
         int myport = dev->port;
 
        outbits(16, RSF16_ENCODE(freq), myport);
        outbits(8, 0xC0, myport);
-       /* we should wait here... */
+       /* it is better than udelay(140000), isn't it? */
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + HZ/7;
+       schedule();
+       /* ignore signals, we really should restore volume */
+       if (dev->curvol) fmi_unmute(myport);
        return 0;
 }
 
-static int fmi_getsigstr(struct fmi_device *dev)
+static inline int fmi_getsigstr(struct fmi_device *dev)
 {
        int val;
        int res;
@@ -93,10+98,17 @@ static int fmi_getsigstr(struct fmi_device *dev)
        val = dev->curvol ? 0x08 : 0x00;        /* unmute/mute */
        outb(val, myport);
        outb(val | 0x10, myport);
-       udelay(140000);
+       /* it is better than udelay(140000), isn't it? */
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + HZ/7;
+       schedule();
+       /* do not do it..., 140ms is very looong time to get signal in real program 
+       if (signal_pending(current))
+           return -EINTR;
+       */
        res = (int)inb(myport+1);
        outb(val, myport);
-       return (res & 2) ? 0 : 1;
+       return (res & 2) ? 0 : 0xFFFF;
 }
 
 static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
@@ -136,7+148,7 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        v.rangehigh = RSF16_MAXFREQ/mult;
                        v.flags=fmi->flags;
                        v.mode=VIDEO_MODE_AUTO;
-                       v.signal=0xFFFF*fmi_getsigstr(fmi);
+                       v.signal = fmi_getsigstr(fmi);
                        if(copy_to_user(arg,&v, sizeof(v)))
                                return -EFAULT;
                        return 0;
index aef8103..2ced2f1 100644 (file)
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/feature.h>
 #include "bmac.h"
 
 #define trunc_page(x)  ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
 /* switch to use multicast code lifted from sunhme driver */
 #define SUNHME_MULTICAST
 
-/* a bunch of constants for the "Heathrow" interrupt controller.
-   These really should be in an include file somewhere */
-#define IoBaseHeathrow ((unsigned *)0xf3000000)
-#define HeathrowFCR 0x0038     /* FCR offset from Heathrow Base Address */
-#define fcrEnetEnabledBits     0x60000000 /* mask to enable Enet Xcvr/Controller */
-#define fcrResetEnetCell       0x80000000 /* mask used to reset Enet cell */
-#define fcrClearResetEnetCell  0x7fffffff /* mask used to clear reset Enet cell */
-#define fcrDisableEnet         0x1fffffff /* mask to disable Enet Xcvr/Controller */
-
 #define N_RX_RING      64
 #define N_TX_RING      32
 #define MAX_TX_ACTIVE  1
@@ -122,6+114,7 @@ bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
 };
 
 struct device *bmac_devs = NULL;
+static int is_bmac_plus;
 
 #if 0
 /*
@@ -157,8+150,6 @@ static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void bmac_set_timeout(struct device *dev);
 static void bmac_tx_timeout(unsigned long data);
-static void bmac_reset_chip(struct device *dev);
-static void bmac_init_registers(struct device *dev);
 static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy);
 static int bmac_output(struct sk_buff *skb, struct device *dev);
 static void bmac_start(struct device *dev);
@@ -240,34+231,86 @@ bmac_reset_chip(struct device *dev)
        struct bmac_data *bp = (struct bmac_data *) dev->priv;
        volatile struct dbdma_regs *rd = bp->rx_dma;
        volatile struct dbdma_regs *td = bp->tx_dma;
-       volatile unsigned *heathrowFCR;
-       unsigned int fcrValue;
         
        dbdma_reset(rd);
        dbdma_reset(td);
 
-       heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR);
+       feature_set(FEATURE_BMac_IO_enable);
+       udelay(10000);
+       feature_set(FEATURE_BMac_reset);
+       udelay(10000);
+       feature_clear(FEATURE_BMac_reset);
+       udelay(10000);
+}
 
-       fcrValue = in_le32(heathrowFCR);
+#define MIFDELAY       udelay(500)
 
-       fcrValue &= fcrDisableEnet;     /* clear out Xvr and Controller Bit */
-       out_le32(heathrowFCR, fcrValue);
-       udelay(50000);
+static unsigned int
+bmac_mif_readbits(struct device *dev, int nb)
+{
+       unsigned int val = 0;
+
+       while (--nb >= 0) {
+               bmwrite(dev, MIFCSR, 0);
+               MIFDELAY;
+               if (bmread(dev, MIFCSR) & 8)
+                       val |= 1 << nb;
+               bmwrite(dev, MIFCSR, 1);
+               MIFDELAY;
+       }
+       bmwrite(dev, MIFCSR, 0);
+       MIFDELAY;
+       bmwrite(dev, MIFCSR, 1);
+       MIFDELAY;
+       return val;
+}
 
-       fcrValue |= fcrResetEnetCell;   /* set bit to reset them */
-       out_le32(heathrowFCR, fcrValue);
-       udelay(50000);
-       
-       fcrValue &= fcrDisableEnet;
-       out_le32(heathrowFCR, fcrValue);
-       udelay(50000);
+static void
+bmac_mif_writebits(struct device *dev, unsigned int val, int nb)
+{
+       int b;
+
+       while (--nb >= 0) {
+               b = (val & (1 << nb))? 6: 4;
+               bmwrite(dev, MIFCSR, b);
+               MIFDELAY;
+               bmwrite(dev, MIFCSR, b|1);
+               MIFDELAY;
+       }
+}
 
-       fcrValue |= fcrEnetEnabledBits;
-       out_le32(heathrowFCR, fcrValue);
-       udelay(50000);
-       
-       out_le32(heathrowFCR, fcrValue);
-       udelay(50000);
+static unsigned int
+bmac_mif_read(struct device *dev, unsigned int addr)
+{
+       unsigned int val;
+
+       bmwrite(dev, MIFCSR, 4);
+       MIFDELAY;
+       bmac_mif_writebits(dev, ~0U, 32);
+       bmac_mif_writebits(dev, 6, 4);
+       bmac_mif_writebits(dev, addr, 10);
+       bmwrite(dev, MIFCSR, 2);
+       MIFDELAY;
+       bmwrite(dev, MIFCSR, 1);
+       MIFDELAY;
+       val = bmac_mif_readbits(dev, 17);
+       bmwrite(dev, MIFCSR, 4);
+       MIFDELAY;
+       printk(KERN_DEBUG "bmac_mif_read(%x) -> %x\n", addr, val);
+       return val;
+}
+
+static void
+bmac_mif_write(struct device *dev, unsigned int addr, unsigned int val)
+{
+       bmwrite(dev, MIFCSR, 4);
+       MIFDELAY;
+       bmac_mif_writebits(dev, ~0U, 32);
+       bmac_mif_writebits(dev, 5, 4);
+       bmac_mif_writebits(dev, addr, 10);
+       bmac_mif_writebits(dev, 2, 2);
+       bmac_mif_writebits(dev, val, 16);
+       bmac_mif_writebits(dev, 3, 2);
 }
 
 static void
@@ -280,14+323,23 @@ bmac_init_registers(struct device *dev)
 
        /* XXDEBUG(("bmac: enter init_registers\n")); */
 
+       bmwrite(dev, RXRST, RxResetValue);
        bmwrite(dev, TXRST, TxResetBit);
 
+       i = 100;
        do {
+               --i;
+               udelay(10000);
                regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
-       } while (regValue & TxResetBit);
+       } while ((regValue & TxResetBit) && i > 0);
+
+       if (!is_bmac_plus) {
+               regValue = bmread(dev, XCVRIF);
+               regValue |= ClkBit | SerialMode | COLActiveLow;
+               bmwrite(dev, XCVRIF, regValue);
+               udelay(10000);
+       }
 
-       bmwrite(dev, RXRST, RxResetValue);
-       bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow);       
        bmwrite(dev, RSEED, (unsigned short)0x1968);            
 
        regValue = bmread(dev, XIFC);
@@ -366,18+418,30 @@ bmac_start_chip(struct device *dev)
 
        /* enable rx dma channel */
        dbdma_continue(rd);
+       oldConfig = bmread(dev, TXCFG);         
+       bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
   
        /* turn on rx plus any other bits already on (promiscuous possibly) */
        oldConfig = bmread(dev, RXCFG);         
        bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 
-       oldConfig = bmread(dev, TXCFG);         
-       bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
+       udelay(20000);
 }
 
 static int
 bmac_init_chip(struct device *dev)
 {
+       if (is_bmac_plus && bmac_mif_read(dev, 2) == 0x7810) {
+               if (bmac_mif_read(dev, 4) == 0xa1) {
+                       bmac_mif_write(dev, 0, 0x1000);
+               } else {
+                       bmac_mif_write(dev, 4, 0xa1);
+                       bmac_mif_write(dev, 0, 0x1200);
+               }
+               /* XXX debugging */
+               bmac_mif_read(dev, 0);
+               bmac_mif_read(dev, 4);
+       }
        bmac_init_registers(dev);
        return 1;
 }
@@ -1144,8+1208,16 @@ bmac_probe(struct device *dev)
        unsigned char *addr;
        static struct device_node *all_bmacs = NULL, *next_bmac;
 
-       if (all_bmacs == NULL)
-               all_bmacs = next_bmac = find_devices("bmac");
+       if (all_bmacs == NULL) {
+               all_bmacs = find_devices("bmac");
+               is_bmac_plus = 0;
+               if (all_bmacs == NULL) {
+                       all_bmacs = find_compatible_devices("network", "bmac+");
+                       if (all_bmacs)
+                               is_bmac_plus = 1;
+               }
+               next_bmac = all_bmacs;
+       }
        bmacs = next_bmac;
        if (bmacs == NULL) return -ENODEV;
        next_bmac = bmacs->next;
@@ -1157,7+1229,7 @@ bmac_probe(struct device *dev)
                       bmacs->full_name);
                return -EINVAL;
        }
-    
+
        if (dev == NULL) {
                dev = init_etherdev(NULL, PRIV_BYTES);
                bmac_devs = dev;  /*KLUDGE!!*/
index 5f1576d..ac1b532 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: pcikbd.c,v 1.22 1998/09/21 05:06:45 jj Exp $
+/* $Id: pcikbd.c,v 1.23 1998/10/07 11:35:24 jj Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
 #else
 #define PCI_KB_NAME    "keyboard"
 #define PCI_MS_NAME    "mouse"
-/*
- * XXX.
- * Gleb defines check_region and request_region here.
- * This looks suspicios because he neglects to call
- * sparc_alloc_io, but the conflict with sparc_alloc_io is what
- * causes problems.
- */
 #endif
 
 #include "pcikbd.h"
@@ -517,7+510,7 @@ __initfunc(void pcikbd_init_hw(void))
                        for_each_ebusdev(edev, ebus) {
                                if(!strcmp(edev->prom_name, "8042")) {
                                        for_each_edevchild(edev, child) {
-                                               if (!strcmp(child->prom_name, "kb_ps2"))
+                                                if (!strcmp(child->prom_name, PCI_KB_NAME))
                                                        goto found;
                                        }
                                }
index 4073e0e..42a92f7 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sab82532.c,v 1.23 1998/09/16 03:20:25 ecd Exp $
+/* $Id: sab82532.c,v 1.26 1998/10/25 06:46:41 ecd Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -88,6+88,7 @@ static char *sab82532_version[16] = {
        "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)",
        "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)"
 };
+static char serial_version[16];
 
 /*
  * tmp_buf is used as a temporary buffer by sab82532_write.  We need to
@@ -505,7+506,7 @@ check_modem:
 #endif
        }
        if ((info->regs->r.pvr & info->pvr_dsr_bit) ^ info->dsr) {
-               info->dsr = info->regs->r.pvr & info->pvr_dsr_bit;
+               info->dsr = (info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : 1;
                info->icount.dsr++;
                modem_change++;
 #if 0
@@ -786,6+787,12 @@ static int startup(struct sab82532 *info)
         */
        sab82532_init_line(info);
 
+       if (info->tty->termios->c_cflag & CBAUD) {
+               info->regs->rw.mode &= ~(SAB82532_MODE_FRTS);
+               info->regs->rw.mode |= SAB82532_MODE_RTS;
+               info->regs->rw.pvr &= ~(info->pvr_dtr_bit);
+       }
+
        /*
         * Finally, enable interrupts
         */
@@ -951,8+958,9 @@ static void change_speed(struct sab82532 *info)
        ebrg = ebrg_table[i].n;
        ebrg |= (ebrg_table[i].m << 6);
 
-       if (ebrg_table[i].baud)
-               info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud;
+       info->baud = ebrg_table[i].baud;
+       if (info->baud)
+               info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
        else
                info->timeout = 0;
        info->timeout += HZ / 50;               /* Add .02 seconds of slop */
@@ -1278,7+1286,9 @@ static int get_modem_info(struct sab82532 * info, unsigned int *value)
 {
        unsigned int result;
 
-       result =  ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS)
+       result =  ((info->regs->r.mode & SAB82532_MODE_RTS) ? 
+                   ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS)
+                                                           : TIOCM_RTS)
                | ((info->regs->r.pvr & info->pvr_dtr_bit) ? 0 : TIOCM_DTR)
                | ((info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR)
                | ((info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : TIOCM_DSR)
@@ -1952,9+1962,11 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp)
  * /proc fs routines....
  */
 
-static int inline line_info(char *buf, struct tty_struct *tty)
+static __inline__ int
+line_info(char *buf, struct sab82532 *info)
 {
-       struct sab82532 *info = (struct sab82532 *)tty->driver_data;
+       unsigned long flags;
+       char stat_buf[30];
        int ret;
 
        ret = sprintf(buf, "%d: uart:SAB82532 ", info->line);
@@ -1972,8+1984,8 @@ static int inline line_info(char *buf, struct tty_struct *tty)
                        ret += sprintf(buf+ret, "V?.? ");
                        break;
        }
-       ret += sprintf(buf+ret, "port:%lX irq:%d",
-                      (unsigned long)info->regs, info->irq);
+       ret += sprintf(buf+ret, "port:%lX irq:%s",
+                      (unsigned long)info->regs, __irq_itoa(info->irq));
 
        if (!info->regs) {
                ret += sprintf(buf+ret, "\n");
@@ -1983,20+1995,57 @@ static int inline line_info(char *buf, struct tty_struct *tty)
        /*
         * Figure out the current RS-232 lines
         */
+       stat_buf[0] = 0;
+       stat_buf[1] = 0;
+       save_flags(flags); cli();
+       if (info->regs->r.mode & SAB82532_MODE_RTS) {
+               if (!(info->regs->r.mode & SAB82532_MODE_FRTS))
+                       strcat(stat_buf, "|RTS");
+       } else {
+               strcat(stat_buf, "|RTS");
+       }
+       if (info->regs->r.star & SAB82532_STAR_CTS)
+               strcat(stat_buf, "|CTS");
+       if (!(info->regs->r.pvr & info->pvr_dtr_bit))
+               strcat(stat_buf, "|DTR");
+       if (!(info->regs->r.pvr & info->pvr_dsr_bit))
+               strcat(stat_buf, "|DSR");
+       if (!(info->regs->r.vstr & SAB82532_VSTR_CD))
+               strcat(stat_buf, "|CD");
+       restore_flags(flags);
+
+       if (info->baud)
+               ret += sprintf(buf+ret, " baud:%d", info->baud);
+
+       if (info->icount.frame)
+               ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+
+       if (info->icount.parity)
+               ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
 
-       ret += sprintf(buf+ret, "\n");
+       if (info->icount.brk)
+               ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+
+       if (info->icount.overrun)
+               ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines.
+        */
+       ret += sprintf(buf+ret, " %s\n", stat_buf + 1);
        return ret;
 }
 
 int sab82532_read_proc(char *page, char **start, off_t off, int count,
                       int *eof, void *data)
 {
-       int i, len = 0;
-       off_t   begin = 0;
+       struct sab82532 *info = sab82532_chain;
+       off_t begin = 0;
+       int len = 0;
 
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.23 $");
-       for (i = 0; i < NR_PORTS && len < 4000; i++) {
-               len += line_info(page + len, sab82532_table[i]);
+       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+       for (info = sab82532_chain; info && len < 4000; info = info->next) {
+               len += line_info(page + len, info);
                if (len+begin > off+count)
                        goto done;
                if (len+begin < off) {
@@ -2089,13+2138,14 @@ sab82532_kgdb_hook(int line))
 
 __initfunc(static inline void show_serial_version(void))
 {
-       char *revision = "$Revision: 1.23 $";
+       char *revision = "$Revision: 1.26 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
-       p = strchr(++version, ' ');
+       strcpy(serial_version, ++version);
+       p = strchr(serial_version, ' ');
        *p = '\0';
-       printk("SAB82532 serial driver version %s\n", version);
+       printk("SAB82532 serial driver version %s\n", serial_version);
 }
 
 /*
@@ -2456,8+2506,9 @@ sab82532_console_setup(struct console *con, char *options)
        ebrg = ebrg_table[i].n;
        ebrg |= (ebrg_table[i].m << 6);
 
-       if (ebrg_table[i].baud)
-               info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud;
+       info->baud = ebrg_table[i].baud;
+       if (info->baud)
+               info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
        else
                info->timeout = 0;
        info->timeout += HZ / 50;               /* Add .02 seconds of slop */
@@ -2490,6+2541,7 @@ sab82532_console_setup(struct console *con, char *options)
                info->regs->rw.mode &= ~(SAB82532_MODE_FRTS);
                info->regs->rw.mode |= SAB82532_MODE_FCTS;
        }
+       info->regs->rw.pvr &= ~(info->pvr_dtr_bit);
        info->regs->rw.mode |= SAB82532_MODE_RAC;
        restore_flags(flags);
 
similarity index 70%
rename from drivers/sbus/char/su32.c
rename to drivers/sbus/char/su.c
index 537c90d..7cb48cb 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: su32.c,v 1.1 1998/09/18 10:45:32 jj Exp $
+/* $Id: su.c,v 1.12 1998/10/25 04:24:52 ecd Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
 #define CONFIG_SERIAL_NOPAUSE_IO       /* Unused on sparc */
 #define SERIAL_DO_RESTART
 
-#if 1
-/* Normally these defines are controlled by the autoconf.h */
-
-#undef CONFIG_SERIAL_MANY_PORTS
-#define CONFIG_SERIAL_SHARE_IRQ                /* Must be enabled for MrCoffee. */
-#undef CONFIG_SERIAL_DETECT_IRQ                /* code is removed from su.c */
-#undef CONFIG_SERIAL_MULTIPORT
-#endif
-
-/* Sanity checks */
-
-#ifdef CONFIG_SERIAL_MULTIPORT
-#ifndef CONFIG_SERIAL_SHARE_IRQ
-#define CONFIG_SERIAL_SHARE_IRQ
-#endif
-#endif
-
 /* Set of debugging defines */
 
 #undef SERIAL_DEBUG_INTR
 #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 #undef SERIAL_DEBUG_THROTTLE
 
-/* */
-
-#define RS_STROBE_TIME (10*HZ)
 #define RS_ISR_PASS_LIMIT 256
 
-#ifdef __sparc_v9__
-#define IRQ_4M(n)      (n)
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
-#else
-/* 0x20 is sun4m thing, Dave Redman heritage. See arch/sparc/kernel/irq.c. */
+/*
+ * 0x20 is sun4m thing, Dave Redman heritage.
+ * See arch/sparc/kernel/irq.c.
+ */
 #define IRQ_4M(n)      ((n)|0x20)
-/* Interrupts must be shared on MrCoffee. */
-#define IRQ_T(info)    SA_SHIRQ
-#endif
 
-#define SERIAL_INLINE
-  
 #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
+#define DBG_CNT(s)                                                     \
+do {                                                                   \
+       printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n",          \
+              kdevname(tty->device), (info->flags), serial_refcount,   \
+              info->count,tty->count,s);                               \
+} while (0);
 #else
 #define DBG_CNT(s)
 #endif
 /*
  * End of serial driver configuration section.
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
-#if 0 /* P3: Needed if we to support /sbin/setserial. */
-#include <asm/serial.h>
-#endif
 
 #include "sunserial.h"
 #include "sunkbd.h"
@@ -128,24+101,22 @@ struct su_struct {
        int              magic;
        unsigned long    port;
        int              baud_base;
-       int             type;                   /* Hardware type: e.g. 16550 */
+       int              type;          /* Hardware type: e.g. 16550 */
        int              irq;
        int              flags;
        int              line;
        int              cflag;
 
-       /* XXX Unify. */
        int              kbd_node;
        int              ms_node;
        int              port_node;
 
        char             name[16];
 
-       int             xmit_fifo_size;
-       int             custom_divisor;
-       unsigned short  close_delay;
-       unsigned short  closing_wait; /* time to wait before closing */
-       unsigned short  closing_wait2; /* no longer used... */
+       int              xmit_fifo_size;
+       int              custom_divisor;
+       unsigned short   close_delay;
+       unsigned short   closing_wait;  /* time to wait before closing */
 
        struct tty_struct       *tty;
        int                     read_status_mask;
@@ -168,30+139,14 @@ struct su_struct {
        struct wait_queue       *close_wait;
        struct wait_queue       *delta_msr_wait;
 
-       struct su_struct        *next_port;
-       struct su_struct        *prev_port;
-
        int                     count;
        struct async_icount     icount;
        struct termios          normal_termios, callout_termios;
        unsigned long           last_active;    /* For async_struct, to be */
 };
 
-#if 0 /* P3: became unused after surgery. */
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-#endif
-
-#ifdef SERIAL_INLINE
-#define _INLINE_ inline
-#endif
-
-static char *serial_name = "Serial driver";
-static char *serial_version = "4.25.s1";
+static char *serial_name = "PCIO serial driver";
+static char *serial_version = "1.1";
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
@@ -201,16+156,6 @@ static int serial_refcount;
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
-/*
- * IRQ_timeout         - How long the timeout should be for each IRQ
- *                             should be after the IRQ has been active.
- */
-static struct su_struct *IRQ_ports[NR_IRQS];
-#ifdef CONFIG_SERIAL_MULTIPORT
-static struct rs_multiport_struct rs_multiport[NR_IRQS];
-#endif
-static int IRQ_timeout[NR_IRQS];
-
 static void autoconfig(struct su_struct *info);
 static void change_speed(struct su_struct *info);
 static void su_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -317,8+262,8 @@ su_outb(struct su_struct *info, unsigned long offset, int value)
 
 #endif
 
-#define serial_in(info, off)   su_inb(info, off)
-#define serial_inp(info, off)  su_inb(info, off)
+#define serial_in(info, off)           su_inb(info, off)
+#define serial_inp(info, off)          su_inb(info, off)
 #define serial_out(info, off, val)     su_outb(info, off, val)
 #define serial_outp(info, off, val)    su_outb(info, off, val)
 
@@ -387,22+332,20 @@ static void su_start(struct tty_struct *tty)
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
  */
-static _INLINE_ void su_sched_event(struct su_struct *info, int event)
+static __inline__ void
+su_sched_event(struct su_struct *info, int event)
 {
        info->event |= 1 << event;
        queue_task(&info->tqueue, &tq_serial);
        mark_bh(SERIAL_BH);
 }
 
-static _INLINE_ void receive_chars(struct su_struct *info, int *status,
-               struct pt_regs *regs)
+static __inline__ void
+receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs)
 {
-       struct tty_struct *tty = info->tty;
+       unsigned char status = 0;
        unsigned char ch;
-       int ignored = 0;
-       struct  async_icount *icount;
 
-       icount = &info->icount;
        do {
                ch = serial_inp(info, UART_RX);
                if (info->kbd_node) {
@@ -427,6+370,23 @@ static _INLINE_ void receive_chars(struct su_struct *info, int *status,
                } else {
                        sun_mouse_inbyte(ch);
                }
+
+               status = su_inb(info, UART_LSR);
+       } while (status & UART_LSR_DR);
+}
+
+static __inline__ void
+receive_serial_chars(struct su_struct *info, int *status, struct pt_regs *regs)
+{
+       struct tty_struct *tty = info->tty;
+       unsigned char ch;
+       int ignored = 0;
+       struct  async_icount *icount;
+
+       icount = &info->icount;
+       do {
+               ch = serial_inp(info, UART_RX);
+
                if (tty->flip.count >= TTY_FLIPBUF_SIZE)
                        break;
                *tty->flip.char_buf_ptr = ch;
@@ -455,7+415,7 @@ static _INLINE_ void receive_chars(struct su_struct *info, int *status,
                         * Now check to see if character should be
                         * ignored, and mask off conditions which
                         * should be ignored.
- */
                       */
                        if (*status & info->ignore_status_mask) {
                                if (++ignored > 100)
                                        break;
@@ -497,7+457,8 @@ static _INLINE_ void receive_chars(struct su_struct *info, int *status,
        tty_flip_buffer_push(tty);
 }
 
-static _INLINE_ void transmit_chars(struct su_struct *info, int *intr_done)
+static __inline__ void
+transmit_chars(struct su_struct *info, int *intr_done)
 {
        int count;
 
@@ -540,7+501,8 @@ static _INLINE_ void transmit_chars(struct su_struct *info, int *intr_done)
        }
 }
 
-static _INLINE_ void check_modem_status(struct su_struct *info)
+static __inline__ void
+check_modem_status(struct su_struct *info)
 {
        int     status;
        struct  async_icount *icount;
@@ -607,222+569,79 @@ static _INLINE_ void check_modem_status(struct su_struct *info)
                }
        }
 }
-       
-#ifdef CONFIG_SERIAL_SHARE_IRQ
+
 /*
- * This is the serial driver's generic interrupt routine
-        */
-static void su_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+ * This is the kbd/mouse serial driver's interrupt routine
+ */
+static void
+su_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-       int status;
-       struct su_struct *info;
-       int pass_counter = 0;
-       struct su_struct *end_mark = 0;
-#ifdef CONFIG_SERIAL_MULTIPORT
-       int first_multi = 0;
-       struct su_multiport_struct *multi;
-#endif
+       struct su_struct *info = (struct su_struct *)dev_id;
+       unsigned char status;
 
 #ifdef SERIAL_DEBUG_INTR
        printk("su_interrupt(%s)...", __irq_itoa(irq));
 #endif
-
-       info = IRQ_ports[irq];
        if (!info)
                return;
-       
-#ifdef CONFIG_SERIAL_MULTIPORT 
-       multi = &rs_multiport[irq];
-       if (multi->port_monitor)
-               first_multi = inb(multi->port_monitor);
-#endif
 
-       do {
-               if (!info->tty ||
-                   (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
-                       if (!end_mark)
-                               end_mark = info;
-                       goto next;
-               }
-               end_mark = 0;
+       if (serial_in(info, UART_IIR) & UART_IIR_NO_INT)
+               return;
 
-               info->last_active = jiffies;
-       
-               status = serial_inp(info, UART_LSR);
+       status = serial_inp(info, UART_LSR);
 #ifdef SERIAL_DEBUG_INTR
-               printk("status = %x...", status);
+       printk("status = %x...", status);
 #endif
-               if (status & UART_LSR_DR)
-                       receive_chars(info, &status, regs);
-               check_modem_status(info);
-               if (status & UART_LSR_THRE)
-                       transmit_chars(info, 0);
+       if (status & UART_LSR_DR)
+               receive_kbd_ms_chars(info, regs);
 
-       next:
-               info = info->next_port;
-               if (!info) {
-                       info = IRQ_ports[irq];
-                       if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
-                               printk("rs loop break\n");
-#endif
-                               break;  /* Prevent infinite loops */
-                       }
-                       continue;
-               }
-       } while (end_mark != info);
-#ifdef CONFIG_SERIAL_MULTIPORT 
-       if (multi->port_monitor)
-               printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
-                      info->irq, first_multi,
-                      inb(multi->port_monitor));
-#endif
 #ifdef SERIAL_DEBUG_INTR
        printk("end.\n");
 #endif
 }
-#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
-       
 
 /*
- * This is the serial driver's interrupt routine for a single port
+ * This is the serial driver's generic interrupt routine
  */
-static void su_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+static void
+su_serial_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        int status;
+       struct su_struct *info;
        int pass_counter = 0;
-       struct su_struct * info;
-#ifdef CONFIG_SERIAL_MULTIPORT 
-       int first_multi = 0;
-       struct rs_multiport_struct *multi;
-#endif
 
 #ifdef SERIAL_DEBUG_INTR
-       printk("su_interrupt_single(%d) int=%x ...", irq,
-                       serial_inp(&su_table[0], UART_IIR));
+       printk("su_interrupt(%s)...", __irq_itoa(irq));
 #endif
-       
-       info = IRQ_ports[irq];
+       info = (struct su_struct *)dev_id;
        if (!info || !info->tty)
                return;
-
-#ifdef CONFIG_SERIAL_MULTIPORT 
-       multi = &rs_multiport[irq];
-       if (multi->port_monitor)
-               first_multi = inb(multi->port_monitor);
-#endif
-
+       
        do {
                status = serial_inp(info, UART_LSR);
 #ifdef SERIAL_DEBUG_INTR
                printk("status = %x...", status);
 #endif
                if (status & UART_LSR_DR)
-                       receive_chars(info, &status, regs);
+                       receive_serial_chars(info, &status, regs);
                check_modem_status(info);
                if (status & UART_LSR_THRE)
                        transmit_chars(info, 0);
+
                if (pass_counter++ > RS_ISR_PASS_LIMIT) {
 #if 0
-                       printk("su_single loop break.\n");
+                       printk("rs loop break\n");
 #endif
-                       break;
+                       break;  /* Prevent infinite loops */
                }
        } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
-       info->last_active = jiffies;
-#ifdef CONFIG_SERIAL_MULTIPORT 
-       if (multi->port_monitor)
-               printk("rs port monitor (single) irq %s: 0x%x, 0x%x\n",
-                      __irq_itoa(info->irq), first_multi,
-                      inb(multi->port_monitor));
-#endif
-#ifdef SERIAL_DEBUG_INTR
-       printk("end.\n");
-#endif
-}
-
-#ifdef CONFIG_SERIAL_MULTIPORT 
-/*
- * This is the serial driver's for multiport boards
- */
-static void su_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
-{
-       int status;
-       struct su_struct * info;
-       int pass_counter = 0;
-       int first_multi= 0;
-       struct rs_multiport_struct *multi;
-
-#ifdef SERIAL_DEBUG_INTR
-       printk("rs_interrupt_multi(%d)...", irq);
-#endif
-
-       info = IRQ_ports[irq];
-       if (!info)
-               return;
-       multi = &rs_multiport[irq];
-       if (!multi->port1) {
-               /* Should never happen */
-               printk("rs_interrupt_multi: NULL port1!\n");
-               return;
-       }
-       if (multi->port_monitor)
-               first_multi = inb(multi->port_monitor);
-
-       while (1) {
-               if (!info->tty ||
-                   (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
-                       goto next;
 
-               info->last_active = jiffies;
-
-               status = serial_inp(info, UART_LSR);
-#ifdef SERIAL_DEBUG_INTR
-               printk("status = %x...", status);
-#endif
-               if (status & UART_LSR_DR)
-                       receive_chars(info, &status, regs);
-               check_modem_status(info);
-               if (status & UART_LSR_THRE)
-                       transmit_chars(info, 0);
-
-       next:
-               info = info->next_port;
-               if (info)
-                       continue;
+       info->last_active = jiffies;
 
-               info = IRQ_ports[irq];
-               if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 1
-                       printk("rs_multi loop break\n");
-#endif
-                       break;  /* Prevent infinite loops */
-               }
-               if (multi->port_monitor)
-                       printk("rs port monitor irq %d: 0x%x, 0x%x\n",
-                              info->irq, first_multi,
-                              inb(multi->port_monitor));
-               if ((inb(multi->port1) & multi->mask1) != multi->match1)
-                       continue;
-               if (!multi->port2)
-                       break;
-               if ((inb(multi->port2) & multi->mask2) != multi->match2)
-                       continue;
-               if (!multi->port3)
-                       break;
-               if ((inb(multi->port3) & multi->mask3) != multi->match3)
-                       continue;
-               if (!multi->port4)
-                       break;
-               if ((inb(multi->port4) & multi->mask4) == multi->match4)
-                       continue;
-               break;
-       } 
 #ifdef SERIAL_DEBUG_INTR
        printk("end.\n");
 #endif
 }
-#endif
 
 /*
  * -------------------------------------------------------------------
@@ -839,12+658,14 @@ static void su_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
  * interrupt driver proper are done; the interrupt driver schedules
  * them using su_sched_event(), and they get done here.
  */
-static void do_serial_bh(void)
+static void
+do_serial_bh(void)
 {
        run_task_queue(&tq_serial);
 }
 
-static void do_softint(void *private_)
+static void
+do_softint(void *private_)
 {
        struct su_struct        *info = (struct su_struct *) private_;
        struct tty_struct       *tty;
@@ -862,62+683,6 @@ static void do_softint(void *private_)
 }
 
 /*
- * This subroutine is called when the RS_TIMER goes off.  It is used
- * by the serial driver to handle ports that do not have an interrupt
- * (irq=0).  This doesn't work very well for 16450's, but gives barely
- * passable results for a 16550A.  (Although at the expense of much
- * CPU overhead).
- */
-static void su_timer(void)
-{
-       static unsigned long last_strobe = 0;
-       struct su_struct *info;
-       unsigned int    i;
-
-       if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
-               for (i=1; i < NR_IRQS; i++) {
-                       info = IRQ_ports[i];
-                       if (!info)
-                               continue;
-                       cli();
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-                       if (info->next_port) {
-                               do {
-                                       serial_out(info, UART_IER, 0);
-                                       info->IER |= UART_IER_THRI;
-                                       serial_out(info, UART_IER, info->IER);
-                                       info = info->next_port;
-                               } while (info);
-#ifdef CONFIG_SERIAL_MULTIPORT
-                               if (rs_multiport[i].port1)
-                                       rs_interrupt_multi(i, NULL, NULL);
-                               else
-#endif
-                                       su_interrupt(i, NULL, NULL);
-                       } else
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
-                               su_interrupt_single(i, NULL, NULL);
-                       sti();
-               }
-       }
-       last_strobe = jiffies;
-       timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
-       timer_active |= 1 << RS_TIMER;
-
-       if (IRQ_ports[0]) {
-               cli();
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-               su_interrupt(0, NULL, NULL);
-#else
-               su_interrupt_single(0, NULL, NULL);
-#endif
-               sti();
-
-               timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
-       }
-}
-
-/*
  * ---------------------------------------------------------------
  * Low level utility subroutines for the serial driver:  routines to
  * figure out the appropriate timeout for an interrupt chain, routines
@@ -926,62+691,41 @@ static void su_timer(void)
  * ---------------------------------------------------------------
  */
 
-/*
- * This routine figures out the correct timeout for a particular IRQ.
- * It uses the smallest timeout of all of the serial ports in a
- * particular interrupt chain.  Now only used for IRQ 0....
- */
-static void figure_IRQ_timeout(int irq)
-{
-       struct su_struct        *info;
-       int     timeout = 60*HZ;        /* 60 seconds === a long time :-) */
-
-       info = IRQ_ports[irq];
-       if (!info) {
-               IRQ_timeout[irq] = 60*HZ;
-               return;
-       }
-       while (info) {
-               if (info->timeout < timeout)
-                       timeout = info->timeout;
-               info = info->next_port;
-       }
-       if (!irq)
-               timeout = timeout / 2;
-       IRQ_timeout[irq] = timeout ? timeout : 1;
-}
-
-static int startup(struct su_struct *info)
+static int
+startup(struct su_struct *info)
 {
        unsigned long flags;
        int     retval=0;
-       void (*handler)(int, void *, struct pt_regs *);
        unsigned long page;
-#ifdef CONFIG_SERIAL_MANY_PORTS
-       unsigned short ICP;
-#endif
 
-       page = get_free_page(GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
+       save_flags(flags);
+       if (info->tty) {
+               page = get_free_page(GFP_KERNEL);
+               if (!page)
+                       return -ENOMEM;
 
-       save_flags(flags); cli();
+               cli();
 
-       if (info->flags & ASYNC_INITIALIZED) {
-               free_page(page);
-               goto errout;
-       }
+               if (info->flags & ASYNC_INITIALIZED) {
+                       free_page(page);
+                       goto errout;
+               }
 
-       if (info->port == 0 || info->type == PORT_UNKNOWN) {
-               if (info->tty)
+               if (info->port == 0 || info->type == PORT_UNKNOWN) {
                        set_bit(TTY_IO_ERROR, &info->tty->flags);
-               free_page(page);
-               goto errout;
+                       free_page(page);
+                       goto errout;
+               }
+               if (info->xmit_buf)
+                       free_page(page);
+               else
+                       info->xmit_buf = (unsigned char *) page;
        }
-       if (info->xmit_buf)
-               free_page(page);
-       else
-               info->xmit_buf = (unsigned char *) page;
+       cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
 
        if (uart_config[info->type].flags & UART_STARTECH) {
                /* Wake up UART */
@@ -1022,51+766,25 @@ static int startup(struct su_struct *info)
        /*
         * Allocate the IRQ if necessary
         */
-       if (info->irq && (!IRQ_ports[info->irq] ||
-                         !IRQ_ports[info->irq]->next_port)) {
-               if (IRQ_ports[info->irq]) {
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-                       free_irq(IRQ_4M(info->irq), info);
-#ifdef CONFIG_SERIAL_MULTIPORT                         
-                       if (rs_multiport[info->irq].port1)
-                               handler = rs_interrupt_multi;
-                       else
-#endif
-                               handler = su_interrupt;
-#else
-                       retval = -EBUSY;
-                       goto errout;
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
-               } else 
-                       handler = su_interrupt_single;
-
-               retval = request_irq(IRQ_4M(info->irq), handler, IRQ_T(info),
-                                    "serial", info);
-               if (retval) {
-                       if (capable(CAP_SYS_ADMIN)) {
-                               if (info->tty)
-                                       set_bit(TTY_IO_ERROR,
-                                               &info->tty->flags);
-                               retval = 0;
-                       }
-                       goto errout;
+       if (info->kbd_node || info->ms_node) {
+               retval = request_irq(info->irq, su_kbd_ms_interrupt,
+                                    SA_SHIRQ, info->name, info);
+       } else {
+               retval = request_irq(info->irq, su_serial_interrupt,
+                                    SA_SHIRQ, info->name, info);
+       }
+       if (retval) {
+               if (capable(CAP_SYS_ADMIN)) {
+                       if (info->tty)
+                               set_bit(TTY_IO_ERROR, &info->tty->flags);
+                       retval = 0;
                }
+               goto errout;
        }
 
        /*
-        * Insert serial port into IRQ chain.
-        */
-       info->prev_port = 0;
-       info->next_port = IRQ_ports[info->irq];
-       if (info->next_port)
-               info->next_port->prev_port = info;
-       IRQ_ports[info->irq] = info;
-       figure_IRQ_timeout(info->irq);
-
-       /*
         * Clear the interrupt registers.
         */
-     /* (void) serial_inp(info, UART_LSR); */   /* (see above) */
        (void) serial_inp(info, UART_RX);
        (void) serial_inp(info, UART_IIR);
        (void) serial_inp(info, UART_MSR);
@@ -1077,24+795,10 @@ static int startup(struct su_struct *info)
        serial_outp(info, UART_LCR, UART_LCR_WLEN8);    /* reset DLAB */
 
        info->MCR = 0;
-       if (info->tty->termios->c_cflag & CBAUD)
+       if (info->tty && info->tty->termios->c_cflag & CBAUD)
                info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#ifdef CONFIG_SERIAL_MANY_PORTS
-       if (info->flags & ASYNC_FOURPORT) {
-               if (info->irq == 0)
-                       info->MCR |= UART_MCR_OUT1;
-       } else
-#endif
-       {
-               if (info->irq != 0)
-                       info->MCR |= UART_MCR_OUT2;
-       }
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-       /*
-        * DEC did something gratutiously wrong....
-        */
-       info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+       if (info->irq != 0)
+               info->MCR |= UART_MCR_OUT2;
        serial_outp(info, UART_MCR, info->MCR);
 
        /*
@@ -1103,15+807,6 @@ static int startup(struct su_struct *info)
        info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
        serial_outp(info, UART_IER, info->IER); /* enable interrupts */
 
-#ifdef CONFIG_SERIAL_MANY_PORTS
-       if (info->flags & ASYNC_FOURPORT) {
-               /* Enable interrupts on the AST Fourport board */
-               ICP = (info->port & 0xFE0) | 0x01F;
-               outb_p(0x80, ICP);
-               (void) inb_p(ICP);
-       }
-#endif
-
        /*
         * And clear the interrupt registers again for luck.
         */
@@ -1125,12+820,6 @@ static int startup(struct su_struct *info)
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
        /*
-        * Set up serial timers...
-        */
-       timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
-       timer_active |= 1 << RS_TIMER;
-
-       /*
         * Set up the tty->alt_speed kludge
         */
        if (info->tty) {
@@ -1162,10+851,10 @@ errout:
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void shutdown(struct su_struct *info)
+static void
+shutdown(struct su_struct *info)
 {
        unsigned long   flags;
-       int             retval;
 
        if (!(info->flags & ASYNC_INITIALIZED))
                return;
@@ -1179,32+868,9 @@ static void shutdown(struct su_struct *info)
        wake_up_interruptible(&info->delta_msr_wait);
        
        /*
-        * First unlink the serial port from the IRQ chain...
-        */
-       if (info->next_port)
-               info->next_port->prev_port = info->prev_port;
-       if (info->prev_port)
-               info->prev_port->next_port = info->next_port;
-       else
-               IRQ_ports[info->irq] = info->next_port;
-       figure_IRQ_timeout(info->irq);
-
-       /*
         * Free the IRQ, if necessary
         */
-       if (info->irq && (!IRQ_ports[info->irq] ||
-                         !IRQ_ports[info->irq]->next_port)) {
-               if (IRQ_ports[info->irq]) {
-                       free_irq(IRQ_4M(info->irq), info);
-                       retval = request_irq(IRQ_4M(info->irq),
-                           su_interrupt_single, IRQ_T(info), "serial", info);
-                       
-                       if (retval)
-                               printk("serial shutdown: request_irq: error %d"
-                                      "  Couldn't reacquire IRQ.\n", retval);
-               } else
-                       free_irq(IRQ_4M(info->irq), info);
-       }
+       free_irq(info->irq, info);
 
        if (info->xmit_buf) {
                free_page((unsigned long) info->xmit_buf);
@@ -1213,20+879,7 @@ static void shutdown(struct su_struct *info)
 
        info->IER = 0;
        serial_outp(info, UART_IER, 0x00);      /* disable all intrs */
-#ifdef CONFIG_SERIAL_MANY_PORTS
-       if (info->flags & ASYNC_FOURPORT) {
-               /* reset interrupts on the AST Fourport board */
-               (void) inb((info->port & 0xFE0) | 0x01F);
-               info->MCR |= UART_MCR_OUT1;
-       } else
-#endif
-               info->MCR &= ~UART_MCR_OUT2;
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-       /*
-        * DEC did something gratutiously wrong....
-        */
-       info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+       info->MCR &= ~UART_MCR_OUT2;
 
        /* disable break condition */
        serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
@@ -1258,26+911,51 @@ static void shutdown(struct su_struct *info)
        restore_flags(flags);
 }
 
+static __inline__ int
+su_get_baud_rate(struct su_struct *info)
+{
+       static int baud_table[] = {
+               0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+               4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
+       };
+       int i;
+
+       if (info->tty)
+               return tty_get_baud_rate(info->tty);
+
+       i = info->cflag & CBAUD;
+       if (i & CBAUDEX) {
+               i &= ~(CBAUDEX);
+               if (i < 1 || i > 4)
+                       info->cflag &= ~(CBAUDEX);
+               else
+                       i += 15;
+       }
+       return baud_table[i];
+}
+
 /*
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static void change_speed(struct su_struct *info)
+static void
+change_speed(struct su_struct *info)
 {
-       unsigned short port;
-       int     quot = 0, baud_base, baud;
-       unsigned cflag, cval, fcr = 0;
-       int     bits;
-       unsigned long flags;
+       int             quot = 0, baud;
+       unsigned int    cval, fcr = 0;
+       int             bits;
+       unsigned long   flags;
 
-       if (!info->tty || !info->tty->termios)
-               return;
-       cflag = info->tty->termios->c_cflag;
-       if (!(port = info->port))
-               return;
+       if (!info->kbd_node && !info->ms_node) {
+               if (!info->tty || !info->tty->termios)
+                       return;
+               if (!info->port)
+                       return;
+               info->cflag = info->tty->termios->c_cflag;
+       }
 
        /* byte size and parity */
-       switch (cflag & CSIZE) {
+       switch (info->cflag & CSIZE) {
              case CS5: cval = 0x00; bits = 7; break;
              case CS6: cval = 0x01; bits = 8; break;
              case CS7: cval = 0x02; bits = 9; break;
@@ -1285,45+963,43 @@ static void change_speed(struct su_struct *info)
                /* Never happens, but GCC is too dumb to figure it out */
              default:  cval = 0x00; bits = 7; break;
        }
-       if (cflag & CSTOPB) {
+       if (info->cflag & CSTOPB) {
                cval |= 0x04;
                bits++;
        }
-       if (cflag & PARENB) {
+       if (info->cflag & PARENB) {
                cval |= UART_LCR_PARITY;
                bits++;
        }
-       if (!(cflag & PARODD))
+       if (!(info->cflag & PARODD))
                cval |= UART_LCR_EPAR;
 #ifdef CMSPAR
-       if (cflag & CMSPAR)
+       if (info->cflag & CMSPAR)
                cval |= UART_LCR_SPAR;
 #endif
 
        /* Determine divisor based on baud rate */
-       baud = tty_get_baud_rate(info->tty);
-       baud_base = info->baud_base;
+       baud = su_get_baud_rate(info);
        if (baud == 38400 &&
            ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
                quot = info->custom_divisor;
        else {
                if (baud == 134)
                        /* Special case since 134 is really 134.5 */
-                       quot = (2*baud_base / 269);
+                       quot = (2 * info->baud_base / 269);
                else if (baud)
-                       quot = baud_base / baud;
+                       quot = info->baud_base / baud;
        }
        /* If the quotient is ever zero, default to 9600 bps */
        if (!quot)
-               quot = baud_base / 9600;
-       info->quot = quot;
-       info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+               quot = info->baud_base / 9600;
+       info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / info->baud_base);
        info->timeout += HZ/50;         /* Add .02 seconds of slop */
 
        /* Set up FIFO's */
        if (uart_config[info->type].flags & UART_USE_FIFO) {
-               if ((info->baud_base / quot) < 2400)
-               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+               if ((info->baud_base / quot) < 9600)
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
                else
                        fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
        }
@@ -1334,12+1010,12 @@ static void change_speed(struct su_struct *info)
        info->IER &= ~UART_IER_MSI;
        if (info->flags & ASYNC_HARDPPS_CD)
                info->IER |= UART_IER_MSI;
-       if (cflag & CRTSCTS) {
+       if (info->cflag & CRTSCTS) {
                info->flags |= ASYNC_CTS_FLOW;
                info->IER |= UART_IER_MSI;
        } else
                info->flags &= ~ASYNC_CTS_FLOW;
-       if (cflag & CLOCAL)
+       if (info->cflag & CLOCAL)
                info->flags &= ~ASYNC_CHECK_CD;
        else {
                info->flags |= ASYNC_CHECK_CD;
@@ -1350,39+1026,43 @@ static void change_speed(struct su_struct *info)
        /*
         * Set up parity check flag
         */
+       if (info->tty) {
 #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
-       info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (I_INPCK(info->tty))
-               info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
-               info->read_status_mask |= UART_LSR_BI;
+               info->read_status_mask = UART_LSR_OE | UART_LSR_THRE |
+                                        UART_LSR_DR;
+               if (I_INPCK(info->tty))
+                       info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+               if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+                       info->read_status_mask |= UART_LSR_BI;
 
-       /*
-        * Characters to ignore
-        */
-       info->ignore_status_mask = 0;
-       if (I_IGNPAR(info->tty))
-               info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-       if (I_IGNBRK(info->tty)) {
-               info->ignore_status_mask |= UART_LSR_BI;
                /*
-                * If we're ignore parity and break indicators, ignore 
-                * overruns too.  (For real raw support).
+                * Characters to ignore
                 */
+               info->ignore_status_mask = 0;
                if (I_IGNPAR(info->tty))
-                       info->ignore_status_mask |= UART_LSR_OE;
+                       info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+               if (I_IGNBRK(info->tty)) {
+                       info->ignore_status_mask |= UART_LSR_BI;
+                       /*
+                        * If we're ignore parity and break indicators, ignore 
+                        * overruns too.  (For real raw support).
+                        */
+                       if (I_IGNPAR(info->tty))
+                               info->ignore_status_mask |= UART_LSR_OE;
+               }
+               /*
+                * !!! ignore all characters if CREAD is not set
+                */
+               if ((info->cflag & CREAD) == 0)
+                       info->ignore_status_mask |= UART_LSR_DR;
        }
-       /*
-        * !!! ignore all characters if CREAD is not set
-        */
-       if ((cflag & CREAD) == 0)
-               info->ignore_status_mask |= UART_LSR_DR;
+
        save_flags(flags); cli();
        if (uart_config[info->type].flags & UART_STARTECH) {
                serial_outp(info, UART_LCR, 0xBF);
                serial_outp(info, UART_EFR,
-                           (cflag & CRTSCTS) ? UART_EFR_CTS : 0);
+                           (info->cflag & CRTSCTS) ? UART_EFR_CTS : 0);
        }
        serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);      /* set DLAB */
        serial_outp(info, UART_DLL, quot & 0xff);       /* LS of divisor */
@@ -1396,7+1076,8 @@ static void change_speed(struct su_struct *info)
        info->quot = quot;
 }
 
-static void su_put_char(struct tty_struct *tty, unsigned char ch)
+static void
+su_put_char(struct tty_struct *tty, unsigned char ch)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
        unsigned long flags;
@@ -1421,18+1102,13 @@ static void su_put_char(struct tty_struct *tty, unsigned char ch)
 
 static void su_put_char_kbd(unsigned char c)
 {
-       struct su_struct *info;
-       int i;
+       struct su_struct *info = su_table;
        int lsr;
 
-       for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
-               if (info->kbd_node != 0)
-                       break;
-       }
-       if (i >= NR_PORTS) {
-               /* XXX P3: I would put a printk here but it may flood. */
+       if (!info->kbd_node)
+               ++info;
+       if (!info)
                return;
-       }
 
        do {
                lsr = serial_in(info, UART_LSR);
@@ -1442,14+1118,15 @@ static void su_put_char_kbd(unsigned char c)
        su_outb(info, UART_TX, c);
 }
 
-static void su_change_mouse_baud(int baud)
+static void
+su_change_mouse_baud(int baud)
 {
        struct su_struct *info = su_table;
-       int i;
 
-       for (i = 0, info = su_table; i < NR_PORTS; i++, info++)
-               if (info->kbd_node != 0) break;
-       if (i >= NR_PORTS) return;
+       if (!info->ms_node)
+               ++info;
+       if (!info)
+               return;
 
        info->cflag &= ~(CBAUDEX | CBAUD);
        switch(baud) {
@@ -1474,7+1151,8 @@ static void su_change_mouse_baud(int baud)
        change_speed(info);
 }
 
-static void su_flush_chars(struct tty_struct *tty)
+static void
+su_flush_chars(struct tty_struct *tty)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
        unsigned long flags;
@@ -1492,7+1170,8 @@ static void su_flush_chars(struct tty_struct *tty)
        restore_flags(flags);
 }
 
-static int su_write(struct tty_struct * tty, int from_user,
+static int
+su_write(struct tty_struct * tty, int from_user,
                    const unsigned char *buf, int count)
 {
        int     c, ret = 0;
@@ -1562,7+1241,8 @@ static int su_write(struct tty_struct * tty, int from_user,
        return ret;
 }
 
-static int su_write_room(struct tty_struct *tty)
+static int
+su_write_room(struct tty_struct *tty)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
        int     ret;
@@ -1575,7+1255,8 @@ static int su_write_room(struct tty_struct *tty)
        return ret;
 }
 
-static int su_chars_in_buffer(struct tty_struct *tty)
+static int
+su_chars_in_buffer(struct tty_struct *tty)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
                                
@@ -1584,7+1265,8 @@ static int su_chars_in_buffer(struct tty_struct *tty)
        return info->xmit_cnt;
 }
 
-static void su_flush_buffer(struct tty_struct *tty)
+static void
+su_flush_buffer(struct tty_struct *tty)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
 
@@ -1603,7+1285,8 @@ static void su_flush_buffer(struct tty_struct *tty)
  * This function is used to send a high-priority XON/XOFF character to
  * the device
  */
-static void su_send_xchar(struct tty_struct *tty, char ch)
+static void
+su_send_xchar(struct tty_struct *tty, char ch)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
 
@@ -1626,7+1309,8 @@ static void su_send_xchar(struct tty_struct *tty, char ch)
  * incoming characters should be throttled.
  * ------------------------------------------------------------
  */
-static void su_throttle(struct tty_struct * tty)
+static void
+su_throttle(struct tty_struct * tty)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
 #ifdef SERIAL_DEBUG_THROTTLE
@@ -1650,7+1334,8 @@ static void su_throttle(struct tty_struct * tty)
        sti();
 }
 
-static void su_unthrottle(struct tty_struct * tty)
+static void
+su_unthrottle(struct tty_struct * tty)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
 #ifdef SERIAL_DEBUG_THROTTLE
@@ -1682,139+1367,6 @@ static void su_unthrottle(struct tty_struct * tty)
  * ------------------------------------------------------------
  */
 
-#if 0
-static int get_serial_info(struct su_struct * info,
-                          struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-
-       if (!retinfo)
-               return -EFAULT;
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = info->type;
-       tmp.line = info->line;
-       tmp.port = info->port;
-       tmp.irq = info->irq;
-       tmp.flags = info->flags;
-       tmp.xmit_fifo_size = info->xmit_fifo_size;
-       tmp.baud_base = info->baud_base;
-       tmp.close_delay = info->close_delay;
-       tmp.closing_wait = info->closing_wait;
-       tmp.custom_divisor = info->custom_divisor;
-       tmp.hub6 = 0;
-       if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int set_serial_info(struct su_struct * info,
-                          struct serial_struct * new_info)
-{
-       struct serial_struct new_serial;
-       struct serial_state old_state, *state;
-       unsigned int            i,change_irq,change_port;
-       int                     retval = 0;
-
-       if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-               return -EFAULT;
-       old_state = *state;
-  
-       change_irq = new_serial.irq != state->irq;
-       change_port = (new_serial.port != state->port);
-  
-       if (!capable(CAP_SYS_ADMIN)) {
-               if (change_irq || change_port ||
-                   (new_serial.baud_base != state->baud_base) ||
-                   (new_serial.type != state->type) ||
-                   (new_serial.close_delay != state->close_delay) ||
-                   (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
-                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
-                    (state->flags & ~ASYNC_USR_MASK)))
-                       return -EPERM;
-               state->flags = ((state->flags & ~ASYNC_USR_MASK) |
-                              (new_serial.flags & ASYNC_USR_MASK));
-               state->custom_divisor = new_serial.custom_divisor;
-               goto check_and_exit;
-       }
-
-       new_serial.irq = irq_cannonicalize(new_serial.irq);
-
-       if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
-           (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
-               return -EINVAL;
-       }
-
-       /* Make sure address is not already in use */
-       if (new_serial.type) {
-               for (i = 0 ; i < NR_PORTS; i++)
-                       if ((state != &su_table[i]) &&
-                           (su_table[i].port == new_serial.port) &&
-                           su_table[i].type)
-                               return -EADDRINUSE;
-       }
-
-       if ((change_port || change_irq) && (state->count > 1))
-               return -EBUSY;
-
-       /*
-        * OK, past this point, all the error checking has been done.
-        * At this point, we start making changes.....
-        */
-
-       state->baud_base = new_serial.baud_base;
-       state->flags = ((state->flags & ~ASYNC_FLAGS) |
-                       (new_serial.flags & ASYNC_FLAGS));
-       info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
-                      (info->flags & ASYNC_INTERNAL_FLAGS));
-       state->custom_divisor = new_serial.custom_divisor;
-       state->type = new_serial.type;
-       state->close_delay = new_serial.close_delay * HZ/100;
-       state->closing_wait = new_serial.closing_wait * HZ/100;
-       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-       info->xmit_fifo_size = state->xmit_fifo_size =
-               new_serial.xmit_fifo_size;
-
-       release_region(state->port,8);
-       if (change_port || change_irq) {
-               /*
-                * We need to shutdown the serial port at the old
-                * port/irq combination.
-                */
-               shutdown(info);
-               state->irq = new_serial.irq;
-               info->port = state->port = new_serial.port;
-               info->hub6 = state->hub6 = new_serial.hub6;
-       }
-       if (state->type != PORT_UNKNOWN)
-               request_region(state->port,8,"serial(set)");
-
-check_and_exit:
-       if (!state->port || !state->type)
-               return 0;
-       if (state->type != old_state.type)
-               info->xmit_fifo_size = state->xmit_fifo_size =
-                       uart_config[state->type].dfl_xmit_fifo_size;
-       if (state->flags & ASYNC_INITIALIZED) {
-               if (((old_state.flags & ASYNC_SPD_MASK) !=
-                    (state->flags & ASYNC_SPD_MASK)) ||
-                   (old_state.custom_divisor != state->custom_divisor)) {
-                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-                               info->tty->alt_speed = 57600;
-                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-                               info->tty->alt_speed = 115200;
-                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-                               info->tty->alt_speed = 230400;
-                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-                               info->tty->alt_speed = 460800;
-                       change_speed(info);
-               }
-       } else
-               retval = startup(info);
-       return retval;
-}
-#endif
-
-
 /*
  * get_lsr_info - get line status register info
  *
@@ -1825,7+1377,8 @@ check_and_exit:
  *         transmit holding register is empty.  This functionality
  *         allows an RS485 driver to be written in user space. 
  */
-static int get_lsr_info(struct su_struct * info, unsigned int *value)
+static int
+get_lsr_info(struct su_struct * info, unsigned int *value)
 {
        unsigned char status;
        unsigned int result;
@@ -1838,7+1391,8 @@ static int get_lsr_info(struct su_struct * info, unsigned int *value)
 }
 
 
-static int get_modem_info(struct su_struct * info, unsigned int *value)
+static int
+get_modem_info(struct su_struct * info, unsigned int *value)
 {
        unsigned char control, status;
        unsigned int result;
@@ -1860,8+1414,8 @@ static int get_modem_info(struct su_struct * info, unsigned int *value)
        return put_user(result,value);
 }
 
-static int set_modem_info(struct su_struct * info, unsigned int cmd,
-                         unsigned int *value)
+static int
+set_modem_info(struct su_struct * info, unsigned int cmd, unsigned int *value)
 {
        int error;
        unsigned int arg;
@@ -1917,34+1471,11 @@ static int set_modem_info(struct su_struct * info, unsigned int cmd,
        return 0;
 }
 
-#if 0
-static int do_autoconfig(struct su_struct * info)
-{
-       int                     retval;
-       
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (info->state->count > 1)
-               return -EBUSY;
-       
-       shutdown(info);
-
-       autoconfig(info->state);
-       if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0))
-               info->state->irq = detect_uart_irq(info->state);
-
-       retval = startup(info);
-       if (retval)
-               return retval;
-       return 0;
-}
-#endif
-
 /*
  * su_break() --- routine which turns the break handling on or off
  */
-static void su_break(struct tty_struct *tty, int break_state)
+static void
+su_break(struct tty_struct *tty, int break_state)
 {
        struct su_struct * info = (struct su_struct *)tty->driver_data;
        unsigned long flags;
@@ -1964,122+1495,8 @@ static void su_break(struct tty_struct *tty, int break_state)
        restore_flags(flags);
 }
 
-#ifdef CONFIG_SERIAL_MULTIPORT
-static int get_multiport_struct(struct su_struct * info,
-                               struct serial_multiport_struct *retinfo)
-{
-       struct serial_multiport_struct ret;
-       struct rs_multiport_struct *multi;
-       
-       multi = &rs_multiport[info->state->irq];
-
-       ret.port_monitor = multi->port_monitor;
-       
-       ret.port1 = multi->port1;
-       ret.mask1 = multi->mask1;
-       ret.match1 = multi->match1;
-       
-       ret.port2 = multi->port2;
-       ret.mask2 = multi->mask2;
-       ret.match2 = multi->match2;
-       
-       ret.port3 = multi->port3;
-       ret.mask3 = multi->mask3;
-       ret.match3 = multi->match3;
-       
-       ret.port4 = multi->port4;
-       ret.mask4 = multi->mask4;
-       ret.match4 = multi->match4;
-
-       ret.irq = info->state->irq;
-
-       if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
-               return -EFAULT;
-       return 0;
-}
-
-static int set_multiport_struct(struct su_struct * info,
-                               struct serial_multiport_struct *in_multi)
-{
-       struct serial_multiport_struct new_multi;
-       struct rs_multiport_struct *multi;
-       struct serial_state *state;
-       int     was_multi, now_multi;
-       int     retval;
-       void (*handler)(int, void *, struct pt_regs *);
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       state = info->state;
-       
-       if (copy_from_user(&new_multi, in_multi,
-                          sizeof(struct serial_multiport_struct)))
-               return -EFAULT;
-       
-       if (new_multi.irq != state->irq || state->irq == 0 ||
-           !IRQ_ports[state->irq])
-               return -EINVAL;
-
-       multi = &rs_multiport[state->irq];
-       was_multi = (multi->port1 != 0);
-       
-       multi->port_monitor = new_multi.port_monitor;
-       
-       if (multi->port1)
-               release_region(multi->port1,1);
-       multi->port1 = new_multi.port1;
-       multi->mask1 = new_multi.mask1;
-       multi->match1 = new_multi.match1;
-       if (multi->port1)
-               request_region(multi->port1,1,"serial(multiport1)");
-
-       if (multi->port2)
-               release_region(multi->port2,1);
-       multi->port2 = new_multi.port2;
-       multi->mask2 = new_multi.mask2;
-       multi->match2 = new_multi.match2;
-       if (multi->port2)
-               request_region(multi->port2,1,"serial(multiport2)");
-
-       if (multi->port3)
-               release_region(multi->port3,1);
-       multi->port3 = new_multi.port3;
-       multi->mask3 = new_multi.mask3;
-       multi->match3 = new_multi.match3;
-       if (multi->port3)
-               request_region(multi->port3,1,"serial(multiport3)");
-
-       if (multi->port4)
-               release_region(multi->port4,1);
-       multi->port4 = new_multi.port4;
-       multi->mask4 = new_multi.mask4;
-       multi->match4 = new_multi.match4;
-       if (multi->port4)
-               request_region(multi->port4,1,"serial(multiport4)");
-
-       now_multi = (multi->port1 != 0);
-       
-       if (IRQ_ports[state->irq]->next_port &&
-           (was_multi != now_multi)) {
-               free_irq(IRQ_4M(state->irq), info);
-               if (now_multi)
-                       handler = rs_interrupt_multi;
-               else
-                       handler = su_interrupt;
-
-               retval = request_irq(IRQ_4M(state->irq), handler, IRQ_T(info),
-                                    "serial", info);
-               if (retval) {
-                       printk("Couldn't reallocate serial interrupt "
-                              "driver!!\n");
-               }
-       }
-
-       return 0;
-}
-#endif
-
-static int su_ioctl(struct tty_struct *tty, struct file * file,
+static int
+su_ioctl(struct tty_struct *tty, struct file * file,
                    unsigned int cmd, unsigned long arg)
 {
        int error;
@@ -2104,16+1521,6 @@ static int su_ioctl(struct tty_struct *tty, struct file * file,
                case TIOCMBIC:
                case TIOCMSET:
                        return set_modem_info(info, cmd, (unsigned int *) arg);
-#if 0
-               case TIOCGSERIAL:
-                       return get_serial_info(info,
-                                              (struct serial_struct *) arg);
-               case TIOCSSERIAL:
-                       return set_serial_info(info,
-                                              (struct serial_struct *) arg);
-               case TIOCSERCONFIG:
-                       return do_autoconfig(info);
-#endif
 
                case TIOCSERGETLSR: /* Get line status register */
                        return get_lsr_info(info, (unsigned int *) arg);
@@ -2126,15+1533,6 @@ static int su_ioctl(struct tty_struct *tty, struct file * file,
                        return 0;
 #endif
                                
-#ifdef CONFIG_SERIAL_MULTIPORT
-               case TIOCSERGETMULTI:
-                       return get_multiport_struct(info,
-                                      (struct serial_multiport_struct *) arg);
-               case TIOCSERSETMULTI:
-                       return set_multiport_struct(info,
-                                      (struct serial_multiport_struct *) arg);
-#endif
-                       
                /*
                 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
                 * - mask passed in arg for lines of interest
@@ -2194,7+1592,8 @@ static int su_ioctl(struct tty_struct *tty, struct file * file,
        /* return 0; */ /* Trigger warnings is fall through by a chance. */
 }
 
-static void su_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void
+su_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
 
@@ -2257,7+1656,8 @@ static void su_set_termios(struct tty_struct *tty, struct termios *old_termios)
  * that IRQ if nothing is left in the chain.
  * ------------------------------------------------------------
  */
-static void su_close(struct tty_struct *tty, struct file * filp)
+static void
+su_close(struct tty_struct *tty, struct file * filp)
 {
        struct su_struct *info = (struct su_struct *)tty->driver_data;
        unsigned long flags;
@@ -2359,7+1759,8 @@ static void su_close(struct tty_struct *tty, struct file * filp)
 /*
  * su_wait_until_sent() --- wait until the transmitter is empty
  */
-static void su_wait_until_sent(struct tty_struct *tty, int timeout)
+static void
+su_wait_until_sent(struct tty_struct *tty, int timeout)
 {
        struct su_struct * info = (struct su_struct *)tty->driver_data;
        unsigned long orig_jiffies, char_time;
@@ -2412,7+1813,8 @@ static void su_wait_until_sent(struct tty_struct *tty, int timeout)
 /*
  * su_hangup() --- called by tty_hangup() when a hangup is signaled.
  */
-static void su_hangup(struct tty_struct *tty)
+static void
+su_hangup(struct tty_struct *tty)
 {
        struct su_struct * info = (struct su_struct *)tty->driver_data;
 
@@ -2433,8+1835,9 @@ static void su_hangup(struct tty_struct *tty)
  * su_open() and friends
  * ------------------------------------------------------------
  */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct su_struct *info)
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+               struct su_struct *info)
 {
        struct wait_queue wait = { current, NULL };
        int             retval;
@@ -2569,8+1972,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
  * enables interrupts for a serial port, linking in its async structure into
  * the IRQ chain.   It also performs the serial-specific
  * initialization for the tty structure.
-        */
-static int su_open(struct tty_struct *tty, struct file * filp)
+ */
+static int
+su_open(struct tty_struct *tty, struct file * filp)
 {
        struct su_struct        *info;
        int                     retval, line;
@@ -2646,7+2050,7 @@ static int su_open(struct tty_struct *tty, struct file * filp)
        if (sercons.cflag && sercons.index == line) {
                tty->termios->c_cflag = sercons.cflag;
                sercons.cflag = 0;
-       change_speed(info);
+               change_speed(info);
        }
 #endif
        info->session = current->session;
@@ -2661,15+2065,15 @@ static int su_open(struct tty_struct *tty, struct file * filp)
 /*
  * /proc fs routines....
  */
-
-static inline int line_info(char *buf, struct su_struct *info)
+static __inline__ int
+line_info(char *buf, struct su_struct *info)
 {
        char    stat_buf[30], control, status;
        int     ret;
 
-       ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+       ret = sprintf(buf, "%d: uart:%s port:%X irq:%s",
                      info->line, uart_config[info->type].name, 
-                     (int)info->port, info->irq);
+                     (int)info->port, __irq_itoa(info->irq));
 
        if (info->port == 0 || info->type == PORT_UNKNOWN) {
                ret += sprintf(buf+ret, "\n");
@@ -2763,30+2167,10 @@ done:
  * number, and identifies which options were configured into this
  * driver.
  */
-static _INLINE_ void show_su_version(void)
+static __inline__
+void show_su_version(void)
 {
-       printk(KERN_INFO "%s version %s with", serial_name, serial_version);
-#ifdef CONFIG_SERIAL_MANY_PORTS
-       printk(" MANY_PORTS");
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_MULTIPORT
-       printk(" MULTIPORT");
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-       printk(" SHARE_IRQ");
-#endif
-#define SERIAL_OPT
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-       printk(" DETECT_IRQ");
-#endif
-#ifdef SERIAL_OPT
-       printk(" enabled\n");
-#else
-       printk(" no serial options enabled\n");
-#endif
-#undef SERIAL_OPT
+       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
 }
 
 /*
@@ -2828,16+2212,10 @@ ebus_done:
                return;
 
        info->irq = dev->irqs[0];
-
-#ifdef DEBUG_SERIAL_OPEN
-       printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
-              __irq_itoa(dev->irqs[0]));
-#endif
-
 #else
-       if (info->port_node == 0) {
+       if (!info->port_node)
                return;
-       }
+
        if (prom_getproperty(info->port_node, "reg",
            (char *)&reg0, sizeof(reg0)) == -1) {
                prom_printf("su: no \"reg\" property\n");
@@ -2852,7+2230,12 @@ ebus_done:
        /*
         * There is no intr property on MrCoffee, so hardwire it. Krups?
         */
-       info->irq = 13;
+       info->irq = IRQ_4M(13);
+#endif
+
+#ifdef DEBUG_SERIAL_OPEN
+       printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
+              __irq_itoa(dev->irqs[0]));
 #endif
 
        info->magic = SERIAL_MAGIC;
@@ -2956,19+2339,20 @@ ebus_done:
                return;
        }
 
+       if (info->kbd_node || info->ms_node)
+               sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
+       else
+               strcpy(info->name, "su(serial)");
+
 #ifdef __sparc_v9__
-       sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
        request_region(info->port, 8, info->name);
-#else
-       strcpy(info->name, "su(serial)");
 #endif
 
        /*
         * Reset the UART.
         */
        su_outb(info, UART_MCR, 0x00);
-       su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
-                                    UART_FCR_CLEAR_XMIT));
+       su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
        su_inb(info, UART_RX);
 
        restore_flags(flags);
@@ -2977,46+2361,12 @@ ebus_done:
 /*
  * The serial driver boot-time initialization code!
  */
-__initfunc(int su_init(void))
+__initfunc(int su_serial_init(void))
 {
        int i;
        struct su_struct *info;
-       extern void atomwide_serial_init (void);
-       extern void dualsp_serial_init (void);
-       
-#ifdef CONFIG_ATOMWIDE_SERIAL
-       atomwide_serial_init ();
-#endif
-#ifdef CONFIG_DUALSP_SERIAL
-       dualsp_serial_init ();
-#endif
-       
+
        init_bh(SERIAL_BH, do_serial_bh);
-       timer_table[RS_TIMER].fn = su_timer;
-       timer_table[RS_TIMER].expires = 0;
-
-       for (i = 0; i < NR_IRQS; i++) {
-               IRQ_ports[i] = 0;
-               IRQ_timeout[i] = 0;
-#ifdef CONFIG_SERIAL_MULTIPORT
-               memset(&rs_multiport[i], 0,
-                      sizeof(struct rs_multiport_struct));
-#endif
-       }
-#if 0  /* Must be shared with keyboard on MrCoffee. */
-#ifdef CONFIG_SERIAL_CONSOLE
-       /*
-        *      The interrupt of the serial console port
-        *      can't be shared.
-        */
-       if (sercons.flags & CON_CONSDEV) {
-               for(i = 0; i < NR_PORTS; i++)
-                       if (i != sercons.index &&
-                           su_table[i].irq == su_table[sercons.index].irq)
-                               su_table[i].irq = 0;
-       }
-#endif
-#endif
        show_su_version();
 
        /* Initialize the tty_driver structure */
@@ -3076,7+2426,6 @@ __initfunc(int su_init(void))
                panic("Couldn't register callout su\n");
 
        for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
-               info->magic = SSTATE_MAGIC;
                info->line = i;
                info->type = PORT_UNKNOWN;
                info->baud_base = BAUD_BASE;
@@ -3093,13+2442,36 @@ __initfunc(int su_init(void))
                info->icount.overrun = info->icount.brk = 0;
                info->tqueue.routine = do_softint;
                info->tqueue.data = info;
+               info->cflag = serial_driver.init_termios.c_cflag;
+
+               autoconfig(info);
+               if (info->type == PORT_UNKNOWN)
+                       continue;
+
+               printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
+                      info->name, info->port, __irq_itoa(info->irq),
+                      uart_config[info->type].name);
+       }
+
+       return 0;
+}
+
+__initfunc(int su_kbd_ms_init(void))
+{
+       int i;
+       struct su_struct *info;
+
+       show_su_version();
+
+       for (i = 0, info = su_table; i < 2; i++, info++) {
+               info->line = i;
+               info->type = PORT_UNKNOWN;
+               info->baud_base = BAUD_BASE;
 
                if (info->kbd_node)
-                       info->cflag = B1200 | CS8 | CREAD;
-               else if (info->ms_node)
-                       info->cflag = B4800 | CS8 | CREAD;
+                       info->cflag = B1200 | CS8 | CLOCAL | CREAD;
                else
-                       info->cflag = B9600 | CS8 | CREAD;
+                       info->cflag = B4800 | CS8 | CLOCAL | CREAD;
 
                autoconfig(info);
                if (info->type == PORT_UNKNOWN)
@@ -3109,20+2481,12 @@ __initfunc(int su_init(void))
                       info->name, info->port, __irq_itoa(info->irq),
                       uart_config[info->type].name);
 
-               /*
-                * We want startup here because we want mouse and keyboard
-                * working without opening. On SPARC console will work
-                * without startup.
-                */
-               if (info->kbd_node) {
-                       startup(info);
-                       keyboard_zsinit(su_put_char_kbd);
-               } else if (info->ms_node) {
                startup(info);
+               if (info->kbd_node)
+                       keyboard_zsinit(su_put_char_kbd);
+               else
                        sun_mouse_zsinit();
        }
-       }
-
        return 0;
 }
 
@@ -3147,12+2511,16 @@ __initfunc(int su_probe (unsigned long *memory_start))
                                info->port_node = sunode;
 #ifdef CONFIG_SERIAL_CONSOLE
                                /*
-                                * Console must be initiated after the generic initialization.
-                                * sunserial_setinitfunc inverts order, so call this before next one.
+                                * Console must be initiated after the generic
+                                * initialization.
+                                * sunserial_setinitfunc inverts order, so
+                                * call this before next one.
                                 */
-                               sunserial_setinitfunc(memory_start, su_serial_console_init);
+                               sunserial_setinitfunc(memory_start,
+                                                     su_serial_console_init);
 #endif
-                               sunserial_setinitfunc(memory_start, su_init);
+                               sunserial_setinitfunc(memory_start,
+                                                     su_serial_init);
                                return 0;
                        }
                }
@@ -3237,7+2605,7 @@ __initfunc(int su_probe (unsigned long *memory_start))
                                /*
                                 * Found everything we need?
                                 */
-                               if (devices == NR_PORTS)
+                               if (devices == 2)
                                        goto found;
 
                                sunode = prom_getsibling(sunode);
@@ -3256,7+2624,7 @@ __initfunc(int su_probe (unsigned long *memory_start))
        return -ENODEV;
 
 found:
-        sunserial_setinitfunc(memory_start, su_init);
+        sunserial_setinitfunc(memory_start, su_kbd_ms_init);
         rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
        sunkbd_setinitfunc(memory_start, sun_kbd_init);
        kbd_ops.compute_shiftstate = sun_compute_shiftstate;
@@ -3273,46+2641,6 @@ found:
        return 0;
 }
 
-#if 0
-#ifdef MODULE
-int init_module(void)
-{
-       return su_init();       /* rs_init? su_probe? XXX */
-}
-
-void cleanup_module(void) 
-{
-       unsigned long flags;
-       int e1, e2;
-       int i;
-
-       /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
-       save_flags(flags);
-       cli();
-       timer_active &= ~(1 << RS_TIMER);
-       timer_table[RS_TIMER].fn = NULL;
-       timer_table[RS_TIMER].expires = 0;
-        remove_bh(SERIAL_BH);
-       if ((e1 = tty_unregister_driver(&serial_driver)))
-               printk("SERIAL: failed to unregister serial driver (%d)\n",
-                      e1);
-       if ((e2 = tty_unregister_driver(&callout_driver)))
-               printk("SERIAL: failed to unregister callout driver (%d)\n", 
-                      e2);
-       restore_flags(flags);
-
-       for (i = 0; i < NR_PORTS; i++) {
-               if (su_table[i].type != PORT_UNKNOWN)
-                       release_region(su_table[i].port, 8);
-       }
-       if (tmp_buf) {
-               free_page((unsigned long) tmp_buf);
-               tmp_buf = NULL;
-       }
-}
-#endif /* MODULE */
-#endif /* deadwood */
-
 /*
  * ------------------------------------------------------------
  * Serial console driver
@@ -3325,7+2653,8 @@ void cleanup_module(void)
 /*
  *     Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct su_struct *info)
+static __inline__ void
+wait_for_xmitr(struct su_struct *info)
 {
        int lsr;
        unsigned int tmout = 1000000;
@@ -3341,7+2670,8 @@ static inline void wait_for_xmitr(struct su_struct *info)
  *     Print a string to the serial port trying not to disturb
  *     any possible real use of the port...
  */
-static void serial_console_write(struct console *co, const char *s,
+static void
+serial_console_write(struct console *co, const char *s,
                                unsigned count)
 {
        struct su_struct *info;
@@ -3383,7+2713,8 @@ static void serial_console_write(struct console *co, const char *s,
 /*
  *     Receive character from the serial port
  */
-static int serial_console_wait_key(struct console *co)
+static int
+serial_console_wait_key(struct console *co)
 {
        struct su_struct *info;
        int ier;
@@ -3413,7+2744,8 @@ static int serial_console_wait_key(struct console *co)
        return c;
 }
 
-static kdev_t serial_console_device(struct console *c)
+static kdev_t
+serial_console_device(struct console *c)
 {
        return MKDEV(TTY_MAJOR, 64 + c->index);
 }
index ccc5496..30ff83e 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sunserial.c,v 1.66 1998/09/21 05:48:48 jj Exp $
+/* $Id: sunserial.c,v 1.67 1998/10/25 03:22:46 jj Exp $
  * serial.c: Serial port driver infrastructure for the Sparc.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -399,6+399,14 @@ sun_serial_setup(unsigned long memory_start))
 
        if (!ret)
                return memory_start;
+               
+#ifdef __sparc_v9__
+       ret = prom_finddevice("/ssp-serial");
+       if (ret && ret != -1) {
+               /* Hello, Starfire. Pleased to meet you :) */
+               return memory_start;
+       }
+#endif
 
        prom_printf("No serial devices found, bailing out.\n");
        prom_halt();
index e3c5d13..48661f3 100644 (file)
@@ -218,7+218,7 @@ static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg)
                        return -ENOMEM;
 
                if(copy_from_user(buffer, inout.buffer, 
-                                 inout.len*sizeof(char));) {
+                                 inout.len*sizeof(char))) {
                        kfree_s(buffer,inout.len*sizeof(char));
                        return -EFAULT;
                }
index bb0ce2b..4676c33 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: zs.c,v 1.29 1998/09/21 05:06:53 jj Exp $
+/* $Id: zs.c,v 1.31 1998/10/07 11:35:29 jj Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1808,7+1808,7 @@ int zs_open(struct tty_struct *tty, struct file * filp)
 
 static void show_serial_version(void)
 {
-       char *revision = "$Revision: 1.29 $";
+       char *revision = "$Revision: 1.31 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
@@ -1830,6+1830,7 @@ __initfunc(static struct sun_zslayout *
 get_zs(int chip))
 {
        unsigned int vaddr[2] = { 0, 0 };
+       unsigned long mapped_addr = 0;
        int busnode, seen, zsnode, sun4u_ino;
        static int irq = 0;
 
@@ -1854,7+1855,30 @@ get_zs(int chip))
                        int len = prom_getproperty(zsnode, "address",
                                                   (void *) vaddr, sizeof(vaddr));
 
-                       if(len % sizeof(unsigned int)) {
+                       if(len == -1) {
+                               struct linux_sbus *sbus;
+                               struct linux_sbus_device *sdev = NULL;
+
+                               /* "address" property is not guarenteed,
+                                * everything in I/O is implicitly mapped
+                                * anyways by our clever TLB miss handling
+                                * scheme, so don't fail here.  -DaveM
+                                */
+                               for_each_sbus(sbus) {
+                                       for_each_sbusdev(sdev, sbus) {
+                                               if (sdev->prom_node == zsnode)
+                                                       goto found;
+                                       }
+                               }
+                       found:
+                               if (sdev == NULL)
+                                       prom_halt();
+                               prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev);
+                               mapped_addr = (unsigned long)
+                                       sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
+                                                      PAGE_SIZE, "Zilog Registers",
+                                                      sdev->reg_addrs[0].which_io, 0x0);
+                       } else if(len % sizeof(unsigned int)) {
                                prom_printf("WHOOPS:  proplen for %s "
                                            "was %d, need multiple of "
                                            "%d\n", "address", len,
@@ -1883,9+1907,12 @@ get_zs(int chip))
        }
        if(!zsnode)
                panic("get_zs: whee chip not found");
-       if(!vaddr[0])
+       if(!vaddr[0] && !mapped_addr)
                panic("get_zs: whee no serial chip mappable");
-       return (struct sun_zslayout *)(unsigned long) vaddr[0];
+       if (mapped_addr != 0)
+               return (struct sun_zslayout *) mapped_addr;
+       else
+               return (struct sun_zslayout *) (unsigned long) vaddr[0];
 }
 #else /* !(__sparc_v9__) */
 __initfunc(static struct sun_zslayout *
@@ -2119,7+2146,7 @@ no_probe:
        kbd_ops.getledstate = sun_getledstate;
        kbd_ops.setkeycode = sun_setkeycode;
        kbd_ops.getkeycode = sun_getkeycode;
-#ifdef CONFIG_PCI
+#if defined(__sparc_v9__) && defined(CONFIG_PCI)
        sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
                               sun_func_buf, sun_func_table,
                               sun_funcbufsize, sun_funcbufleft,
index 7ea65c9..8d0869e 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sbus.c,v 1.72 1998/09/05 17:25:51 jj Exp $
+/* $Id: sbus.c,v 1.73 1998/10/07 11:35:50 jj Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -278,8+278,16 @@ __initfunc(void sbus_init(void))
                if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
                   (nd = prom_getchild(iommund)) == 0 ||
                   (nd = prom_searchsiblings(nd, "sbus")) == 0) {
+#ifdef CONFIG_PCI
+                        if (!pcibios_present()) {       
+                                prom_printf("Neither SBUS nor PCI found.\n");
+                                prom_halt();
+                        }
+                        return;
+#else
                        /* No reason to run further - the data access trap will occur. */
                        panic("sbus not found");
+#endif
                }
        }
 
index f637860..1cc11f7 100644 (file)
@@ -104,8+104,11 @@ if [ "$CONFIG_PCI" = "y" ]; then
   dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
 fi
 dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
-if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then
-  dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" ]; then
+  dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+  if [ "$CONFIG_SCSI_DC390T" != "n" ]; then
+    bool '  _omit_ support for non-DC390 adapters' CONFIG_SCSI_DC390T_NOGENSUPP
+  fi
 fi
 dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
 dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
diff --git a/drivers/scsi/README.tmscsim b/drivers/scsi/README.tmscsim
new file mode 100644 (file)
index 0000000..b11cd4d
--- /dev/null
@@ -0,0 +1,413 @@
+The tmscsim driver
+==================
+
+1. Purpose and history
+2. Installation
+3. Features
+4. Configuration via /proc/scsi/tmscsim/?
+5. Configuration via boot/module params
+6. Potential improvements
+7. Bug reports, debugging and updates
+8. Acknowledgements
+
+
+1. Purpose and history
+----------------------
+The tmscsim driver supports PCI SCSI Host Adapters based on the AM53C974
+chip. AM53C974 based SCSI adapters include: 
+ Tekram DC390, DC390T
+ Dawicontrol 2974
+ some on-board adapters
+(This is most probably not a complete list)
+
+It has originally written by C.L. Huang from the Tekram corp. to support the
+Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram
+scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F
+(NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter,
+tmscsimw, which supported DC390W/U/F adapters. It's not maintained any more,
+as the ncr53c8xx is perfectly supporting these adpaters since some time.
+
+The driver first appeared in April 1996, exclusively supported the DC390 
+and has been enhanced since then in various steps. In May 1998 support for 
+general AM53C974 based adapters and some possibilities to configure it were
+added. The non-DC390 support works by assuming some values for the data
+normally taken from the DC390 EEPROM. See below (chapter 5) for details.
+
+When using the DC390, the configuration is still be done using the DC390
+BIOS setup. The DC390 EEPROM is read and used by the driver, any boot or
+module parameters (chapter 5) are ignored! However, you can change settings
+dynamically, as described in chapter 4. 
+
+For a more detailed description of the driver's history, see the first lines
+of tmscsim.c.
+The numbering scheme isn't consistent. The first versions went from 1.00 to
+1.12, then 1.20a to 1.20t. Finally I decided to use the ncr53c8xx scheme. So
+the next revisions will be 2.0a to 2.0X (stable), 2.1a to 2.1X (experimental),
+2.2a to 2.2X (stable, again) etc. (X = anything between a and z.) If I send
+fixes to people for testing, those will have a digit appended, e.g. 2.0a1.
+
+
+2. Installation
+---------------
+If you got any recent kernel with this driver and document included in
+linux/drivers/scsi, you basically have to do nothing special to use this
+driver. Of course you have to choose to compile SCSI support and DC390(T)
+support into your kernel or as module when configuring your kernel for
+compiling.
+
+If you got an older kernel with an old version of this driver included, you
+should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and
+README.tmscsim) from this directory to linux/drivers/scsi. You have to
+recompile your kernel/module of course.
+
+You should apply the three patches included in dc390-20-kernel.diff
+(Applying them: cd /usr/src; patch -p0 <~/dc390-20-kernel.diff)
+The patches are against 2.1.103, so you might have to manually resolve
+rejections when applying to another kernel version.
+
+The patches will update the kernel startup code to allow boot parameters to
+be passed to the driver, update the Documentation and finally offer you the
+possibility to omit the non-DC390 parts of the driver.
+(By selecting "Omit support for non DC390" you basically disable the
+emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes
+of memory.)
+
+If you got a very old kernel without the tmscsim driver (pre 2.0.31)
+I recommend upgrading your kernel. However, if you don't want to, please
+contact me to get the appropriate patches.
+
+Testing a SCSI driver is always a delicate thing to do. The 2.0 driver has
+proven stable on many systems, but it's still a good idea to take some
+precautions. In an ideal world you would have a full backup of your disks.
+The world isn't ideal and most people don't have full backups (me neither).
+So take at least the following two measures:
+* make your kernel remount the FS read-only on detecting an error:
+  tune2fs -e remount-ro /dev/sd??
+* have copies of your SCSI disk's partition tables on some safe location:
+  dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1
+* make sure you are able to boot Linux (e.g. from floppy disk using InitRD)
+  if your SCSI disk gets corrupted. You can use 
+  ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz
+
+One more warning: I used to overclock my PCI bus to 41.67 MHz. My Tekram
+DC390F (Sym53c875) accepted this as well as my Millenium. But the Am53C974
+produced errors and started to corrupt my disks. So don't do that! A 37.50
+MHz PCI bus works for me, though, but I don't recommend using higher clocks
+than the 33.33 MHz being in the PCI spec.
+
+If you want to share the IRQ with another device and the driver refuses to
+do, you might succeed with changing the DC390_IRQ type in tmscsim.c to 
+SA_SHIRQ | SA_INTERRUPT.
+
+
+3.Features
+----------
+- SCSI
+ * Tagged queueing
+ * Sync speed up to 10 MHz
+ * Disconnection
+ * Multiple LUNs
+
+- General / Linux interface
+ * Support for up to 4 adapters.
+ * DC390 EEPROM usage or boot/module params
+ * Information via cat /proc/scsi/tmscsim/?
+ * Dynamically configurable by writing to /proc/scsi/tmscsim/?
+ * Dynamic allocation of resources
+ * SMP support: Adapter specific locks (Linux 2.1.x)
+ * Uniform source code for Linux-2.x.y
+ * Support for dyn. addition/removal of devices via add/remove-single-device
+   (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi 
+    H = Host, C = Channel, I = SCSI ID, L = SCSI LUN.) Use with care!
+ * Try to use the partition table for the determination of the mapping
+
+
+4. Configuration via /proc/scsi/tmscsim/?
+-----------------------------------------
+First of all look at the output of /proc/scsi/tmscsim/? by typing
+ cat /proc/scsi/tmscsim/?
+The "?" should be replaced by the SCSI host number. (The shell might do this
+for you.)
+You will see some info regarding the adapter and, at the end, a listing of
+the attached devices and their settings.
+
+Here's an example:
+garloff@kg1:/home/garloff > cat /proc/scsi/tmscsim/0
+Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 1.20s, 1998/08/20
+SCSI Host Nr 0, AM53C974 Adapter Nr 0
+IOPortBase 0x6200, IRQLevel 0x09
+MaxID 7, MaxLUN 8, AdapterID 7, SelTimeout 250 ms
+TagMaxNum 16, Status 0, ACBFlag 0, GlitchEater 24 ns
+Statistics: Nr of Cmnds 39563, Cmnds not sent directly 0, Out of SRB conds 0
+            Nr of lost arbitrations 17
+Nr of attached devices: 4, Nr of DCBs: 4
+Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs
+00  00  00  Yes  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15
+01  01  00  Yes  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15
+02  03  00  Yes  Yes  Yes  Yes  No   No    100 ns    10.0 M      15
+03  05  00  Yes  No   Yes  Yes  No   No   (200 ns)
+
+Note that the settings MaxID and MaxLUN are not zero- but one-based, which
+means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This
+is somehow inconvenient, but the way the mid-level SCSI code expects it to be.
+
+ACB and DCB are acronyms for Adapter Control Block and Device Control Block.
+These are data structures of the driver containing information about the
+adapter and the connected SCSI devices respectively.
+
+Idx is the device index (just a consecutive number for the driver), ID and
+LUN are the SCSI ID and LUN, Prty means Parity checking, Sync synchronous
+negotiation, DsCn Disconnection, SndS Send Start command on startup (not
+used by the driver) and TagQ Tagged Command Queueing. NegoPeriod and
+SyncSpeed are somehow redundant, because they are reciprocal values 
+(1 / 112 ns = 8.9 MHz). At least in theory. The driver is able to adjust the
+NegoPeriod more accurate (4ns) than the SyncSpeed (1 / 25ns). I don't know
+if certain devices will have problems with this discrepancy. Max. speed is
+10 MHz corresp. to a min. NegoPeriod of 100 ns. 
+(The driver allows slightly higher speeds if the devices (Ultra SCSI) accept
+it, but that's out of adapter spec, on your own risk and unlikely to improve
+performance. You're likely to crash your disks.) 
+SyncOffs is the offset used for synchronous negotiations; max. is 15. 
+The last values are only shown, if Sync is enabled. (NegoPeriod is still
+displayed in brackets to show the values which will be used after enabling
+Sync.)
+The STOP parameter is for testing/debugging purposes only and should bet set
+to No. Please don't fiddle with it, unless you want to get rid of the
+contents of your disk.
+
+If you want to change a setting, you can do that by writing to
+/proc/scsi/tmscsim/?. Basically you have to imitate the output of driver.
+(Don't use the brackets for NegoPeriod on Sync disabled devices.)
+You don't have to care about capitalisation. The driver will accept space,
+tab, comma, = and : as separators.
+
+There are three kinds of changes: 
+
+(1) Change driver settings: 
+    You type the names of the parameters and the params following it.
+    Example:
+     echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0
+
+    Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut,
+    TagMaxNum, ACBFlag and GlitchEater. Don't change ACBFlag unless you
+    want to see what happens, if the driver hangs.
+
+(2) Change device settings: You write a config line to the driver. The Nr
+    must match the ID and LUN given. If you give "-" as parameter, it is
+    ignored and the corresponding setting won't be changed. 
+    You can use "y" or "n" instead of "Yes" and "No" if you want to.
+    You don't need to specify a full line. The driver automatically performs
+    an INQUIRY on the device if necessary to check if it is capable to operate
+    with the given settings (Sync, TagQ).
+    Examples:
+     echo "0 0 0 y y y - y - 10" >/proc/scsi/tmscsim/0
+     echo "3 5 0 y n y" >/proc/scsi/tmscsim/0
+
+    To give a short explanation of the first example: 
+    The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0),
+    select the device to which the following parameters apply. Note that it
+    would be sufficient to use the index or both SCSI ID and LUN, but I chose
+    to require all three to have a syntax similar to the output.
+    The following "y y y - y" enables Parity checking, enables Synchronous
+    transfers, Disconnection, leaves Send Start (not used) untouched and
+    enables Tagged Command Queueing for the selected device. The "-" skips
+    the Negotiation Period setting but the "10" sets the max sync. speed to
+    10 MHz. It's useless to specify both NegoPeriod and SyncSpeed as
+    discussed above. The values used in this example will result in maximum
+    performance.
+
+(3) Special commands: You can force a SCSI bus reset, an INQUIRY command and
+    the removal of a device's DCB.
+    This is only used for debugging when you meet problems. The parameter of
+    the INQUIRY and remove command is the device index as shown by the
+    output of /proc/scsi/tmscsim/? in the device listing in the first column
+    (Idx).
+    Examples:
+     echo "reset" >/proc/scsi/tmscsim/0
+     echo "inquiry 1" >/proc/scsi/tmscsim/0
+     echo "remove 2" >/proc/scsi/tmscsim/1
+
+    Note that you will meet problems when you remove a device's DCB with the
+    remove command if it contains partitions which are mounted. Only use it
+    after unmounting its partitions, telling the SCSI mid-level code to
+    remove it (scsi remove-single-device) and you really need a few bytes of
+    memory.
+
+
+I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing
+settings to see if everything changed as requested.
+
+
+5. Configuration via boot/module parameters
+-------------------------------------------
+With the DC390, the driver reads its EEPROM settings and IGNORES boot / 
+module parameters. If you want to override the EEPROM settings of a DC390, 
+you have to use the /proc/scsi/tmscsim/? interface described in the above
+chapter.
+
+However, if you do have another AM53C974 based adapter you might want to
+adjust some settings before you are able to write to the /proc/scsi/tmscsim/?
+pseudo-file, e.g. if you want to use another adapter ID than 7. (Note that
+the log message "DC390: No EEPROM found!" is normal without a DC390.)
+For this purpose, you can pass options to the driver before it is initialised
+by using kernel or module parameters. See lilo(8) or modprobe(1) manual
+pages on how to pass params to the kernel or a module.
+
+The syntax of the params is much shorter than the syntax of the /proc/...
+interface. This makes it a little bit more difficult to use. However, long
+parameter lines have the risk to be misinterpreted and the length of kernel
+parameters is limited.
+
+As the support for non-DC390 adapters works by simulating the values of the
+DC390 EEPROM, the settings are given in a DC390 BIOS' way.
+
+Here's the syntax:
+tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds
+
+Each of the parameters is a number, containing the described information:
+
+* AdaptID: The SCSI ID of the host adapter. Must be in the range 0..7
+  Default is 7.
+
+* SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values
+  0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is
+  1 (8.0 MHz).
+
+* DevMode is a bit mapped value describing the per-device features. It
+  applies to all devices. (Sync, Disc and TagQ will only apply, if the
+  device supports it.) The meaning of the bits (* = default):
+
+   Bit Val(hex) Val(dec)  Meaning
+   *0   0x01       1     Parity check
+   *1   0x02       2     Synchronous Negotiation
+   *2   0x04       4     Disconnection
+   *3   0x08       8     Send Start command on startup. (Not used)
+   *4   0x10      16     Tagged Queueing
+
+  As usual, the desired value is obtained by adding the wanted values. If
+  you want to enable all values, e.g., you would use 31(0x1f). Default is 31.
+
+* AdaptMode is a bit mapped value describing the enabled adapter features.
+
+   Bit Val(hex) Val(dec)  Meaning
+   *0   0x01       1     Support more than two drives. (Not used)
+   *1   0x02       2     Use DOS compatible mapping for HDs greater than 1GB.
+   *2   0x04       4     Reset SCSI Bus on startup.
+   *3   0x08       8     Active Negation: Improves SCSI Bus noise immunity.
+    4   0x10      16     Immediate return on BIOS seek command. (Not used)
+ (*)5   0x20      32     Check for LUNs >= 1.
+  
+  The default for LUN Check depends on CONFIG_SCSI_MULTI_LUN.
+
+* TaggedCmnds is a number indicating the maximum number of Tagged Commands.
+  It is the binary logarithm - 1 of the actual number. Max is 4 (32).
+   Value  Number of Tagged Commands
+     0          2
+     1          4
+     2          8
+    *3         16
+     4         32
+
+Example:
+ modprobe tmscsim tmscsim=6,2,31
+would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device
+features and leave the adapter features and the number of Tagged Commands 
+to the defaults.
+
+As you can see, you don't need to specify all of the five params.
+
+The defaults (7,1,31,15,3) are aggressive to allow good performance. You can
+use tmscsim=7,0,31,63,4 for maximum performance, if your SCSI chain is
+perfect. If you meet problems, you can use tmscsim=-1 which is a shortcut
+for tmscsim=7,4,9,15,2. 
+
+
+6. Potential improvements
+-------------------------
+Most of the intended work on the driver has been done. Here are a few ideas
+to further improve its usability:
+
+* More intelligent abort() routine
+* Implement new_eh code (Linux-2.1+)
+* Have the mid-level code (and not the driver) handle more of the various
+  conditions.
+* Rework command queueing in the driver
+* More user friendly boot/module param syntax
+
+Further investigation on these problems:
+
+* TagQ and Disconnection (Resel: SRB Tag Seleection)
+* Problems with IRQ sharing (IO-APIC on SMP Systems) (??)
+* Driver crashes with readcdda (xcdroast)
+
+Known problems:
+
+* There was a report that with a certain Scanner, the last SCSI command
+  won't be finished correctly. This might be a command queueing bug or a bug
+  in SCSI implementation of the scanner. Issueing another command to the
+  scanner seems to help. (Try echo "INQUIRY x" >/proc/scsi/tmscsim/?, where
+  x is the index (not the SCSI ID!) of the scanner. See 4.(3).)
+* If there is a valid partition table, the driver will use it for determing
+  the mapping. Other operating systems may not like this mapping, though
+  it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the
+  partition table and used a H/S = 64/32 or 255/63 translation. So if you
+  want to be compatible to those, use this old mapping when creating
+  partition tables.
+* In some situations, the driver will get stuck in an abort loop. Please
+  disable DsCn, if you meet this problem. Please contact me for further
+  debugging.
+* 2.1.115+: Linux misses locks in sr_ioctl.c and scsi_ioctl.c
+  There used to be a patch included here, which partially solved the
+  problem. I suggest you contact Chiaki Ishikawa <ishikawa@yk.rim.or.jp>, 
+  Richard Waltham <dormouse@farsrobt.demon.co.uk> or Doug Ledford
+  <dledford@dialnet.net>, if you want to help further debugging it.
+* 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because
+  the mid-level code doesn't handle BLIST_SINGLELUN correctly. Apply
+  the patch 2035-scsi-singlelun.diff. Thanks to Chiaki Ishikawa.
+  I was told that this fix will be in 2.0.36, so you don't need it for
+  2.0.36. 
+[The patch file is contained in the dc390-XXX.tar.gz files which can be found
+on the ftp server. See below.]
+
+
+7. Bug reports, debugging and updates
+-------------------------------------
+Whenever you have problems with the driver, you are invited to ask the
+author for help. However, I'd suggest reading the docs and trying to solve
+the problem yourself, first. 
+If you find something, which you believe to be a bug, please report it to me. 
+Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and
+maybe the DC390 log messages to the report. 
+
+Bug reports should be send to me (Kurt Garloff <K.Garloff@ping.de>) as well
+as to the linux-scsi list (<linux-scsi@vger.rutgers.edu>), as sometimes bugs
+are caused by the SCSI mid-level code.
+
+I will ask you for some more details and probably I will also ask you to
+enable some of the DEBUG options in the driver (tmscsim.c:DC390_DEBUGXXX
+defines). The driver will produce some data for the syslog facility then.
+Beware: If your syslog gets written to a SCSI disk connected to your
+AM53C974, the logging might produce log output again, and you might end
+having your box spending most of its time doing the logging.
+
+The latest version of the driver can be found at:
+ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+
+
+8. Acknowledgements
+-------------------
+Thanks to Linus Torvalds, Alan Cox, David Miller, Rik v. Riel, the FSF
+people, the XFree86 team and all the others for the wonderful OS and
+software. 
+Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver
+release and support.
+Thanks to Doug Ledford, Gerard Roudier for support with SCSI coding.
+Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert 
+Tonneau) for intensively testing the driver (and even risking data loss
+doing this during early revisions). 
+
+
+-------------------------------------------------------------------------
+Written by Kurt Garloff <K.Garloff@ping.de> 1998/06/11
+Last updated 1998/10/15, driver revision 2.0b
+$Id: README.tmscsim,v 2.4 1998/10/24 08:45:02 garloff Exp $
index 88ae90f..b3a30eb 100644 (file)
  *     Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
  *                  Bus Master Host Adapter                           *
  ***********************************************************************/
+/* $Id: dc390.h,v 2.3 1998/10/24 08:45:02 garloff Exp $ */
 
 #include <linux/version.h>
 
 /*
- * AMD 53C974 driver, header file
+ * DC390/AMD 53C974 driver, header file
  */
 
 #ifndef DC390_H
 #define DC390_H
 
+#define DC390_BANNER "Tekram DC390/AM53C974"
+#define DC390_VERSION "2.0b 1998/10/24"
+
 #if defined(HOSTS_C) || defined(MODULE)
 
 #include <scsi/scsicam.h>
@@ -30,24+34,24 @@ static int DC390_release(struct Scsi_Host *);
 # define DC390_release NULL
 #endif
 
-extern struct proc_dir_entry proc_scsi_tmscsim;
-extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
-
-#define DC390_T    {                             \
-   proc_dir:       &proc_scsi_tmscsim,            \
-   proc_info:      tmscsim_proc_info,             \
-   name:           "Tekram DC390(T) V1.12 Feb-25-1998",\
-   detect:         DC390_detect,                 \
-   release:        DC390_release,                \
-   queuecommand:   DC390_queue_command,                  \
-   abort:          DC390_abort,                  \
-   reset:          DC390_reset,                  \
-   bios_param:     DC390_bios_param,             \
-   can_queue:      10,                                   \
-   this_id:        7,                             \
-   sg_tablesize:   SG_ALL,                       \
-   cmd_per_lun:    2,                            \
-   use_clustering: DISABLE_CLUSTERING            \
+extern struct proc_dir_entry DC390_proc_scsi_tmscsim;
+extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+
+#define DC390_T    {                                   \
+   proc_dir:       &DC390_proc_scsi_tmscsim,           \
+   proc_info:      DC390_proc_info,                    \
+   name:           DC390_BANNER " V" DC390_VERSION,    \
+   detect:         DC390_detect,                       \
+   release:        DC390_release,                      \
+   queuecommand:   DC390_queue_command,                        \
+   abort:          DC390_abort,                                \
+   reset:          DC390_reset,                                \
+   bios_param:     DC390_bios_param,                   \
+   can_queue:      17,                                 \
+   this_id:        7,                                  \
+   sg_tablesize:   SG_ALL,                             \
+   cmd_per_lun:    8,                                  \
+   use_clustering: DISABLE_CLUSTERING                  \
    }
 
 #endif /* defined(HOSTS_C) || defined(MODULE) */
index c995a83..e09e7dc 100644 (file)
  *     Description: Device Driver for Tekram DC-390 (T) PCI SCSI      *
  *                  Bus Master Host Adapter                           *
  ***********************************************************************/
+/* $Id: scsiiom.c,v 2.3 1998/10/24 09:10:28 garloff Exp $ */
 
-
-static USHORT
-DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+UCHAR
+dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
-    USHORT ioport, rc;
-    UCHAR  bval, bval1, i, cnt;
-    PUCHAR ptr;
-    ULONG  wlval;
+    USHORT wlval;
+    UCHAR  bval, bval1;
 
     pSRB->TagNumber = 31;
-    ioport = pACB->IOPortBase;
-    bval = pDCB->UnitSCSIID;
-    outb(bval,ioport+Scsi_Dest_ID);
-    bval = pDCB->SyncPeriod;
-    outb(bval,ioport+Sync_Period);
-    bval = pDCB->SyncOffset;
-    outb(bval,ioport+Sync_Offset);
-    bval = pDCB->CtrlR1;
-    outb(bval,ioport+CtrlReg1);
-    bval = pDCB->CtrlR3;
-    outb(bval,ioport+CtrlReg3);
-    bval = pDCB->CtrlR4;
-    outb(bval,ioport+CtrlReg4);
-    bval = CLEAR_FIFO_CMD;        /* Flush FIFO */
-    outb(bval,ioport+ScsiCmd);
-
+    DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+    DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+    DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+    DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+    DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+    DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);            /* Flush FIFO */
+    DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\
+           pSRB->CmdBlock[0], pDCB->SyncMode);)
     pSRB->ScsiPhase = SCSI_NOP0;
+    //pSRB->MsgOutBuf[0] = MSG_NOP;
+    //pSRB->MsgCnt = 0;
     bval = pDCB->IdentifyMsg;
-    if( !(pDCB->SyncMode & EN_ATN_STOP) )
+    if( !(pDCB->SyncMode & EN_ATN_STOP) )      /* Don't always try send Extended messages on arbitration */
     {
        if( (pSRB->CmdBlock[0] == INQUIRY) ||
            (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
            (pSRB->SRBFlag & AUTO_REQSENSE) )
        {
-           bval &= 0xBF;       /* NO disconnection */
-           outb(bval,ioport+ScsiFifo);
-           bval1 = SELECT_W_ATN;
+           bval &= 0xBF;       /* No DisConn */
+           DC390_write8 (ScsiFifo, bval);
+           bval1 = SEL_W_ATN;
            pSRB->SRBState = SRB_START_;
+           DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
            if( pDCB->SyncMode & SYNC_ENABLE )
-           {
-               if( !(pDCB->IdentifyMsg & 7) ||
+               {
+               if( !(pDCB->IdentifyMsg & 7) ||         /* LUN == 0 || Cmd != INQUIRY */
                    (pSRB->CmdBlock[0] != INQUIRY) )
                {
-                   bval1 = SEL_W_ATN_STOP;
+                   bval1 = SEL_W_ATN_STOP;     /* Try to establish SYNC nego */
                    pSRB->SRBState = SRB_MSGOUT;
                }
            }
        }
-       else
+       else    /* TagQ ? */
        {
-           if(pDCB->SyncMode & EN_TAG_QUEUING)
+           DC390_write8 (ScsiFifo, bval);
+           if(pDCB->SyncMode & EN_TAG_QUEUEING)
            {
-               outb(bval,ioport+ScsiFifo);
-               bval = MSG_SIMPLE_QTAG;
-               outb(bval,ioport+ScsiFifo);
-               wlval = 1;
-               bval = 0;
-               while( wlval & pDCB->TagMask )
-               {
-                   wlval = wlval << 1;
-                   bval++;
-               }
-               outb(bval,ioport+ScsiFifo);
+               DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG);
+                   DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
+               bval = 0; wlval = 1;
+               while (wlval & pDCB->TagMask)
+                 { bval++; wlval <<= 1; };
                pDCB->TagMask |= wlval;
+               DC390_write8 (ScsiFifo, bval);
                pSRB->TagNumber = bval;
-               bval1 = SEL_W_ATN2;
+               DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
+               bval1 = SEL_W_ATN3;
                pSRB->SRBState = SRB_START_;
            }
-           else
+           else        /* No TagQ */
            {
-               outb(bval,ioport+ScsiFifo);
-               bval1 = SELECT_W_ATN;
+               bval1 = SEL_W_ATN;
+                   DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
                pSRB->SRBState = SRB_START_;
            }
        }
 
-       if( pSRB->SRBFlag & AUTO_REQSENSE )
-       {
-           bval = REQUEST_SENSE;
-           outb(bval,ioport+ScsiFifo);
-           bval = pDCB->IdentifyMsg << 5;
-           outb(bval,ioport+ScsiFifo);
-           bval = 0;
-           outb(bval,ioport+ScsiFifo);
-           outb(bval,ioport+ScsiFifo);
-           bval = sizeof(pSRB->pcmd->sense_buffer);
-           outb(bval,ioport+ScsiFifo);
-           bval = 0;
-           outb(bval,ioport+ScsiFifo);
-       }
-       else
-       {
-           cnt = pSRB->ScsiCmdLen;
-           ptr = (PUCHAR) pSRB->CmdBlock;
-           for(i=0; i<cnt; i++)
-           {
-               bval = *ptr++;
-               outb(bval,ioport+ScsiFifo);
-           }
-       }
     }
-    else       /* ATN_STOP */
+    else       /* ATN_STOP: Always try to establish Sync nego */
     {
        if( (pSRB->CmdBlock[0] == INQUIRY) ||
            (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
            (pSRB->SRBFlag & AUTO_REQSENSE) )
        {
-           bval &= 0xBF;
-           outb(bval,ioport+ScsiFifo);
-           bval1 = SELECT_W_ATN;
+           bval &= 0xBF;       /* No DisConn */
+           DC390_write8 (ScsiFifo, bval);
+           bval1 = SEL_W_ATN;
+           DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
            pSRB->SRBState = SRB_START_;
+             /* ??? */
            if( pDCB->SyncMode & SYNC_ENABLE )
            {
-               if( !(pDCB->IdentifyMsg & 7) ||
+               if( !(pDCB->IdentifyMsg & 7) ||         /* LUN == 0 || Cmd != INQUIRY */
                    (pSRB->CmdBlock[0] != INQUIRY) )
                {
-                   bval1 = SEL_W_ATN_STOP;
+                   bval1 = SEL_W_ATN_STOP;     /* Try to establish Sync nego */
                    pSRB->SRBState = SRB_MSGOUT;
                }
            }
        }
-       else
+       else    /* TagQ ? */
        {
-           if(pDCB->SyncMode & EN_TAG_QUEUING)
+           DC390_write8 (ScsiFifo, bval);
+           if(pDCB->SyncMode & EN_TAG_QUEUEING)
            {
-               outb(bval,ioport+ScsiFifo);
                pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
-               wlval = 1;
-               bval = 0;
-               while( wlval & pDCB->TagMask )
-               {
-                   wlval = wlval << 1;
-                   bval++;
-               }
+               DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
+               bval = 0; wlval = 1;
+               while (wlval & pDCB->TagMask)
+                 { bval++; wlval <<= 1; };
                pDCB->TagMask |= wlval;
                pSRB->TagNumber = bval;
+               DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
                pSRB->MsgOutBuf[1] = bval;
                pSRB->MsgCnt = 2;
                bval1 = SEL_W_ATN_STOP;
-               pSRB->SRBState = SRB_START_;
+               pSRB->SRBState = SRB_START_;    /* ?? */
            }
-           else
+           else        /* No TagQ */
            {
-               outb(bval,ioport+ScsiFifo);
                pSRB->MsgOutBuf[0] = MSG_NOP;
                pSRB->MsgCnt = 1;
                pSRB->SRBState = SRB_START_;
                bval1 = SEL_W_ATN_STOP;
-           }
+               DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
+           };
        }
     }
-    bval = inb( ioport+Scsi_Status );
-    if( bval & INTERRUPT )
+    if (bval1 != SEL_W_ATN_STOP)
+      {        /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
+       if( pSRB->SRBFlag & AUTO_REQSENSE )
+         {
+           bval = 0;
+           DC390_write8 (ScsiFifo, REQUEST_SENSE);
+           DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
+           DC390_write8 (ScsiFifo, bval);
+           DC390_write8 (ScsiFifo, bval);
+           DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+           DC390_write8 (ScsiFifo, bval);
+           DEBUG1(printk ("DC390: AutoReqSense !\n");)
+         }
+       else    /* write cmnd to bus */ 
+         {
+           PUCHAR ptr; UCHAR i;
+           ptr = (PUCHAR) pSRB->CmdBlock;
+           for (i=0; i<pSRB->ScsiCmdLen; i++)
+             DC390_write8 (ScsiFifo, *(ptr++));
+         };
+      }
+
+    /* Check if we can't win arbitration */
+    if (DC390_read8 (Scsi_Status) & INTERRUPT)
     {
        pSRB->SRBState = SRB_READY;
        pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
-       rc = 1;
+       DEBUG0(printk ("DC390: Interrupt during StartSCSI!\n");)
+       return 1;
     }
     else
     {
        pSRB->ScsiPhase = SCSI_NOP1;
+       DEBUG0(if (pACB->pActiveDCB)    \
+                   printk ("DC390: ActiveDCB != 0\n");)
+       DEBUG0(if (pDCB->pActiveSRB)    \
+                   printk ("DC390: ActiveSRB != 0\n");)
        pACB->pActiveDCB = pDCB;
        pDCB->pActiveSRB = pSRB;
-       rc = 0;
-       outb(bval1,ioport+ScsiCmd);
+       //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+       DC390_write8 (ScsiCmd, bval1);
+       return 0;
     }
-    return( rc );
 }
 
+//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
+#define DMA_INT 0
 
-static void
+#if DMA_INT
+/* This is similar to AM53C974.c ... */
+static UCHAR 
+dc390_dma_intr (PACB pACB)
+{
+  PSRB pSRB;
+  UCHAR dstate;
+  DEBUG0(USHORT pstate;PDEVDECL1;)
+  
+  DEBUG0(PDEVSET1;)
+  DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);)
+  DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
+       { printk("DC390: PCI state = %04x!\n", pstate); \
+         PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};)
+
+  dstate = DC390_read8 (DMA_Status);
+  DC390_write8 (DMA_Status, dstate);   /* clear */
+  //DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */
+
+  if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
+  else pSRB  = pACB->pActiveDCB->pActiveSRB;
+  
+  if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
+    {
+       printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
+       return dstate;
+    };
+  if (dstate & DMA_XFER_DONE)
+    {
+       ULONG residual, xferCnt; int ctr = 5000000;
+       if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
+         {
+           do
+             {
+               DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");)
+               dstate = DC390_read8 (DMA_Status);
+               DC390_write8 (DMA_Status, dstate);      /* clear */
+               residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
+                 DC390_read8 (CtcReg_High) << 16;
+               residual += DC390_read8 (Current_Fifo) & 0x1f;
+             } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
+           if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+           /* residual =  ... */
+         }
+       else
+           residual = 0;
+       
+       /* ??? */
+       
+       xferCnt = pSRB->SGToBeXferLen - residual;
+       pSRB->SGBusAddr += xferCnt;
+       pSRB->TotalXferredLen += xferCnt;
+       pSRB->SGToBeXferLen = residual;
+# ifdef DC390_DEBUG0
+       printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", 
+               (unsigned int)residual, (unsigned int)xferCnt);
+# endif
+       
+       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    }
+  return dstate;
+};
+#endif
+
+void __inline__
 DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
 {
     PACB   pACB;
     PDCB   pDCB;
     PSRB   pSRB;
-    USHORT ioport = 0;
-    USHORT phase, i;
+    UCHAR  sstatus=0;
+    UCHAR  phase, i;
     void   (*stateV)( PACB, PSRB, PUCHAR );
-    UCHAR  istate = 0;
-    UCHAR  sstatus=0, istatus;
+    UCHAR  istate, istatus;
+    UCHAR  dstatus;
+    DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS
+
+    pACB = dc390_pACB_start;
 
-    pACB = pACB_start;
-    if( pACB == NULL )
+    if (pACB == 0)
+    {
+       printk(KERN_ERR "DC390: Interrupt on uninitialized adapter!\n");
        return;
-    for( i=0; i < adapterCnt; i++ )
+    }
+    DC390_LOCK_DRV;
+
+    for( i=0; i < dc390_adapterCnt; i++ )
     {
        if( pACB->IRQLevel == (UCHAR) irq )
        {
-            ioport = pACB->IOPortBase;
-            sstatus = inb( ioport+Scsi_Status );
+            sstatus = DC390_read8 (Scsi_Status);
             if( sstatus & INTERRUPT )
                 break;
             else
@@ -207,99+273,128 @@ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
        }
     }
 
-#ifdef DC390_DEBUG1
-       printk("sstatus=%2x,",sstatus);
+    DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);)
+
+    if( pACB == (PACB )-1) { DC390_UNLOCK_DRV; return; };
+   
+#if DMA_INT
+    DC390_LOCK_IO;
+    DC390_LOCK_ACB;
+    dstatus = dc390_dma_intr (pACB);
+    DC390_UNLOCK_ACB;
+    DC390_UNLOCK_IO;
+
+    DEBUG1(printk ("dstatus=%02x,", dstatus);)
+    if (! (dstatus & SCSI_INTERRUPT))
+      {
+       DEBUG0(printk ("DC390 Int w/o SCSI actions (only DMA?)\n");)
+       DC390_UNLOCK_DRV;
+       return;
+      };
+#else
+    dstatus = DC390_read8 (DMA_Status);
 #endif
 
-    if( pACB == (PACB )-1 )
-    {
-       printk("DC390: Spurious interrupt detected!\n");
-       return;
-    }
+    DC390_LOCK_IO;
+    DC390_LOCK_ACB;
+    DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */
 
-    istate = inb( ioport+Intern_State );
-    istatus = inb( ioport+INT_Status );
+    istate = DC390_read8 (Intern_State);
+    istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
 
-#ifdef DC390_DEBUG1
-       printk("Istatus=%2x,",istatus);
-#endif
+    DEBUG1(printk ("Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);)
+    dc390_laststatus = dstatus<<24 | sstatus<<16 | istate<<8 | istatus;
 
+    if (sstatus & ILLEGAL_OP_ERR)
+       {
+              printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
+              dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
+       };
+       
     if(istatus &  DISCONNECTED)
     {
-       DC390_Disconnect( pACB );
-       return;
+       dc390_Disconnect( pACB );
+       goto unlock;
     }
 
     if(istatus &  RESELECTED)
     {
-       DC390_Reselect( pACB );
-       return;
+       dc390_Reselect( pACB );
+       goto unlock;
     }
 
     if(istatus &  INVALID_CMD)
     {
-       DC390_InvalidCmd( pACB );
-       return;
+       dc390_InvalidCmd( pACB );
+       goto unlock;
     }
 
     if(istatus &  SCSI_RESET)
     {
-       DC390_ScsiRstDetect( pACB );
-       return;
+       dc390_ScsiRstDetect( pACB );
+       goto unlock;
     }
 
-    if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) )
+    if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
     {
        pDCB = pACB->pActiveDCB;
-       pSRB = pDCB->pActiveSRB;
-       if( pDCB )
+       if (!pDCB)
        {
-           if( pDCB->DCBFlag & ABORT_DEV_ )
-               EnableMsgOut( pACB, pSRB );
-       }
+               printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n");
+               goto unlock;
+       };
+       pSRB = pDCB->pActiveSRB;
+       if( pDCB->DCBFlag & ABORT_DEV_ )
+               dc390_EnableMsgOut( pACB, pSRB );
 
-       phase = (USHORT) pSRB->ScsiPhase;
-       stateV = (void *) DC390_phase0[phase];
-       stateV( pACB, pSRB, &sstatus );
+       phase = pSRB->ScsiPhase;
+       DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);)
+       stateV = (void *) dc390_phase0[phase];
+       ( *stateV )( pACB, pSRB, &sstatus );
 
        pSRB->ScsiPhase = sstatus & 7;
-       phase = (USHORT) sstatus & 7;
-       stateV = (void *) DC390_phase1[phase];
-       stateV( pACB, pSRB, &sstatus );
+       phase = (UCHAR) sstatus & 7;
+       DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);)
+       stateV = (void *) dc390_phase1[phase];
+       ( *stateV )( pACB, pSRB, &sstatus );
     }
+ unlock:
+    DC390_LOCK_DRV_NI;
+    DC390_UNLOCK_ACB;
+    DC390_UNLOCK_IO;
+    DC390_UNLOCK_DRV; /* Restore initial flags */
 }
 
-static void
+void
 do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
 {
-    unsigned long flags;
-
-    spin_lock_irqsave(&io_request_lock, flags);
+    DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);)
+    /* Locking is done in DC390_Interrupt */
     DC390_Interrupt(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    DEBUG1(printk (".. IRQ returned\n");)
 }
 
-static void
-DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR   sstatus, bval;
-    USHORT  ioport;
+    UCHAR   sstatus;
     PSGL    psgl;
     ULONG   ResidCnt, xferCnt;
 
-    ioport = pACB->IOPortBase;
     sstatus = *psstatus;
 
     if( !(pSRB->SRBState & SRB_XFERPAD) )
     {
-       if( sstatus & PARITY_ERR )
+       if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) )
            pSRB->SRBStatus |= PARITY_ERROR;
 
        if( sstatus & COUNT_2_ZERO )
        {
-           bval = inb(ioport+DMA_Status);
-           while( !(bval & DMA_XFER_DONE) )
-               bval = inb(ioport+DMA_Status);
+           int ctr = 5000000; /* only try for about a tenth of a second */
+           while( --ctr && !(DC390_read8 (DMA_Status) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
+               DC390_write8 (DMA_Status,  DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);     /* clear */
+           if (!ctr) printk (KERN_CRIT "DC390: DataOut_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+           DC390_write8 (DMA_Status,  DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */
            pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
            pSRB->SGIndex++;
            if( pSRB->SGIndex < pSRB->SGcount )
@@ -307,7+402,7 @@ DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
                pSRB->pSegmentList++;
                psgl = pSRB->pSegmentList;
 
-               pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+               pSRB->SGBusAddr = virt_to_bus( psgl->address );
                pSRB->SGToBeXferLen = (ULONG) psgl->length;
            }
            else
@@ -315,51+410,50 @@ DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
        }
        else
        {
-           bval = inb( ioport+Current_Fifo );
-           bval &= 0x1f;
-           ResidCnt = (ULONG) inb(ioport+CtcReg_High);
-           ResidCnt = ResidCnt << 8;
-           ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
-           ResidCnt = ResidCnt << 8;
-           ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
-           ResidCnt += (ULONG) bval;
+           ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f;
+           ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16;
+           ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8; 
+           ResidCnt += (ULONG) DC390_read8 (CtcReg_Low);
 
            xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-           pSRB->SGPhysAddr += xferCnt;
+           pSRB->SGBusAddr += xferCnt;
            pSRB->TotalXferredLen += xferCnt;
            pSRB->SGToBeXferLen = ResidCnt;
        }
     }
-    bval = WRITE_DIRECTION+DMA_IDLE_CMD;
-    outb( bval, ioport+DMA_Cmd);
+    DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 }
 
-static void
-DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR   sstatus, bval;
-    USHORT  i, ioport, residual;
+    UCHAR   sstatus, residual, bval;
     PSGL    psgl;
-    ULONG   ResidCnt, xferCnt;
+    ULONG   ResidCnt, xferCnt, i;
     PUCHAR  ptr;
 
-
-    ioport = pACB->IOPortBase;
     sstatus = *psstatus;
 
     if( !(pSRB->SRBState & SRB_XFERPAD) )
     {
-       if( sstatus & PARITY_ERR )
+       if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR))
            pSRB->SRBStatus |= PARITY_ERROR;
 
        if( sstatus & COUNT_2_ZERO )
        {
-           bval = inb(ioport+DMA_Status);
-           while( !(bval & DMA_XFER_DONE) )
-               bval = inb(ioport+DMA_Status);
-
-           bval = READ_DIRECTION+DMA_IDLE_CMD;
-           outb( bval, ioport+DMA_Cmd);
+           int ctr = 5000000; /* only try for about a tenth of a second */
+           int dstate = 0;
+           while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
+               DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);      /* clear */
+           if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+           if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
+           DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \
+               + ((ULONG) DC390_read8 (CtcReg_Mid) << 8)               \
+               + ((ULONG) DC390_read8 (CtcReg_Low));)
+           DEBUG1(printk ("Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
+           DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);  /* clear */
+
+           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 
            pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
            pSRB->SGIndex++;
@@ -368,7+462,7 @@ DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
                pSRB->pSegmentList++;
                psgl = pSRB->pSegmentList;
 
-               pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+               pSRB->SGBusAddr = virt_to_bus( psgl->address );
                pSRB->SGToBeXferLen = (ULONG) psgl->length;
            }
            else
@@ -377,14+471,15 @@ DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
        else    /* phase changed */
        {
            residual = 0;
-           bval = inb(ioport+Current_Fifo);
+           bval = DC390_read8 (Current_Fifo);
            while( bval & 0x1f )
            {
+               DEBUG1(printk ("Check for residuals,");)
                if( (bval & 0x1f) == 1 )
                {
-                   for(i=0; i< 0x100; i++)
+                   for(i=0; i < 0x100; i++)
                    {
-                       bval = inb(ioport+Current_Fifo);
+                       bval = DC390_read8 (Current_Fifo);
                        if( !(bval & 0x1f) )
                            goto din_1;
                        else if( i == 0x0ff )
@@ -395,87+490,85 @@ DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
                    }
                }
                else
-                   bval = inb(ioport+Current_Fifo);
+                   bval = DC390_read8 (Current_Fifo);
            }
 din_1:
-           bval = READ_DIRECTION+DMA_BLAST_CMD;
-           outb(bval, ioport+DMA_Cmd);
-           for(i=0; i<0x8000; i++)
+           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
+           for (i=0; i<0x8000; i++)
            {
-               bval = inb(ioport+DMA_Status);
-               if(bval & BLAST_COMPLETE)
+               bval = DC390_read8 (DMA_Status);
+               DC390_write8 (DMA_Status, BLAST_COMPLETE | DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);     /* clear */
+               if (bval & BLAST_COMPLETE)
                    break;
            }
-           bval = READ_DIRECTION+DMA_IDLE_CMD;
-           outb(bval, ioport+DMA_Cmd);
+           if (i == 0x8000) printk (KERN_CRIT "DC390: DMA Blast aborted unfinished!!\n");
+           //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 
-           ResidCnt = (ULONG) inb(ioport+CtcReg_High);
-           ResidCnt = ResidCnt << 8;
-           ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
-           ResidCnt = ResidCnt << 8;
-           ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+           DEBUG1(printk ("Blast: Read %i times DMA_Status %02x", i, bval);)
+           ResidCnt = (ULONG) DC390_read8 (CtcReg_High);
+           ResidCnt <<= 8;
+           ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid);
+           ResidCnt <<= 8;
+           ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low);
 
            xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-           pSRB->SGPhysAddr += xferCnt;
+           pSRB->SGBusAddr += xferCnt;
            pSRB->TotalXferredLen += xferCnt;
            pSRB->SGToBeXferLen = ResidCnt;
 
            if( residual )
            {
-               bval = inb(ioport+ScsiFifo);        /* get residual byte */
-               ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
+               bval = DC390_read8 (ScsiFifo);      /* get one residual byte */
+               ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr );
                *ptr = bval;
-               pSRB->SGPhysAddr++;
+               pSRB->SGBusAddr++; xferCnt++;
                pSRB->TotalXferredLen++;
                pSRB->SGToBeXferLen--;
            }
+           DEBUG1(printk ("Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+                          pSRB->TotalXferredLen, pSRB->SGToBeXferLen);)
+
        }
     }
 }
 
 static void
-DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
 }
 
 static void
-DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  bval;
-    USHORT ioport;
 
-    ioport = pACB->IOPortBase;
-    bval = inb(ioport+ScsiFifo);
-    pSRB->TargetStatus = bval;
-    bval++;
-    bval = inb(ioport+ScsiFifo);       /* get message */
-    pSRB->EndMessage = bval;
+    pSRB->TargetStatus = DC390_read8 (ScsiFifo);
+    //udelay (1);
+    pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */
 
     *psstatus = SCSI_NOP0;
     pSRB->SRBState = SRB_COMPLETED;
-    bval = MSG_ACCEPTED_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
 }
 
 static void
-DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
        *psstatus = SCSI_NOP0;
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-static void
-DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     UCHAR  bval;
-    USHORT ioport, wval, wval1;
+    USHORT wval, wval1;
     PDCB   pDCB;
     PSRB   psrb;
 
-    ioport = pACB->IOPortBase;
     pDCB = pACB->pActiveDCB;
 
-    bval = inb( ioport+ScsiFifo );
+    bval = DC390_read8 (ScsiFifo);
     if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
     {
        if(bval == MSG_DISCONNECT)
@@ -490,12+583,12 @@ DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
            pSRB->SRBState |= SRB_MSGIN_MULTI;
            pSRB->MsgInBuf[0] = bval;
            pSRB->MsgCnt = 1;
-           pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
+           pSRB->pMsgPtr = &(pSRB->MsgInBuf[1]);
        }
        else if(bval == MSG_REJECT_)
        {
-           bval = RESET_ATN_CMD;
-           outb(bval, ioport+ScsiCmd);
+           DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+           pDCB->NegoPeriod = 50;
            if( pSRB->SRBState & DO_SYNC_NEGO)
                goto  set_async;
        }
@@ -521,7+614,7 @@ DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
                psrb = pDCB->pGoingLast;
                if( pSRB )
                {
-                   for( ;; )
+                   for( ;pSRB ; )
                    {
                        if(pSRB->TagNumber != bval)
                        {
@@ -535,7+628,7 @@ DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
                    if( pDCB->DCBFlag & ABORT_DEV_ )
                    {
                        pSRB->SRBState = SRB_ABORT_SENT;
-                       EnableMsgOut( pACB, pSRB );
+                       dc390_EnableMsgOut( pACB, pSRB );
                    }
                    if( !(pSRB->SRBState & SRB_DISCONNECT) )
                        goto  mingx0;
@@ -549,234+642,199 @@ mingx0:
                    pSRB->SRBState = SRB_UNEXPECT_RESEL;
                    pDCB->pActiveSRB = pSRB;
                    pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
-                   EnableMsgOut2( pACB, pSRB );
+                   dc390_EnableMsgOut2( pACB, pSRB );
                }
            }
        }
        else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
-       {
-           pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO);
-           if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) )
+       {       /* Note: This will fail for target initiated SDTR ? */
+           pSRB->SRBState &= ~(SRB_MSGIN_MULTI);
+           if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != EXTENDED_SDTR) )
            {   /* reject_msg: */
                pSRB->MsgCnt = 1;
                pSRB->MsgInBuf[0] = MSG_REJECT_;
-               bval = SET_ATN_CMD;
-               outb(bval, ioport+ScsiCmd);
+               DC390_write8 (ScsiCmd, SET_ATN_CMD);
            }
            else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
            {
 set_async:
                pDCB = pSRB->pSRBDCB;
+               if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
+                       printk ("DC390: Target (%i,%i) initiates Non-Sync?\n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+               pSRB->SRBState &= ~DO_SYNC_NEGO;
                pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
                pDCB->SyncPeriod = 0;
                pDCB->SyncOffset = 0;
-               pDCB->CtrlR3 = FAST_CLK;     /* ;non_fast */
+               pDCB->CtrlR3 = FAST_CLK;        /* fast clock / normal scsi */
                pDCB->CtrlR4 &= 0x3f;
-               pDCB->CtrlR4 |= EATER_25NS;  /* ; 25ns glitch eater */
-               goto  re_prog;
+               pDCB->CtrlR4 |= pACB->glitch_cfg;       /* glitch eater */
+               goto re_prog;
            }
            else
            {   /* set_sync: */
 
                pDCB = pSRB->pSRBDCB;
+               if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
+                       printk ("DC390: Target (%i,%i) initiates Sync: %ins %i ?\n", 
+                               pDCB->UnitSCSIID, pDCB->UnitSCSILUN, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
+               pSRB->SRBState &= ~DO_SYNC_NEGO;
                pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
                pDCB->SyncOffset &= 0x0f0;
                pDCB->SyncOffset |= pSRB->MsgInBuf[4];
                pDCB->NegoPeriod = pSRB->MsgInBuf[3];
                wval = (USHORT) pSRB->MsgInBuf[3];
-               wval = wval << 2;
-               wval--;
-               wval1 = wval / 25;
+               wval = wval << 2; wval -= 3; wval1 = wval / 25; /* compute speed */
                if( (wval1 * 25) != wval)
                    wval1++;
-               bval = FAST_CLK+FAST_SCSI;
-               pDCB->CtrlR4 &= 0x3f;
-               if(wval1 >= 8)
+               bval = FAST_CLK+FAST_SCSI;      /* fast clock / fast scsi */
+               pDCB->CtrlR4 &= 0x3f;           /* Glitch eater: 12ns less than normal */
+               if (pACB->glitch_cfg != NS_TO_GLITCH(0))
+                       pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
+               else
+                       pDCB->CtrlR4 |= NS_TO_GLITCH(0);
+               if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
+               if (wval1 >= 8)
                {
-                   wval1--;
-                   bval = FAST_CLK;        /* ;fast clock/normal scsi */
-                   pDCB->CtrlR4 |= EATER_25NS;   /* ;25 ns glitch eater */
+                   wval1--;    /* Timing computation differs by 1 from FAST_SCSI */
+                   bval = FAST_CLK;            /* fast clock / normal scsi */
+                   pDCB->CtrlR4 |= pACB->glitch_cfg;   /* glitch eater */
                }
                pDCB->CtrlR3 = bval;
                pDCB->SyncPeriod = (UCHAR)wval1;
 re_prog:
-               bval = pDCB->SyncPeriod;
-               outb(bval, ioport+Sync_Period);
-               bval = pDCB->SyncOffset;
-               outb(bval, ioport+Sync_Offset);
-               bval = pDCB->CtrlR3;
-               outb(bval, ioport+CtrlReg3);
-               bval = pDCB->CtrlR4;
-               outb(bval, ioport+CtrlReg4);
-               SetXferRate( pACB, pDCB);
+               DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+               DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+               DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+               DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+               dc390_SetXferRate (pACB, pDCB);
            }
        }
     }
 min6:
     *psstatus = SCSI_NOP0;
-    bval = MSG_ACCEPTED_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-static void
-DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
+void
+dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
 {
     PSGL   psgl;
-    UCHAR  bval;
-    USHORT ioport;
     ULONG  lval;
 
-
-    ioport = pACB->IOPortBase;
     if( pSRB->SGIndex < pSRB->SGcount )
     {
-       bval = DMA_IDLE_CMD | ioDir;   /* ;+EN_DMA_INT */
-       outb( bval, ioport+DMA_Cmd);
+       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
        if( !pSRB->SGToBeXferLen )
        {
            psgl = pSRB->pSegmentList;
-           pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+           pSRB->SGBusAddr = virt_to_bus( psgl->address );
            pSRB->SGToBeXferLen = (ULONG) psgl->length;
+           DEBUG1(printk (" DC390: Next SG segment.");)
        }
        lval = pSRB->SGToBeXferLen;
-       bval = (UCHAR) lval;
-       outb(bval,ioport+CtcReg_Low);
-       lval = lval >> 8;
-       bval = (UCHAR) lval;
-       outb(bval,ioport+CtcReg_Mid);
-       lval = lval >> 8;
-       bval = (UCHAR) lval;
-       outb(bval,ioport+CtcReg_High);
-
-       lval = pSRB->SGToBeXferLen;
-       outl(lval, ioport+DMA_XferCnt);
+       DEBUG1(printk (" DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
+       DC390_write8 (CtcReg_Low, (UCHAR) lval);
+       lval >>= 8;
+       DC390_write8 (CtcReg_Mid, (UCHAR) lval);
+       lval >>= 8;
+       DC390_write8 (CtcReg_High, (UCHAR) lval);
 
-       lval = pSRB->SGPhysAddr;
-       outl( lval, ioport+DMA_XferAddr);
-
-       bval = DMA_COMMAND+INFO_XFER_CMD;
-       outb(bval, ioport+ScsiCmd);
+       DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
+       DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
 
+       //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
        pSRB->SRBState = SRB_DATA_XFER;
 
-       bval = DMA_IDLE_CMD | ioDir;    /* ;+EN_DMA_INT */
-       outb(bval, ioport+DMA_Cmd);
+       DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
 
-       bval = DMA_START_CMD | ioDir;   /* ;+EN_DMA_INT */
-       outb(bval, ioport+DMA_Cmd);
+       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+       //DEBUG1(printk ("DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
     }
     else    /* xfer pad */
     {
+       UCHAR bval = 0;
        if( pSRB->SGcount )
        {
            pSRB->AdaptStatus = H_OVER_UNDER_RUN;
            pSRB->SRBStatus |= OVER_RUN;
+           DEBUG0(printk (" DC390: Overrun -");)
        }
-       bval = 0;
-       outb(bval,ioport+CtcReg_Low);
-       outb(bval,ioport+CtcReg_Mid);
-       outb(bval,ioport+CtcReg_High);
+       DEBUG0(printk (" Clear transfer pad \n");)
+       DC390_write8 (CtcReg_Low, bval);
+       DC390_write8 (CtcReg_Mid, bval);
+       DC390_write8 (CtcReg_High, bval);
 
        pSRB->SRBState |= SRB_XFERPAD;
-       bval = DMA_COMMAND+XFER_PAD_BYTE;
-       outb(bval, ioport+ScsiCmd);
+       DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
 /*
-       bval = DMA_IDLE_CMD | ioDir;    ;+EN_DMA_INT
-       outb(bval, ioport+DMA_Cmd);
-       bval = DMA_START_CMD | ioDir;   ;+EN_DMA_INT
-       outb(bval, ioport+DMA_Cmd);
+       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
+       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
 */
     }
 }
 
 
 static void
-DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  ioDir;
-
-    ioDir = WRITE_DIRECTION;
-    DataIO_Comm( pACB, pSRB, ioDir);
+    dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION);
 }
 
 static void
-DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  ioDir;
-
-    ioDir = READ_DIRECTION;
-    DataIO_Comm( pACB, pSRB, ioDir);
+    dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION);
 }
 
-static void
-DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     PDCB   pDCB;
-    UCHAR  bval;
+    UCHAR  i, cnt;
     PUCHAR ptr;
-    USHORT ioport, i,  cnt;
 
-
-    ioport = pACB->IOPortBase;
-    bval = RESET_ATN_CMD;
-    outb(bval, ioport+ScsiCmd);
-    bval = CLEAR_FIFO_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
     {
-       cnt = (USHORT) pSRB->ScsiCmdLen;
+       cnt = (UCHAR) pSRB->ScsiCmdLen;
        ptr = (PUCHAR) pSRB->CmdBlock;
        for(i=0; i < cnt; i++)
-       {
-           outb(*ptr, ioport+ScsiFifo);
-           ptr++;
-       }
+           DC390_write8 (ScsiFifo, *(ptr++));
     }
     else
     {
-       bval = REQUEST_SENSE;
-       outb(bval, ioport+ScsiFifo);
+       UCHAR bval = 0;
+       DC390_write8 (ScsiFifo, REQUEST_SENSE);
        pDCB = pACB->pActiveDCB;
-       bval = pDCB->IdentifyMsg << 5;
-       outb(bval, ioport+ScsiFifo);
-       bval = 0;
-       outb(bval, ioport+ScsiFifo);
-       outb(bval, ioport+ScsiFifo);
-       bval = sizeof(pSRB->pcmd->sense_buffer);
-       outb(bval, ioport+ScsiFifo);
-       bval = 0;
-       outb(bval, ioport+ScsiFifo);
+       DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
+       DC390_write8 (ScsiFifo, bval);
+       DC390_write8 (ScsiFifo, bval);
+       DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+       DC390_write8 (ScsiFifo, bval);
     }
     pSRB->SRBState = SRB_COMMAND;
-    bval = INFO_XFER_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
 }
 
 static void
-DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  bval;
-    USHORT ioport;
-
-    ioport = pACB->IOPortBase;
-    bval = CLEAR_FIFO_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     pSRB->SRBState = SRB_STATUS;
-    bval = INITIATOR_CMD_CMPLTE;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-static void
-DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR   bval;
-    USHORT  ioport, i, cnt;
+    UCHAR   bval, i, cnt;
     PUCHAR  ptr;
     PDCB    pDCB;
 
-    ioport = pACB->IOPortBase;
-    bval = CLEAR_FIFO_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     pDCB = pACB->pActiveDCB;
     if( !(pSRB->SRBState & SRB_MSGOUT) )
     {
@@ -785,10+843,7 @@ DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
        {
            ptr = (PUCHAR) pSRB->MsgOutBuf;
            for(i=0; i < cnt; i++)
-           {
-               outb(*ptr, ioport+ScsiFifo);
-               ptr++;
-           }
+               DC390_write8 (ScsiFifo, *(ptr++));
            pSRB->MsgCnt = 0;
            if( (pDCB->DCBFlag & ABORT_DEV_) &&
                (pSRB->MsgOutBuf[0] == MSG_ABORT) )
@@ -804,76+859,67 @@ DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
                if( pDCB->SyncMode & SYNC_ENABLE )
                    goto  mop1;
            }
-           outb(bval, ioport+ScsiFifo);
+           DC390_write8 (ScsiFifo, bval);
        }
-       bval = INFO_XFER_CMD;
-       outb( bval, ioport+ScsiCmd);
+       DC390_write8 (ScsiCmd, INFO_XFER_CMD);
     }
     else
     {
 mop1:
-       bval = MSG_EXTENDED;
-       outb(bval, ioport+ScsiFifo);
-       bval = 3;       /*    ;length of extended msg */
-       outb(bval, ioport+ScsiFifo);
-       bval = 1;       /*    ; sync nego */
-       outb(bval, ioport+ScsiFifo);
-       bval = pDCB->NegoPeriod;
-       outb(bval, ioport+ScsiFifo);
-       bval = SYNC_NEGO_OFFSET;
-       outb(bval, ioport+ScsiFifo);
+       //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+       DC390_write8 (ScsiFifo, MSG_EXTENDED);
+       DC390_write8 (ScsiFifo, 3);     /*    ;length of extended msg */
+       DC390_write8 (ScsiFifo, EXTENDED_SDTR); /*    ; sync nego */
+       DC390_write8 (ScsiFifo, pDCB->NegoPeriod);
+       if (pDCB->SyncOffset & 0x0f)
+                   DC390_write8 (ScsiFifo, pDCB->SyncOffset);
+       else
+                   DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET);              
        pSRB->SRBState |= DO_SYNC_NEGO;
-       bval = INFO_XFER_CMD;
-       outb(bval, ioport+ScsiCmd);
+       DC390_write8 (ScsiCmd, INFO_XFER_CMD);
     }
 }
 
 static void
-DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  bval;
-    USHORT ioport;
-
-    ioport = pACB->IOPortBase;
-    bval = CLEAR_FIFO_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     if( !(pSRB->SRBState & SRB_MSGIN) )
     {
-       pSRB->SRBState &= SRB_DISCONNECT;
+       pSRB->SRBState &= ~SRB_DISCONNECT;
        pSRB->SRBState |= SRB_MSGIN;
     }
-    bval = INFO_XFER_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
 static void
-DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
 }
 
 static void
-DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
 }
 
 
 static void
-SetXferRate( PACB pACB, PDCB pDCB )
+dc390_SetXferRate( PACB pACB, PDCB pDCB )
 {
-    UCHAR  bval;
-    USHORT cnt, i;
+    UCHAR  bval, i, cnt;
     PDCB   ptr;
 
     if( !(pDCB->IdentifyMsg & 0x07) )
     {
        if( pACB->scan_devices )
        {
-           CurrSyncOffset = pDCB->SyncOffset;
+           dc390_CurrSyncOffset = pDCB->SyncOffset;
        }
        else
        {
            ptr = pACB->pLinkDCB;
-           cnt = pACB->DeviceCnt;
+           cnt = pACB->DCBCnt;
            bval = pDCB->UnitSCSIID;
            for(i=0; i<cnt; i++)
            {
@@ -893,39+939,34 @@ SetXferRate( PACB pACB, PDCB pDCB )
 }
 
 
-static void
-DC390_Disconnect( PACB pACB )
+void
+dc390_Disconnect( PACB pACB )
 {
     PDCB   pDCB;
     PSRB   pSRB, psrb;
-    ULONG  flags;
-    USHORT ioport, i, cnt;
-    UCHAR  bval;
+    UCHAR  i, cnt;
 
-#ifdef DC390_DEBUG0
-    printk("DISC,");
-#endif
+    DEBUG0(printk(KERN_INFO "DISC,");)
 
-    save_flags(flags);
-    cli();
-    ioport = pACB->IOPortBase;
     pDCB = pACB->pActiveDCB;
     if (!pDCB)
      {
-#ifdef DC390_DEBUG0
-       printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB);
-#endif
-       restore_flags(flags); return;
+       int j = 400;
+       DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\
+              (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);)
+       while (--j) udelay (1000);
+       DC390_read8 (INT_Status);       /* Reset Pending INT */
+       DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+       return;
      }
     pSRB = pDCB->pActiveSRB;
     pACB->pActiveDCB = 0;
     pSRB->ScsiPhase = SCSI_NOP0;
-    bval = EN_SEL_RESEL;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, EN_SEL_RESEL);
     if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
     {
        pSRB->SRBState = 0;
-       DoWaitingSRB( pACB );
+       dc390_DoWaitingSRB( pACB );
     }
     else if( pSRB->SRBState & SRB_ABORT_SENT )
     {
@@ -942,7+983,7 @@ DC390_Disconnect( PACB pACB )
            pSRB = psrb;
        }
        pDCB->pGoingSRB = 0;
-       DoWaitingSRB( pACB );
+       dc390_DoWaitingSRB( pACB );
     }
     else
     {
@@ -952,7+993,7 @@ DC390_Disconnect( PACB pACB )
            if( !(pACB->scan_devices) )
            {
                pSRB->SRBState = SRB_READY;
-               RewaitSRB( pDCB, pSRB);
+               dc390_RewaitSRB( pDCB, pSRB);
            }
            else
            {
@@ -962,76+1003,66 @@ DC390_Disconnect( PACB pACB )
        }
        else if( pSRB->SRBState & SRB_DISCONNECT )
        {
-           DoWaitingSRB( pACB );
+           dc390_DoWaitingSRB( pACB );
        }
        else if( pSRB->SRBState & SRB_COMPLETED )
        {
 disc1:
            if(pDCB->MaxCommand > 1)
            {
-              bval = pSRB->TagNumber;
-              pDCB->TagMask &= (~(1 << bval));   /* free tag mask */
+              pDCB->TagMask &= (~(1 << pSRB->TagNumber));   /* free tag mask */
            }
            pDCB->pActiveSRB = 0;
            pSRB->SRBState = SRB_FREE;
-           SRBdone( pACB, pDCB, pSRB);
+           dc390_SRBdone( pACB, pDCB, pSRB);
        }
     }
-    restore_flags(flags);
     return;
 }
 
 
-static void
-DC390_Reselect( PACB pACB )
+void
+dc390_Reselect( PACB pACB )
 {
-    PDCB   pDCB, pdcb;
+    PDCB   pDCB;
     PSRB   pSRB;
-    USHORT ioport, wval;
-    UCHAR  bval, bval1;
-
+    USHORT wval;
+    UCHAR  bval;
 
-#ifdef DC390_DEBUG0
-    printk("RSEL,");
-#endif
-    ioport = pACB->IOPortBase;
+    DEBUG0(printk(KERN_INFO "RSEL,");)
     pDCB = pACB->pActiveDCB;
     if( pDCB )
     {  /* Arbitration lost but Reselection win */
+       DEBUG0(printk ("(ActiveDCB != 0)");)
        pSRB = pDCB->pActiveSRB;
        if( !( pACB->scan_devices ) )
        {
            pSRB->SRBState = SRB_READY;
-           RewaitSRB( pDCB, pSRB);
+           dc390_RewaitSRB( pDCB, pSRB);
        }
     }
-    bval = inb(ioport+ScsiFifo);       /* get ID */
-    bval = bval ^ pACB->HostID_Bit;
+    bval = DC390_read8 (ScsiFifo);     /* get ID */
+    DEBUG0(printk ("Dev %02x,", bval);)
+    bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
     wval = 0;
-    bval1 = 1;
-    for(;;)
-    {
-       if( !(bval & bval1) )
-       {
-           bval1 = bval1 << 1;
-           wval++;
-       }
-       else
-           break;
-    }
-    wval |=  ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8;  /* get LUN */
+    while (bval >>= 1) wval++;
+    wval |=  ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8;  /* get LUN */
+    DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);)
     pDCB = pACB->pLinkDCB;
-    pdcb = pDCB;
     while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
     {
        pDCB = pDCB->pNextDCB;
-       if( pDCB == pdcb )
+       if( pDCB == pACB->pLinkDCB )
+        {
+           printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n",
+                   wval & 0xff, (wval & 0xff00) >> 8);
            return;
+        }
     }
     pACB->pActiveDCB = pDCB;
-    if( pDCB->SyncMode & EN_TAG_QUEUING )
+    if( pDCB->SyncMode & EN_TAG_QUEUEING )
     {
-       pSRB = pACB->pTmpSRB;
+       pSRB = pACB->pTmpSRB; /* ?? */
        pDCB->pActiveSRB = pSRB;
     }
     else
@@ -1041,57+1072,163 @@ DC390_Reselect( PACB pACB )
        {
            pSRB= pACB->pTmpSRB;
            pSRB->SRBState = SRB_UNEXPECT_RESEL;
+           printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n",
+                   wval & 0xff, (wval & 0xff00) >> 8);
            pDCB->pActiveSRB = pSRB;
-           EnableMsgOut( pACB, pSRB );
+           dc390_EnableMsgOut( pACB, pSRB );
        }
        else
        {
            if( pDCB->DCBFlag & ABORT_DEV_ )
            {
                pSRB->SRBState = SRB_ABORT_SENT;
-               EnableMsgOut( pACB, pSRB );
+               printk (KERN_NOTICE "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
+                       wval & 0xff, (wval & 0xff00) >> 8);
+               dc390_EnableMsgOut( pACB, pSRB );
            }
            else
                pSRB->SRBState = SRB_DATA_XFER;
        }
     }
+
+    DEBUG1(printk ("Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
     pSRB->ScsiPhase = SCSI_NOP0;
-    bval = pDCB->UnitSCSIID;
-    outb( bval, ioport+Scsi_Dest_ID);
-    bval = pDCB->SyncPeriod;
-    outb(bval, ioport+Sync_Period);
-    bval = pDCB->SyncOffset;
-    outb( bval, ioport+Sync_Offset);
-    bval = pDCB->CtrlR1;
-    outb(bval, ioport+CtrlReg1);
-    bval = pDCB->CtrlR3;
-    outb(bval, ioport+CtrlReg3);
-    bval = pDCB->CtrlR4;       /* ; Glitch eater */
-    outb(bval, ioport+CtrlReg4);
-    bval = MSG_ACCEPTED_CMD;   /* ;to rls the /ACK signal */
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+    DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+    DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+    DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+    DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+    DC390_write8 (CtrlReg4, pDCB->CtrlR4);     /* ; Glitch eater */
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);  /* ;to release the /ACK signal */
 }
 
 
-static void
-SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
+static void 
+dc390_remove_dev (PACB pACB, PDCB pDCB)
+{
+   PDCB pPrevDCB = pACB->pLinkDCB;
+
+   pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN);
+   if (pDCB->GoingSRBCnt > 1)
+     {
+       DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\
+               pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);)
+       return;
+     };
+   
+   if (pDCB == pACB->pLinkDCB) 
+     {
+       if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0;
+       pACB->pLinkDCB = pDCB->pNextDCB;
+       pACB->pLastDCB->pNextDCB = pDCB->pNextDCB;
+     }
+   else
+     {
+       while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB;
+       pPrevDCB->pNextDCB = pDCB->pNextDCB;
+       if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB;
+     }
+
+   DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\
+          pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
+   kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0;
+   pACB->DCBCnt--;
+   /* pACB->DeviceCnt--; */
+};
+
+
+static UCHAR __inline__
+dc390_tagq_blacklist (char* name)
+{
+   UCHAR i;
+   for(i=0; i<BADDEVCNT; i++)
+     if (memcmp (name, dc390_baddevname1[i], 28) == 0)
+       return 1;
+   return 0;
+};
+   
+
+static void 
+dc390_disc_tagq_set (PDCB pDCB, PSCSI_INQDATA ptr)
+{
+   /* Check for SCSI format (ANSI and Response data format) */
+   if ( (ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 )
+   {
+       if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
+           (pDCB->DevMode & TAG_QUEUEING_) &&
+           /* ((pDCB->DevType == TYPE_DISK) 
+               || (pDCB->DevType == TYPE_MOD)) &&*/
+           !dc390_tagq_blacklist (((char*)ptr)+8) )
+         {
+            pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum;
+            pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */;
+            pDCB->TagMask = 0;
+         }
+       else
+         {
+            /* Do we really need to check for DevType here ? */
+            if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/
+                /* && ((pDCB->DevType == TYPE_DISK) 
+                    || (pDCB->DevType == TYPE_MOD))*/ )
+               pDCB->SyncMode |= EN_ATN_STOP;
+            else
+              //pDCB->SyncMode &= ~EN_ATN_STOP;
+              pDCB->SyncMode &= ~0;
+         }
+     }
+};
+
+
+static void 
+dc390_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr)
+{
+   UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE;
+   pDCB->DevType = bval1;
+   /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
+       dc390_disc_tagq_set (pDCB, ptr);
+};
+
+
+void
+dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
     PSRB   psrb;
-    UCHAR  bval, bval1, i, j, status;
+    UCHAR  bval, status, i;
     PSCSICMD pcmd;
     PSCSI_INQDATA  ptr;
-    USHORT disable_tag;
-    ULONG  flags;
     PSGL   ptr2;
     ULONG  swlval;
 
     pcmd = pSRB->pcmd;
     status = pSRB->TargetStatus;
+    DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
+               pSRB, pcmd->pid);)
     if(pSRB->SRBFlag & AUTO_REQSENSE)
-    {
+    {  /* Last command was a Request Sense */
        pSRB->SRBFlag &= ~AUTO_REQSENSE;
        pSRB->AdaptStatus = 0;
        pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+#ifdef DC390_REMOVABLEDEBUG
+       switch (pcmd->sense_buffer[2] & 0x0f)
+       {           
+        case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+                                pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+                                status, pACB->scan_devices); break;
+        case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+                                     pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+                                     status, pACB->scan_devices); break;
+        case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+                                      pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+                                      status, pACB->scan_devices); break;
+        case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+                                   pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+                                   status, pACB->scan_devices); break;
+        case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+                                     pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+                                     status, pACB->scan_devices); break;
+       }
+#endif
+       //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status;
        if(status == SCSI_STAT_CHECKCOND)
        {
            pcmd->result = DID_BAD_TARGET << 16;
@@ -1099,7+1236,7 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
        }
        if(pSRB->RetryCnt == 0)
        {
-           *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+           (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0];
            pSRB->TotalXferredLen = pSRB->Segment1[1];
            if( (pSRB->TotalXferredLen) &&
                (pSRB->TotalXferredLen >= pcmd->underflow) )
@@ -1107,28+1244,29 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
            else
                pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
                                SCSI_STAT_CHECKCOND;
-#ifdef DC390_DEBUG0
-       printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0],
-               (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
-#endif
+           REMOVABLEDEBUG(printk("Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
+               (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
            goto ckc_e;
        }
-       else
+       else /* Retry */
        {
            pSRB->RetryCnt--;
            pSRB->AdaptStatus = 0;
            pSRB->TargetStatus = 0;
            *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
            *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
-           if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+           /* Don't retry on TEST_UNIT_READY */
+           if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */)
            {
-               pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
-                               SCSI_STAT_CHECKCOND;
+               pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) 
+                           | SCSI_STAT_CHECKCOND;
+               REMOVABLEDEBUG(printk("Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
+                      (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
                goto ckc_e;
            }
            pcmd->result |= (DRIVER_SENSE << 24);
-           pSRB->SGcount                = (UCHAR) pSRB->Segment1[0];
-           pSRB->ScsiCmdLen             = (UCHAR) (pSRB->Segment1[0] >> 8);
+           pSRB->SGcount        = (UCHAR) pSRB->Segment1[0];
+           pSRB->ScsiCmdLen     = (UCHAR) (pSRB->Segment1[0] >> 8);
            pSRB->SGIndex = 0;
            pSRB->TotalXferredLen = 0;
            pSRB->SGToBeXferLen = 0;
@@ -1140,8+1278,8 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
                pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
                pSRB->Segmentx.length = pcmd->request_bufflen;
            }
-           if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
-               RewaitSRB( pDCB, pSRB );
+           if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+               dc390_RewaitSRB( pDCB, pSRB );
            return;
        }
     }
@@ -1149,6+1287,8 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
     {
        if( status == SCSI_STAT_CHECKCOND)
        {
+           REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\
+                   pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
            if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
            {
                bval = pSRB->SGcount;
@@ -1159,12+1299,10 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
                    swlval += ptr2->length;
                    ptr2++;
                }
-#ifdef DC390_DEBUG0
-               printk("XferredLen=%8x,NotXferLen=%8x,",
-                       (UINT) pSRB->TotalXferredLen, (UINT) swlval);
-#endif
+               REMOVABLEDEBUG(printk("XferredLen=%08x,NotXferLen=%08x\n",\
+                       (UINT) pSRB->TotalXferredLen, (UINT) swlval);)
            }
-           RequestSense( pACB, pDCB, pSRB );
+           dc390_RequestSense( pACB, pDCB, pSRB );
            return;
        }
        else if( status == SCSI_STAT_QUEUEFULL )
@@ -1172,7+1310,7 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
            bval = (UCHAR) pDCB->GoingSRBCnt;
            bval--;
            pDCB->MaxCommand = bval;
-           RewaitSRB( pDCB, pSRB );
+           dc390_RewaitSRB( pDCB, pSRB );
            pSRB->AdaptStatus = 0;
            pSRB->TargetStatus = 0;
            return;
@@ -1182,12+1320,22 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
            pSRB->AdaptStatus = H_SEL_TIMEOUT;
            pSRB->TargetStatus = 0;
            pcmd->result = DID_BAD_TARGET << 16;
+           /* Devices are removed below ... */
        }
-       else
+       else if (status == SCSI_STAT_BUSY && 
+                (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) &&
+                pACB->scan_devices)
        {
            pSRB->AdaptStatus = 0;
+           pSRB->TargetStatus = status;
+           pcmd->result = (ULONG) (pSRB->EndMessage << 8)
+                               /* | (ULONG) status */;
+       }
+       else
+       {   /* Another error */
+           pSRB->AdaptStatus = 0;
            if( pSRB->RetryCnt )
-           {
+           {   /* Retry */
                pSRB->RetryCnt--;
                pSRB->TargetStatus = 0;
                pSRB->SGIndex = 0;
@@ -1201,19+1349,19 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
                    pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
                    pSRB->Segmentx.length = pcmd->request_bufflen;
                }
-               if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
-                   RewaitSRB( pDCB, pSRB );
+               if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+                   dc390_RewaitSRB( pDCB, pSRB );
                return;
            }
            else
-           {
+           {   /* Report error */
                pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
                               (ULONG) status;
            }
        }
     }
     else
-    {
+    {  /*  Target status == 0 */
        status = pSRB->AdaptStatus;
        if(status & H_OVER_UNDER_RUN)
        {
@@ -1237,95+1385,57 @@ ckc_e:
     {
        if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
        {
-           if(pcmd->result != (DID_OK << 16))
-           {
-               if( pcmd->result & SCSI_STAT_CHECKCOND )
-               {
-                   goto RTN_OK;
-               }
-               else
-               {
-                   pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
-                   pPrevDCB->pNextDCB = pACB->pLinkDCB;
-                   if( (pcmd->target == pACB->max_id) &&
-                      ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) )
-                   {
-                       pACB->scan_devices = 0;
-                   }
-               }
-           }
-           else
-           {
-RTN_OK:
-               pPrevDCB->pNextDCB = pDCB;
-               pDCB->pNextDCB = pACB->pLinkDCB;
-               if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) )
-                   pACB->scan_devices = END_SCAN;
-           }
-       }
-       else if( pSRB->CmdBlock[0] == INQUIRY )
-       {
-           if( (pcmd->target == pACB->max_id) &&
-               (pcmd->lun == pACB->max_lun) )
-           {
-               pACB->scan_devices = 0;
-           }
-           ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
-           if( pcmd->use_sg )
-               ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
-           bval1 = ptr->DevType & SCSI_DEVTYPE;
-           if(bval1 == SCSI_NODEV)
+#ifdef DC390_DEBUG0
+           printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result);
+           if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n",
+                                  pcmd->sense_buffer[0], pcmd->sense_buffer[1],
+                                  pcmd->sense_buffer[2], pcmd->sense_buffer[3]);
+           else printk ("\n");
+#endif
+           if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) ||
+              ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
+               (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16)
            {
-               pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
-               pPrevDCB->pNextDCB = pACB->pLinkDCB;
+              /* device not present: remove */ 
+              dc390_remove_dev (pACB, pDCB);
+              
+              if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
+                 ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) )
+                pACB->scan_devices = 0;
            }
            else
            {
-               pACB->DeviceCnt++;
-               pPrevDCB = pDCB;
-               pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB ));
-               pDCB->DevType = bval1;
-               if(bval1 == TYPE_DISK || bval1 == TYPE_MOD)
-               {
-                   if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) &&
-                       (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
-                       (pDCB->DevMode & TAG_QUEUING_) &&
-                       (pDCB->DevMode & EN_DISCONNECT_) )
-                   {
-                       disable_tag = 0;
-                       for(i=0; i<BADDEVCNT; i++)
-                       {
-                           for(j=0; j<28; j++)
-                           {
-                               if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j])
-                                   break;
-                           }
-                           if(j == 28)
-                           {
-                               disable_tag = 1;
-                               break;
-                           }
-                       }
-
-                       if( !disable_tag )
-                       {
-                           pDCB->MaxCommand = pACB->TagMaxNum;
-                           pDCB->SyncMode |= EN_TAG_QUEUING;
-                           pDCB->TagMask = 0;
-                       }
-                       else
-                       {
-                           pDCB->SyncMode |= EN_ATN_STOP;
-                       }
-                   }
-               }
+               /* device present: add */
+               if( (pcmd->target == pACB->pScsiHost->max_id - 1) && 
+                   (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
+                   pACB->scan_devices = END_SCAN ;
+               /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */
            }
        }
     }
-
-    save_flags( flags );
-    cli();
-/*  ReleaseSRB( pDCB, pSRB ); */
+   
+   if( pSRB->CmdBlock[0] == INQUIRY && 
+      (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) )
+     {
+       ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+       if( pcmd->use_sg )
+         ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+       if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV)
+         {
+            /* device not present: remove */
+            dc390_remove_dev (pACB, pDCB);
+         }
+       else
+         {
+            /* device found: add */ 
+            dc390_add_dev (pACB, pDCB, ptr);
+            if (pACB->scan_devices) pACB->DeviceCnt++;
+         }
+       if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
+           (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
+         pACB->scan_devices = 0;
+     };
+/*  dc390_ReleaseSRB( pDCB, pSRB ); */
 
     if(pSRB == pDCB->pGoingSRB )
     {
@@ -1344,33+1454,34 @@ RTN_OK:
     pACB->pFreeSRB = pSRB;
     pDCB->GoingSRBCnt--;
 
-    DoWaitingSRB( pACB );
-    restore_flags(flags);
+    dc390_DoWaitingSRB( pACB );
 
-/*  Notify cmd done */
+    DC390_UNLOCK_ACB_NI;
     pcmd->scsi_done( pcmd );
+    DC390_LOCK_ACB_NI;
 
     if( pDCB->QIORBCnt )
-       DoNextCmd( pACB, pDCB );
+       dc390_DoNextCmd( pACB, pDCB );
     return;
 }
 
 
-static void
-DoingSRB_Done( PACB pACB )
+/* Remove all SRBs and tell midlevel code DID_RESET */
+void
+dc390_DoingSRB_Done( PACB pACB )
 {
-    PDCB  pDCB, pdcb;
-    PSRB  psrb, psrb2;
-    USHORT  cnt, i;
+    PDCB   pDCB, pdcb;
+    PSRB   psrb, psrb2;
+    UCHAR  i;
     PSCSICMD pcmd;
 
     pDCB = pACB->pLinkDCB;
     pdcb = pDCB;
+    if (! pdcb) return;
     do
     {
-       cnt = pdcb->GoingSRBCnt;
        psrb = pdcb->pGoingSRB;
-       for( i=0; i<cnt; i++)
+       for( i=0; i<pdcb->GoingSRBCnt; i++)
        {
            psrb2 = psrb->pNextSRB;
            pcmd = psrb->pcmd;
@@ -1381,63+1492,46 @@ DoingSRB_Done( PACB pACB )
            psrb->pNextSRB = pACB->pFreeSRB;
            pACB->pFreeSRB = psrb;
 
+           DC390_UNLOCK_ACB_NI;
            pcmd->scsi_done( pcmd );
+           DC390_LOCK_ACB_NI;
            psrb  = psrb2;
        }
        pdcb->GoingSRBCnt = 0;;
        pdcb->pGoingSRB = NULL;
        pdcb->TagMask = 0;
        pdcb = pdcb->pNextDCB;
-    }
-    while( pdcb != pDCB );
+    } while( pdcb != pDCB );
 }
 
 
 static void
-DC390_ResetSCSIBus( PACB pACB )
+dc390_ResetSCSIBus( PACB pACB )
 {
-    USHORT ioport;
-    UCHAR  bval;
-    ULONG  flags;
-
-    save_flags(flags);
-    cli();
     pACB->ACBFlag |= RESET_DEV;
-    ioport = pACB->IOPortBase;
 
-    bval = DMA_IDLE_CMD;
-    outb(bval,ioport+DMA_Cmd);
+    DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+    udelay (250);
+    DC390_write8 (ScsiCmd, NOP_CMD);
 
-    bval = RST_SCSI_BUS_CMD;
-    outb(bval,ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD);
 
-    restore_flags(flags);
     return;
 }
 
-
 static void
-DC390_ScsiRstDetect( PACB pACB )
+dc390_ScsiRstDetect( PACB pACB )
 {
-    ULONG wlval, flags;
-    USHORT ioport;
-    UCHAR  bval;
-
-#ifdef DC390_DEBUG0
-    printk("RST_DETEC");
-#endif
+    printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus);
+    //DEBUG0(printk(KERN_INFO "RST_DETECT,");)
 
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    /* Unlock before ? */
     /* delay a second */
-    mdelay(1000);
-
-    save_flags(flags);
-    cli();
-
-    ioport = pACB->IOPortBase;
-    bval = DMA_IDLE_CMD;
-    outb(bval,ioport+DMA_Cmd);
-    bval = CLEAR_FIFO_CMD;
-    outb(bval,ioport+ScsiCmd);
+    { unsigned int msec = 1*1000; while (--msec) udelay(1000); }
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
 
     if( pACB->ACBFlag & RESET_DEV )
        pACB->ACBFlag |= RESET_DONE;
@@ -1445,30+1539,32 @@ DC390_ScsiRstDetect( PACB pACB )
     {
        pACB->ACBFlag |= RESET_DETECT;
 
-       ResetDevParam( pACB );
-/*     DoingSRB_Done( pACB ); ???? */
-       RecoverSRB( pACB );
+       dc390_ResetDevParam( pACB );
+/*     dc390_DoingSRB_Done( pACB ); ???? */
+       dc390_RecoverSRB( pACB );
        pACB->pActiveDCB = NULL;
        pACB->ACBFlag = 0;
-       DoWaitingSRB( pACB );
+       dc390_DoWaitingSRB( pACB );
     }
-    restore_flags(flags);
     return;
 }
 
 
-static void
-RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+static void __inline__
+dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
     PSCSICMD  pcmd;
 
+    REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\
+           pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+
     pSRB->SRBFlag |= AUTO_REQSENSE;
-    pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
-    pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
+    pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0];
+    pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4];
     pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
     pSRB->Segment1[1] = pSRB->TotalXferredLen;
     pSRB->AdaptStatus = 0;
-    pSRB->TargetStatus = 0;
+    pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */
 
     pcmd = pSRB->pcmd;
 
@@ -1478,52+1574,40 @@ RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
     pSRB->SGcount = 1;
     pSRB->SGIndex = 0;
 
-    *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
+    pSRB->CmdBlock[0] = REQUEST_SENSE;
     pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
-    *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
+    (USHORT) pSRB->CmdBlock[2] = 0;
+    (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer);
     pSRB->ScsiCmdLen = 6;
 
     pSRB->TotalXferredLen = 0;
     pSRB->SGToBeXferLen = 0;
-    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
-       RewaitSRB( pDCB, pSRB );
+    if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+       dc390_RewaitSRB( pDCB, pSRB );
 }
 
 
-static void
-EnableMsgOut2( PACB pACB, PSRB pSRB )
+static void __inline__
+dc390_EnableMsgOut2( PACB pACB, PSRB pSRB )
 {
-    USHORT ioport;
-    UCHAR  bval;
-
-    ioport = pACB->IOPortBase;
     pSRB->MsgCnt = 1;
-    bval = SET_ATN_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, SET_ATN_CMD);
 }
 
 
-static void
-EnableMsgOut( PACB pACB, PSRB pSRB )
+static void __inline__
+dc390_EnableMsgOut( PACB pACB, PSRB pSRB )
 {
     pSRB->MsgOutBuf[0] = MSG_ABORT;
-    EnableMsgOut2( pACB, pSRB );
+    dc390_EnableMsgOut2( pACB, pSRB );
+    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
 }
 
 
-static void
-DC390_InvalidCmd( PACB pACB )
+static void __inline__
+dc390_InvalidCmd( PACB pACB )
 {
-   UCHAR bval;
-   USHORT ioport;
-   PSRB   pSRB;
-
-    pSRB = pACB->pActiveDCB->pActiveSRB;
-    if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
-    {
-       ioport = pACB->IOPortBase;
-       bval = CLEAR_FIFO_CMD;
-       outb(bval,(ioport+ScsiCmd));
-    }
+    if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
+       DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
 }
 
index c1f89dc..cafd928 100644 (file)
  *                  Bus Master Host Adapter                           *
  * (C)Copyright 1995-1996 Tekram Technology Co., Ltd.                 *
  ***********************************************************************/
-/*     Minor enhancements and bugfixes by                              *
+/* $Id: tmscsim.c,v 2.4 1998/10/24 08:50:47 garloff Exp $              */
+/*     Enhancements and bugfixes by                                    *
  *     Kurt Garloff <K.Garloff@ping.de>                                *
  ***********************************************************************/
 /*     HISTORY:                                                        *
  *                                                                     *
  *     REV#    DATE    NAME    DESCRIPTION                             *
- *     1.00  04/24/96  CLH     First release                           *
- *     1.01  06/12/96  CLH     Fixed bug of Media Change for Removable *
+ *     1.00  96/04/24  CLH     First release                           *
+ *     1.01  96/06/12  CLH     Fixed bug of Media Change for Removable *
  *                             Device, scan all LUN. Support Pre2.0.10 *
- *     1.02  06/18/96  CLH     Fixed bug of Command timeout ...        *
- *     1.03  09/25/96  KG      Added tmscsim_proc_info()               *
- *     1.04  10/11/96  CLH     Updating for support KV 2.0.x           *
- *     1.05  10/18/96  KG      Fixed bug in DC390_abort(null ptr deref)*
- *     1.06  10/25/96  KG      Fixed module support                    *
- *     1.07  11/09/96  KG      Fixed tmscsim_proc_info()               *
- *     1.08  11/18/96  KG      Fixed null ptr in DC390_Disconnect()    *
- *     1.09  11/30/96  KG      Added register the allocated IO space   *
- *     1.10  12/05/96  CLH     Modified tmscsim_proc_info(), and reset *
+ *     1.02  96/06/18  CLH     Fixed bug of Command timeout ...        *
+ *     1.03  96/09/25  KG      Added tmscsim_proc_info()               *
+ *     1.04  96/10/11  CLH     Updating for support KV 2.0.x           *
+ *     1.05  96/10/18  KG      Fixed bug in DC390_abort(null ptr deref)*
+ *     1.06  96/10/25  KG      Fixed module support                    *
+ *     1.07  96/11/09  KG      Fixed tmscsim_proc_info()               *
+ *     1.08  96/11/18  KG      Fixed null ptr in DC390_Disconnect()    *
+ *     1.09  96/11/30  KG      Added register the allocated IO space   *
+ *     1.10  96/12/05  CLH     Modified tmscsim_proc_info(), and reset *
  *                             pending interrupt in DC390_detect()     *
- *     1.11  02/05/97  KG/CLH  Fixeds problem with partitions greater  *
- *                             than 1GB                                *
- *      1.12  15/02/98  MJ      Rewritten PCI probing                  *
+ *     1.11  97/02/05  KG/CLH  Fixeds problem with partitions greater  *
+ *                             than 1GB                                *
+ *     1.12  98/02/15  MJ      Rewritten PCI probing                   *
+ *     1.13  98/04/08  KG      Support for non DC390, __initfunc decls,*
+ *                             changed max devs from 10 to 16          *
+ *     1.14a 98/05/05  KG      Dynamic DCB allocation, add-single-dev  *
+ *                             for LUNs if LUN_SCAN (BIOS) not set     *
+ *                             runtime config using /proc interface    *
+ *     1.14b 98/05/06  KG      eliminated cli (); sti (); spinlocks    *
+ *     1.14c 98/05/07  KG      2.0.x compatibility                     *
+ *     1.20a 98/05/07  KG      changed names of funcs to be consistent *
+ *                             DC390_ (entry points), dc390_ (internal)*
+ *                             reworked locking                        *
+ *     1.20b 98/05/12  KG      bugs: version, kfree, _ctmp             *
+ *                             debug output                            *
+ *     1.20c 98/05/12  KG      bugs: kfree, parsing, EEpromDefaults    *
+ *     1.20d 98/05/14  KG      bugs: list linkage, clear flag after    *
+ *                             reset on startup, code cleanup          *
+ *     1.20e 98/05/15  KG      spinlock comments, name space cleanup   *
+ *                             pLastDCB now part of ACB structure      *
+ *                             added stats, timeout for 2.1, TagQ bug  *
+ *                             RESET and INQUIRY interface commands    *
+ *     1.20f 98/05/18  KG      spinlocks fixes, max_lun fix, free DCBs *
+ *                             for missing LUNs, pending int           *
+ *     1.20g 98/05/19  KG      Clean up: Avoid short                   *
+ *     1.20h 98/05/21  KG      Remove AdaptSCSIID, max_lun ...         *
+ *     1.20i 98/05/21  KG      Aiiie: Bug with TagQMask                *
+ *     1.20j 98/05/24  KG      Handle STAT_BUSY, handle pACB->pLinkDCB *
+ *                             == 0 in remove_dev and DoingSRB_Done    *
+ *     1.20k 98/05/25  KG      DMA_INT (experimental)                  *
+ *     1.20l 98/05/27  KG      remove DMA_INT; DMA_IDLE cmds added;    *
+ *     1.20m 98/06/10  KG      glitch configurable; made some global   *
+ *                             vars part of ACB; use DC390_readX       *
+ *     1.20n 98/06/11  KG      startup params                          *
+ *     1.20o 98/06/15  KG      added TagMaxNum to boot/module params   *
+ *                             Device Nr -> Idx, TagMaxNum power of 2  *
+ *     1.20p 98/06/17  KG      Docu updates. Reset depends on settings *
+ *                             pci_set_master added; 2.0.xx: pcibios_* *
+ *                             used instead of MechNum things ...      *
+ *     1.20q 98/06/23  KG      Changed defaults. Added debug code for  *
+ *                             removable media and fixed it. TagMaxNum *
+ *                             fixed for DC390. Locking: ACB, DRV for  *
+ *                             better IRQ sharing. Spelling: Queueing  *
+ *                             Parsing and glitch_cfg changes. Display *
+ *                             real SyncSpeed value. Made DisConn      *
+ *                             functional (!)                          *
+ *     1.20r 98/06/30  KG      Debug macros, allow disabling DsCn, set *
+ *                             BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module *
+ *                             param -1 fixed.                         *
+ *     1.20s 98/08/20  KG      Debug info on abort(), try to check PCI,*
+ *                             phys_to_bus instead of phys_to_virt,    *
+ *                             fixed sel. process, fixed locking,      *
+ *                             added MODULE_XXX infos, changed IRQ     *
+ *                             request flags, disable DMA_INT          *
+ *     1.20t 98/09/07  KG      TagQ report fixed; Write Erase DMA Stat;*
+ *                             initfunc -> __init; better abort;       *
+ *                             Timeout for XFER_DONE & BLAST_COMPLETE; *
+ *                             Allow up to 33 commands being processed *
+ *     2.0a  98/10/14  KG      Max Cmnds back to 17. DMA_Stat clearing *
+ *                             all flags. Clear within while() loops   *
+ *                             in DataIn_0/Out_0. Null ptr in dumpinfo *
+ *                             for pSRB==0. Better locking during init.*
+ *                             bios_param() now respects part. table.  *
+ *     2.0b  98/10/24  KG      Docu fixes. Timeout Msg in DMA Blast.   *
+ *                             Disallow illegal idx in INQUIRY/REMOVE  *
  ***********************************************************************/
 
+/* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
+#define DC390_IRQ SA_SHIRQ /* | SA_INTERRUPT */
 
-#define DC390_DEBUG
+/* DEBUG options */
+//#define DC390_DEBUG0
+//#define DC390_DEBUG1
+//#define DC390_DCBDEBUG
+//#define DC390_PARSEDEBUG
+//#define DC390_REMOVABLEDEBUG
 
-#define SCSI_MALLOC
+/* Debug definitions */
+#ifdef DC390_DEBUG0
+# define DEBUG0(x) x;
+#else
+# define DEBUG0(x)
+#endif
+#ifdef DC390_DEBUG1
+# define DEBUG1(x) x;
+#else
+# define DEBUG1(x)
+#endif
+#ifdef DC390_DCBDEBUG
+# define DCBDEBUG(x) x;
+#else
+# define DCBDEBUG(x)
+#endif
+#ifdef DC390_PARSEDEBUG
+# define PARSEDEBUG(x) x;
+#else
+# define PARSEDEBUG(x)
+#endif
+#ifdef DC390_REMOVABLEDEBUG
+# define REMOVABLEDEBUG(x) x;
+#else
+# define REMOVABLEDEBUG(x)
+#endif
+#define DCBDEBUG1(x)
 
+/* Includes */
 #ifdef MODULE
 # include <linux/module.h>
 #endif
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/mm.h>
 #include <linux/config.h>
-#include <linux/init.h>
+#include <linux/version.h>
 #include <linux/blk.h>
 
 #include "scsi.h"
 #include "hosts.h"
-#include "tmscsim.h"
 #include "constants.h"
 #include "sd.h"
 #include <linux/stat.h>
 
 #define PCI_DEVICE_ID_AMD53C974        PCI_DEVICE_ID_AMD_SCSI
 
-struct proc_dir_entry  proc_scsi_tmscsim ={
-       PROC_SCSI_DC390T, 7 ,"tmscsim",
-       S_IFDIR | S_IRUGO | S_IXUGO, 2
-       };
+/* Locking */
+
+/* Note: Starting from 2.1.9x, the mid-level scsi code issues a 
+ * spinlock_irqsave (&io_request_lock) before calling the driver's 
+ * routines, so we don't need to lock.
+ * TODO: Verify, if we are locked in every case!
+ * The policy 3, let the midlevel scsi code do the io_request_locks
+ * and us locking on a driver specific lock, shouldn't hurt anybody; it
+ * just causes a minor performance degradation for setting the locks.
+ */
+
+/* spinlock things
+ * level 3: lock on both adapter specific locks and (global) io_request_lock
+ * level 2: lock on adapter specific locks only
+ * level 1: rely on the locking of the mid level code (io_request_lock)
+ * undef  : traditional save_flags; cli; restore_flags;
+ */
 
-static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-
-static void SetXferRate( PACB pACB, PDCB pDCB );
-static void DC390_Disconnect( PACB pACB );
-static void DC390_Reselect( PACB pACB );
-static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void DoingSRB_Done( PACB pACB );
-static void DC390_ScsiRstDetect( PACB pACB );
-static void DC390_ResetSCSIBus( PACB pACB );
-static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void EnableMsgOut2( PACB pACB, PSRB pSRB );
-static void EnableMsgOut( PACB pACB, PSRB pSRB );
-static void DC390_InvalidCmd( PACB pACB );
-
-int    DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
-void   DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
+//#define DEBUG_SPINLOCKS 2    /* Set to 0, 1 or 2 in include/asm/spinlock.h */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+# include <linux/init.h>
+# include <asm/spinlock.h>
+#endif
+
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) 
+# define USE_SPINLOCKS 1
+# define NEW_PCI 1
+#else
+# undef NEW_PCI
+# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+#  define USE_SPINLOCKS 2
+# endif
+#endif
+
+#ifdef USE_SPINLOCKS
+
+# if USE_SPINLOCKS == 3 /* both */
+
+#  if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+#   define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+#  else
+#   define DC390_LOCK_INIT
+#  endif
+   spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+
+#  define DC390_AFLAGS unsigned long aflags;
+#  define DC390_IFLAGS unsigned long iflags;
+#  define DC390_DFLAGS unsigned long dflags; 
+
+#  define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
+#  define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+
+#  define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+#  define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+#  define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+#  define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+
+#  define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags)
+#  define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
+#  define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
+#  define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
+//#  define DC390_LOCK_INIT spin_lock_init (&(pACB->lock))
+
+# else
+
+#  if USE_SPINLOCKS == 2 /* adapter specific locks */
+
+#   if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+#    define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+#   else
+#    define DC390_LOCK_INIT
+#   endif
+    spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+#   define DC390_AFLAGS unsigned long aflags;
+#   define DC390_IFLAGS 
+#  define DC390_DFLAGS unsigned long dflags; 
+#   define DC390_LOCK_IO /* spin_lock_irqsave (&io_request_lock, iflags) */
+#   define DC390_UNLOCK_IO /* spin_unlock_irqrestore (&io_request_lock, iflags) */
+#   define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+#   define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+#   define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+#   define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+#   define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags)
+#   define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
+#   define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
+#   define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
+//#   define DC390_LOCK_INIT spin_lock_init (&(pACB->lock))
+
+#  else /* USE_SPINLOCKS == 1: global lock io_request_lock */
+
+#   define DC390_AFLAGS 
+#   define DC390_IFLAGS unsigned long iflags;
+#   define DC390_DFLAGS unsigned long dflags; 
+    spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+#   define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
+#   define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+#   define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+#   define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+#   define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+#   define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+#   define DC390_LOCK_ACB /* DC390_LOCK_IO */
+#   define DC390_UNLOCK_ACB /* DC390_UNLOCK_IO */
+#   define DC390_LOCK_ACB_NI /* spin_lock (&(pACB->lock)) */
+#   define DC390_UNLOCK_ACB_NI /* spin_unlock (&(pACB->lock)) */
+#   define DC390_LOCK_INIT /* DC390_LOCK_INIT */
+
+#  endif /* 2 */
+# endif /* 3 */
+
+#else /* USE_SPINLOCKS undefined */
+
+# define DC390_AFLAGS unsigned long aflags;
+# define DC390_IFLAGS unsigned long iflags;
+# define DC390_DFLAGS unsigned long dflags; 
+# define DC390_LOCK_IO save_flags (iflags); cli ()
+# define DC390_UNLOCK_IO restore_flags (iflags)
+# define DC390_LOCK_DRV save_flags (dflags); cli ()
+# define DC390_UNLOCK_DRV restore_flags (dflags)
+# define DC390_LOCK_DRV_NI
+# define DC390_UNLOCK_DRV_NI
+# define DC390_LOCK_ACB save_flags (aflags); cli ()
+# define DC390_UNLOCK_ACB restore_flags (aflags)
+# define DC390_LOCK_ACB_NI
+# define DC390_UNLOCK_ACB_NI
+# define DC390_LOCK_INIT
+#endif /* def */
+
+
+/* These macros are used for uniform access to 2.0.x and 2.1.x PCI config space*/
+
+#ifdef NEW_PCI
+# define PDEV pdev
+# define PDEVDECL struct pci_dev *pdev
+# define PDEVDECL0 struct pci_dev *pdev = NULL
+# define PDEVDECL1 struct pci_dev *pdev
+# define PDEVSET pACB->pdev=pdev
+# define PDEVSET1 pdev=pACB->pdev
+# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pci_write_config_byte (pd, rv, bv)
+# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pci_read_config_byte (pd, rv, bv)
+# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pci_write_config_word (pd, rv, bv)
+# define PCI_READ_CONFIG_WORD(pd, rv, bv) pci_read_config_word (pd, rv, bv)
+# define PCI_BUS_DEV pdev->bus->number, pdev->devfn
+# define PCI_PRESENT pci_present ()
+# define PCI_SET_MASTER pci_set_master (pdev)
+# define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev))
+# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq
+#else
+# include <linux/bios32.h>
+# define PDEV pbus, pdevfn
+# define PDEVDECL UCHAR pbus, UCHAR pdevfn
+# define PDEVDECL0 UCHAR pbus = 0; UCHAR pdevfn = 0; USHORT pci_index = 0; int error
+# define PDEVDECL1 UCHAR pbus; UCHAR pdevfn /*; USHORT pci_index */
+# define PDEVSET pACB->pbus=pbus; pACB->pdevfn=pdevfn /*; pACB->pci_index=pci_index */
+# define PDEVSET1 pbus=pACB->pbus; pdevfn=pACB->pdevfn /*; pci_index=pACB->pci_index */
+# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pcibios_write_config_byte (pd, rv, bv)
+# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pcibios_read_config_byte (pd, rv, bv)
+# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pcibios_write_config_word (pd, rv, bv)
+# define PCI_READ_CONFIG_WORD(pd, rv, bv) pcibios_read_config_word (pd, rv, bv)
+# define PCI_BUS_DEV pbus, pdevfn
+# define PCI_PRESENT pcibios_present ()
+# define PCI_SET_MASTER dc390_set_master (pbus, pdevfn)
+# define PCI_FIND_DEVICE(vend, id) (!pcibios_find_device (vend, id, pci_index++, &pbus, &pdevfn))
+# define PCI_GET_IO_AND_IRQ error = pcibios_read_config_dword (pbus, pdevfn, PCI_BASE_ADDRESS_0, &io_port);    \
+ error |= pcibios_read_config_byte (pbus, pdevfn, PCI_INTERRUPT_LINE, &irq);   \
+ io_port &= 0xfffe;    \
+ if (error) { printk (KERN_ERR "DC390_detect: Error reading PCI config registers!\n"); continue; }
+#endif 
+
+#include "tmscsim.h"
+
+#ifndef __init
+# define __init
+#endif
+
+UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+void dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+
+static void dc390_SetXferRate( PACB pACB, PDCB pDCB );
+void dc390_Disconnect( PACB pACB );
+void dc390_Reselect( PACB pACB );
+void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+void dc390_DoingSRB_Done( PACB pACB );
+static void dc390_ScsiRstDetect( PACB pACB );
+static void dc390_ResetSCSIBus( PACB pACB );
+static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void __inline__ dc390_EnableMsgOut2( PACB pACB, PSRB pSRB );
+static void __inline__ dc390_EnableMsgOut( PACB pACB, PSRB pSRB );
+static void __inline__ dc390_InvalidCmd( PACB pACB );
+static void dc390_remove_dev (PACB pACB, PDCB pDCB);
+void do_DC390_Interrupt( int, void *, struct pt_regs *);
+
+int    dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index );
+void   dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd );
+void   dc390_updateDCB (PACB pACB, PDCB pDCB);
 
 #ifdef MODULE
-static int DC390_release(struct Scsi_Host *host);
-static int DC390_shutdown (struct Scsi_Host *host);
+ static int DC390_release(struct Scsi_Host *host);
+ static int dc390_shutdown (struct Scsi_Host *host);
 #endif
 
 
-static PSHT    pSHT_start = NULL;
-static PSH     pSH_start = NULL;
-static PSH     pSH_current = NULL;
-static PACB    pACB_start= NULL;
-static PACB    pACB_current = NULL;
-static PDCB    pPrevDCB = NULL;
-static USHORT  adapterCnt = 0;
-static USHORT  InitialTime = 0;
-static USHORT  CurrSyncOffset = 0;
-
-static PVOID DC390_phase0[]={
-       DC390_DataOut_0,
-       DC390_DataIn_0,
-       DC390_Command_0,
-       DC390_Status_0,
-       DC390_Nop_0,
-       DC390_Nop_0,
-       DC390_MsgOut_0,
-       DC390_MsgIn_0,
-       DC390_Nop_1
-       };
+//static PSHT  dc390_pSHT_start = NULL;
+//static PSH   dc390_pSH_start = NULL;
+//static PSH   dc390_pSH_current = NULL;
+static PACB    dc390_pACB_start= NULL;
+static PACB    dc390_pACB_current = NULL;
+static UCHAR   dc390_adapterCnt = 0;
+static UCHAR   dc390_CurrSyncOffset = 0;
+static ULONG   dc390_lastabortedpid = 0;
+static ULONG   dc390_laststatus = 0;
+
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+/* Startup values, to be overriden on the commandline */
+int tmscsim[] = {7, 1 /* 8MHz */, 
+               PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_
+               | SYNC_NEGO_ | TAG_QUEUEING_,
+               MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION
+               /* | NO_SEEK */
+# ifdef CONFIG_SCSI_MULTI_LUN
+               | LUN_CHECK
+# endif
+               , 3 /* 16 Tags per LUN */};
+
+# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_PARM(tmscsim, "1-5i");
+MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)");
+# endif
+
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
+#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
+MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
+MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
+#endif
 
-static PVOID DC390_phase1[]={
-       DC390_DataOutPhase,
-       DC390_DataInPhase,
-       DC390_CommandPhase,
-       DC390_StatusPhase,
-       DC390_Nop_0,
-       DC390_Nop_0,
-       DC390_MsgOutPhase,
-       DC390_MsgInPhase,
-       DC390_Nop_1,
+static PVOID dc390_phase0[]={
+       dc390_DataOut_0,
+       dc390_DataIn_0,
+       dc390_Command_0,
+       dc390_Status_0,
+       dc390_Nop_0,
+       dc390_Nop_0,
+       dc390_MsgOut_0,
+       dc390_MsgIn_0,
+       dc390_Nop_1
        };
 
-UCHAR  eepromBuf[MAX_ADAPTER_NUM][128];
-
+static PVOID dc390_phase1[]={
+       dc390_DataOutPhase,
+       dc390_DataInPhase,
+       dc390_CommandPhase,
+       dc390_StatusPhase,
+       dc390_Nop_0,
+       dc390_Nop_0,
+       dc390_MsgOutPhase,
+       dc390_MsgInPhase,
+       dc390_Nop_1
+       };
 
-UCHAR  clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+#ifdef DC390_DEBUG1
+static char* dc390_p0_str[] = {
+       "dc390_DataOut_0",
+       "dc390_DataIn_0",
+       "dc390_Command_0",
+       "dc390_Status_0",
+       "dc390_Nop_0",
+       "dc390_Nop_0",
+       "dc390_MsgOut_0",
+       "dc390_MsgIn_0",
+       "dc390_Nop_1"
+       };
+     
+static char* dc390_p1_str[] = {
+       "dc390_DataOutPhase",
+       "dc390_DataInPhase",
+       "dc390_CommandPhase",
+       "dc390_StatusPhase",
+       "dc390_Nop_0",
+       "dc390_Nop_0",
+       "dc390_MsgOutPhase",
+       "dc390_MsgInPhase",
+       "dc390_Nop_1"
+       };
+#endif   
 
-UCHAR  baddevname1[2][28] ={
+/* Devices erroneously pretending to be able to do TagQ */
+UCHAR  dc390_baddevname1[2][28] ={
        "SEAGATE ST3390N         9546",
        "HP      C3323-300       4269"};
-
 #define BADDEVCNT      2
 
+static char*  dc390_adapname = "DC390";
+UCHAR  dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
+UCHAR  dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+
+struct proc_dir_entry  DC390_proc_scsi_tmscsim ={
+       PROC_SCSI_DC390T, 7 ,"tmscsim",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+       };
 
 /***********************************************************************
  *
  *
  *
  **********************************************************************/
-static void
-QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd)
+{
+   PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0;
+   while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun)
+     {
+       pDCB = pDCB->pNextDCB;
+       if (pDCB == pACB->pLinkDCB)
+         {
+            printk (KERN_ERR "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
+                    (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]);
+            return 0;
+         }
+     };
+   DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n",      \
+          (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+   return pDCB;
+};
+
+static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB )
 {
-    ULONG  flags;
     PSCSICMD  pcmd;
 
-    save_flags(flags);
-    cli();
-
     if( !pDCB->QIORBCnt )
     {
        pDCB->pQIORBhead = cmd;
@@ -185,83+524,61 @@ QLinkcmd( PSCSICMD cmd, PDCB pDCB )
        cmd->next = NULL;
     }
 
-    restore_flags(flags);
 }
 
 
-static PSCSICMD
-Getcmd( PDCB pDCB )
+static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB )
 {
-    ULONG  flags;
     PSCSICMD  pcmd;
 
-    save_flags(flags);
-    cli();
-
     pcmd = pDCB->pQIORBhead;
     pDCB->pQIORBhead = pcmd->next;
     pcmd->next = NULL;
     pDCB->QIORBCnt--;
 
-    restore_flags(flags);
     return( pcmd );
 }
 
 
-static PSRB
-GetSRB( PACB pACB )
+static __inline__ PSRB dc390_GetSRB( PACB pACB )
 {
-    ULONG  flags;
     PSRB   pSRB;
 
-    save_flags(flags);
-    cli();
-
     pSRB = pACB->pFreeSRB;
     if( pSRB )
     {
        pACB->pFreeSRB = pSRB->pNextSRB;
        pSRB->pNextSRB = NULL;
     }
-    restore_flags(flags);
+
     return( pSRB );
 }
 
 
-static void
-RewaitSRB0( PDCB pDCB, PSRB pSRB )
+static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB )
 {
     PSRB   psrb1;
-    ULONG  flags;
-
-    save_flags(flags);
-    cli();
 
     if( (psrb1 = pDCB->pWaitingSRB) )
     {
        pSRB->pNextSRB = psrb1;
-       pDCB->pWaitingSRB = pSRB;
     }
     else
     {
        pSRB->pNextSRB = NULL;
-       pDCB->pWaitingSRB = pSRB;
        pDCB->pWaitLast = pSRB;
     }
-    restore_flags(flags);
+    pDCB->pWaitingSRB = pSRB;
 }
 
 
-static void
-RewaitSRB( PDCB pDCB, PSRB pSRB )
+static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB )
 {
     PSRB   psrb1;
-    ULONG  flags;
     UCHAR  bval;
 
-    save_flags(flags);
-    cli();
-    pDCB->GoingSRBCnt--;
+    pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++;
+    DEBUG0(printk("DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
     psrb1 = pDCB->pGoingSRB;
     if( pSRB == psrb1 )
     {
@@ -289,20+606,14 @@ RewaitSRB( PDCB pDCB, PSRB pSRB )
 
     bval = pSRB->TagNumber;
     pDCB->TagMask &= (~(1 << bval));     /* Free TAG number */
-    restore_flags(flags);
 }
 
 
-static void
-DoWaitingSRB( PACB pACB )
+static void dc390_DoWaitingSRB( PACB pACB )
 {
-    ULONG  flags;
     PDCB   ptr, ptr1;
     PSRB   pSRB;
 
-    save_flags(flags);
-    cli();
-
     if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
     {
        ptr = pACB->pDCBRunRobin;
@@ -324,7+635,7 @@ DoWaitingSRB( PACB pACB )
            }
            else
            {
-               if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
+               if( !dc390_StartSCSI(pACB, ptr1, pSRB) )
                {
                    ptr1->GoingSRBCnt++;
                    if( ptr1->pWaitLast == pSRB )
@@ -348,55+659,47 @@ DoWaitingSRB( PACB pACB )
            }
        }
     }
-    restore_flags(flags);
     return;
 }
 
 
-static void
-SRBwaiting( PDCB pDCB, PSRB pSRB)
+static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB)
 {
     if( pDCB->pWaitingSRB )
     {
        pDCB->pWaitLast->pNextSRB = pSRB;
-       pDCB->pWaitLast = pSRB;
        pSRB->pNextSRB = NULL;
     }
     else
     {
        pDCB->pWaitingSRB = pSRB;
-       pDCB->pWaitLast = pSRB;
     }
+    pDCB->pWaitLast = pSRB;
 }
 
 
-static void
-SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
+static void dc390_SendSRB( PACB pACB, PSRB pSRB )
 {
-    ULONG  flags;
     PDCB   pDCB;
 
-    save_flags(flags);
-    cli();
-
     pDCB = pSRB->pSRBDCB;
     if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
        (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
     {
-       SRBwaiting(pDCB, pSRB);
+       dc390_SRBwaiting(pDCB, pSRB);
        goto SND_EXIT;
     }
 
     if( pDCB->pWaitingSRB )
     {
-       SRBwaiting(pDCB, pSRB);
-/*     pSRB = GetWaitingSRB(pDCB); */
+       dc390_SRBwaiting(pDCB, pSRB);
+/*     pSRB = GetWaitingSRB(pDCB); */  /* non-existent */
        pSRB = pDCB->pWaitingSRB;
        pDCB->pWaitingSRB = pSRB->pNextSRB;
        pSRB->pNextSRB = NULL;
     }
 
-    if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
+    if( !dc390_StartSCSI(pACB, pDCB, pSRB) )
     {
        pDCB->GoingSRBCnt++;
        if( pDCB->pGoingSRB )
@@ -411,13+714,52 @@ SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
        }
     }
     else
-       RewaitSRB0( pDCB, pSRB );
+       dc390_RewaitSRB0( pDCB, pSRB );
 
 SND_EXIT:
-    restore_flags(flags);
     return;
 }
 
+static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB)
+{
+    pSRB->pSRBDCB = pDCB;
+    pSRB->pcmd = pcmd;
+    pSRB->ScsiCmdLen = pcmd->cmd_len;
+    memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len);
+    
+    if( pcmd->use_sg )
+    {
+       pSRB->SGcount = (UCHAR) pcmd->use_sg;
+       pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+    }
+    else if( pcmd->request_buffer )
+    {
+       pSRB->SGcount = 1;
+       pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+       pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+       pSRB->Segmentx.length = pcmd->request_bufflen;
+    }
+    else
+       pSRB->SGcount = 0;
+
+    pSRB->SGIndex = 0;
+    pSRB->AdaptStatus = 0;
+    pSRB->TargetStatus = 0;
+    pSRB->MsgCnt = 0;
+    if( pDCB->DevType != TYPE_TAPE )
+       pSRB->RetryCnt = 1;
+    else
+       pSRB->RetryCnt = 0;
+    pSRB->SRBStatus = 0;
+    pSRB->SRBFlag = 0;
+    pSRB->SRBState = 0;
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGBusAddr = 0;
+    pSRB->SGToBeXferLen = 0;
+    pSRB->ScsiPhase = 0;
+    pSRB->EndMessage = 0;
+};
+
 
 /***********************************************************************
  * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
@@ -425,241+767,220 @@ SND_EXIT:
  *
  * Purpose : enqueues a SCSI command
  *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- *         a pointer to the command descriptor.
+ * Inputs : cmd - SCSI command, done - callback function called on 
+ *         completion, with a pointer to the command descriptor.
  *
- * Returns : 0
+ * Returns : (depending on kernel version)
+ * 2.0.x: always return 0
+ * 2.1.x: old model: (use_new_eh_code == 0): like 2.0.x
+ *       TO BE DONE:
+ *       new model: return 0 if successful
+ *                  return 1 if command cannot be queued (queue full)
+ *                  command will be inserted in midlevel queue then ...
  *
  ***********************************************************************/
 
-int
-DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
-    USHORT ioport, i;
     Scsi_Cmnd *pcmd;
-    struct Scsi_Host *psh;
-    PACB   pACB;
     PDCB   pDCB;
     PSRB   pSRB;
-    ULONG  flags;
-    PUCHAR ptr,ptr1;
+    DC390_AFLAGS
+    PACB   pACB = (PACB) cmd->host->hostdata;
 
-    psh = cmd->host;
-    pACB = (PACB ) psh->hostdata;
-    ioport = pACB->IOPortBase;
 
-#ifdef DC390_DEBUG0
-/*  if(pACB->scan_devices) */
-       printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
-#endif
+    DEBUG0(/*  if(pACB->scan_devices) */       \
+       printk(KERN_DEBUG "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
+               cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);)
+
+    DC390_LOCK_ACB;
+    
+    /* Assume BAD_TARGET; will be cleared later */
+    cmd->result = DID_BAD_TARGET << 16;
+   
+    /* TODO: Change the policy: Alway accept TEST_UNIT_READY or INQUIRY 
+     * commands and alloc a DCB for the device if not yet there. DCB will
+     * be removed in dc390_SRBdone if SEL_TIMEOUT */
 
     if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
-    {
        pACB->scan_devices = 0;
-       pPrevDCB->pNextDCB = pACB->pLinkDCB;
-    }
-    else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
-    {
+
+    else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) )
        pACB->scan_devices = 0;
-       pPrevDCB->pNextDCB = pACB->pLinkDCB;
-    }
 
-    if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
+    if ( ( cmd->target >= pACB->pScsiHost->max_id ) || 
+        (cmd->lun >= pACB->pScsiHost->max_lun) )
     {
 /*     printk("DC390: Ignore target %d lun %d\n",
                cmd->target, cmd->lun); */
-       cmd->result = (DID_BAD_TARGET << 16);
+       DC390_UNLOCK_ACB;
        done(cmd);
        return( 0 );
     }
 
-    if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+    if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
     {
-       if( pACB->DeviceCnt < MAX_DEVICES )
-       {
-           pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
-           pDCB = pACB->pDCB_free;
-#ifdef DC390_DEBUG0
-           printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
-#endif
-           DC390_initDCB( pACB, pDCB, cmd );
-       }
-       else    /* ???? */
-       {
-/*         printk("DC390: Ignore target %d lun %d\n",
-                   cmd->target, cmd->lun); */
-           cmd->result = (DID_BAD_TARGET << 16);
+       pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
+        pACB->scan_devices = 1;
+
+       dc390_initDCB( pACB, &pDCB, cmd );
+       if (!pDCB)
+         {
+           printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target);
+           DC390_UNLOCK_ACB;
            done(cmd);
            return(0);
-       }
+         };
+            
     }
     else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
     {
-/*     printk("DC390: Ignore target %d lun %d\n",
-               cmd->target, cmd->lun); */
-       cmd->result = (DID_BAD_TARGET << 16);
+       printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n",
+               cmd->target, cmd->lun); 
+       DC390_UNLOCK_ACB;
        done(cmd);
        return(0);
     }
     else
     {
-       pDCB = pACB->pLinkDCB;
-       while( (pDCB->UnitSCSIID != cmd->target) ||
-              (pDCB->UnitSCSILUN != cmd->lun) )
-       {
-           pDCB = pDCB->pNextDCB;
-       }
-#ifdef DC390_DEBUG0
-           printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
-#endif
+       pDCB = dc390_findDCB (pACB, cmd);
+       if (!pDCB)
+        {  /* should never happen */
+           DC390_UNLOCK_ACB;
+           done(cmd);
+           return(0);
+        };
     }
 
+    pACB->Cmds++;
     cmd->scsi_done = done;
     cmd->result = 0;
 
-    save_flags(flags);
-    cli();
-
-    if( pDCB->QIORBCnt )
+    if( pDCB->QIORBCnt ) /* Unsent commands ? */
     {
-       QLinkcmd( cmd, pDCB );
-       pcmd = Getcmd( pDCB );
+       dc390_QLinkcmd( cmd, pDCB );
+       pcmd = dc390_Getcmd( pDCB ); /* Get first command */
+        pACB->CmdInQ++;
     }
     else
        pcmd = cmd;
 
-    pSRB = GetSRB( pACB );
+    pSRB = dc390_GetSRB( pACB );
 
     if( !pSRB )
     {
-       QLinkcmd( pcmd, pDCB );
-       restore_flags(flags);
+        dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */
+       pACB->CmdOutOfSRB++;
+       DC390_UNLOCK_ACB;
        return(0);
     }
 
-/*  BuildSRB(pSRB); */
-
-    pSRB->pSRBDCB = pDCB;
-    pSRB->pcmd = pcmd;
-    ptr = (PUCHAR) pSRB->CmdBlock;
-    ptr1 = (PUCHAR) pcmd->cmnd;
-    pSRB->ScsiCmdLen = pcmd->cmd_len;
-    for(i=0; i< pcmd->cmd_len; i++)
-    {
-       *ptr = *ptr1;
-       ptr++;
-       ptr1++;
-    }
-    if( pcmd->use_sg )
-    {
-       pSRB->SGcount = (UCHAR) pcmd->use_sg;
-       pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
-    }
-    else if( pcmd->request_buffer )
-    {
-       pSRB->SGcount = 1;
-       pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
-       pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
-       pSRB->Segmentx.length = pcmd->request_bufflen;
-    }
-    else
-       pSRB->SGcount = 0;
-
-    pSRB->SGIndex = 0;
-    pSRB->AdaptStatus = 0;
-    pSRB->TargetStatus = 0;
-    pSRB->MsgCnt = 0;
-    if( pDCB->DevType != TYPE_TAPE )
-       pSRB->RetryCnt = 1;
-    else
-       pSRB->RetryCnt = 0;
-    pSRB->SRBStatus = 0;
-    pSRB->SRBFlag = 0;
-    pSRB->SRBState = 0;
-    pSRB->TotalXferredLen = 0;
-    pSRB->SGPhysAddr = 0;
-    pSRB->SGToBeXferLen = 0;
-    pSRB->ScsiPhase = 0;
-    pSRB->EndMessage = 0;
-    SendSRB( pcmd, pACB, pSRB );
+    dc390_BuildSRB (pcmd, pDCB, pSRB);
+    dc390_SendSRB( pACB, pSRB );
 
-    restore_flags(flags);
+    DC390_UNLOCK_ACB;
+    DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);)
     return(0);
 }
 
 
-static void
-DoNextCmd( PACB pACB, PDCB pDCB )
+static void dc390_DoNextCmd( PACB pACB, PDCB pDCB )
 {
     Scsi_Cmnd *pcmd;
     PSRB   pSRB;
-    ULONG  flags;
-    PUCHAR ptr,ptr1;
-    USHORT i;
-
 
     if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
        return;
-    save_flags(flags);
-    cli();
 
-    pcmd = Getcmd( pDCB );
-    pSRB = GetSRB( pACB );
+    pcmd = dc390_Getcmd( pDCB );
+    pSRB = dc390_GetSRB( pACB );
     if( !pSRB )
-    {
-       QLinkcmd( pcmd, pDCB );
-       restore_flags(flags);
-       return;
-    }
-
-    pSRB->pSRBDCB = pDCB;
-    pSRB->pcmd = pcmd;
-    ptr = (PUCHAR) pSRB->CmdBlock;
-    ptr1 = (PUCHAR) pcmd->cmnd;
-    pSRB->ScsiCmdLen = pcmd->cmd_len;
-    for(i=0; i< pcmd->cmd_len; i++)
-    {
-       *ptr = *ptr1;
-       ptr++;
-       ptr1++;
-    }
-    if( pcmd->use_sg )
-    {
-       pSRB->SGcount = (UCHAR) pcmd->use_sg;
-       pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
-    }
-    else if( pcmd->request_buffer )
-    {
-       pSRB->SGcount = 1;
-       pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
-       pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
-       pSRB->Segmentx.length = pcmd->request_bufflen;
-    }
+       dc390_QLinkcmd( pcmd, pDCB );
     else
-       pSRB->SGcount = 0;
+      {
+       dc390_BuildSRB (pcmd, pDCB, pSRB);
+       dc390_SendSRB( pACB, pSRB );
+      };
+}
 
-    pSRB->SGIndex = 0;
-    pSRB->AdaptStatus = 0;
-    pSRB->TargetStatus = 0;
-    pSRB->MsgCnt = 0;
-    if( pDCB->DevType != TYPE_TAPE )
-       pSRB->RetryCnt = 1;
-    else
-       pSRB->RetryCnt = 0;
-    pSRB->SRBStatus = 0;
-    pSRB->SRBFlag = 0;
-    pSRB->SRBState = 0;
-    pSRB->TotalXferredLen = 0;
-    pSRB->SGPhysAddr = 0;
-    pSRB->SGToBeXferLen = 0;
-    pSRB->ScsiPhase = 0;
-    pSRB->EndMessage = 0;
-    SendSRB( pcmd, pACB, pSRB );
+/* We ignore mapping problems, as we expect everybody to respect 
+ * valid partition tables. Waiting for complaints ;-) */
 
-    restore_flags(flags);
-    return;
-}
+#ifdef CONFIG_SCSI_DC390T_TRADMAP
+/* 
+ * The next function, partsize(), is copied from scsicam.c.
+ *
+ * This is ugly code duplication, but I didn't find another way to solve it:
+ * We want to respect the partition table and if it fails, we apply the 
+ * DC390 BIOS heuristic. Too bad, just calling scsicam_bios_param() doesn't do
+ * the job, because we don't know, whether the values returned are from
+ * the part. table or determined by setsize(). Unfortunately the setsize() 
+ * values differ from the ones chosen by the DC390 BIOS.
+ *
+ * Looking forward to seeing suggestions for a better solution! KG, 98/10/14
+ */
+#include <asm/unaligned.h>
 
+/*
+ * Function : static int partsize(struct buffer_head *bh, unsigned long 
+ *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ *     table, storing the results in *cyls, *hds, and *secs 
+ *
+ * Returns : -1 on failure, 0 on success.
+ *
+ */
+
+static int partsize(struct buffer_head *bh, unsigned long capacity,
+    unsigned int  *cyls, unsigned int *hds, unsigned int *secs) {
+    struct partition *p, *largest = NULL;
+    int i, largest_cyl;
+    int cyl, ext_cyl, end_head, end_cyl, end_sector;
+    unsigned int logical_end, physical_end, ext_physical_end;
+    
+
+    if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
+       for (largest_cyl = -1, p = (struct partition *) 
+           (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
+           if (!p->sys_ind)
+               continue;
+           cyl = p->cyl + ((p->sector & 0xc0) << 2);
+           if (cyl > largest_cyl) {
+               largest_cyl = cyl;
+               largest = p;
+           }
+       }
+    }
+
+    if (largest) {
+       end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
+       end_head = largest->end_head;
+       end_sector = largest->end_sector & 0x3f;
+
+       physical_end =  end_cyl * (end_head + 1) * end_sector +
+           end_head * end_sector + end_sector;
+
+       /* This is the actual _sector_ number at the end */
+       logical_end = get_unaligned(&largest->start_sect)
+                       + get_unaligned(&largest->nr_sects);
+
+       /* This is for >1023 cylinders */
+        ext_cyl= (logical_end-(end_head * end_sector + end_sector))
+                                        /(end_head + 1) / end_sector;
+       ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
+            end_head * end_sector + end_sector;
+
+       if ((logical_end == physical_end) ||
+           (end_cyl==1023 && ext_physical_end==logical_end)) {
+           *secs = end_sector;
+           *hds = end_head + 1;
+           *cyls = capacity / ((end_head + 1) * end_sector);
+           return 0;
+       }
+    }
+    return -1;
+}
 
 /***********************************************************************
  * Function:
@@ -667,30+988,84 @@ DoNextCmd( PACB pACB, PDCB pDCB )
  *
  * Description:
  *   Return the disk geometry for the given SCSI device.
+ *   Respect the partition table, otherwise try own heuristic
+ *
+ * Note:
+ *   In contrary to other externally callable funcs (DC390_), we don't lock
  ***********************************************************************/
-int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
+int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
 {
     int heads, sectors, cylinders;
-    PACB pACB;
-
-    pACB = (PACB) disk->device->host->hostdata;
-    heads = 64;
-    sectors = 32;
-    cylinders = disk->capacity / (heads * sectors);
+    PACB pACB = (PACB) disk->device->host->hostdata;
+    struct buffer_head *bh;
+    int ret_code = -1;
+    int size = disk->capacity;
 
-    if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
+    if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024)))
     {
-      heads = 255;
-      sectors = 63;
-      cylinders = disk->capacity / (heads * sectors);
+       /* try to infer mapping from partition table */
+       ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2,
+                            (unsigned int *) geom + 0, (unsigned int *) geom + 1);
+       brelse (bh);
     }
+    if (ret_code == -1)
+    {
+       heads = 64;
+       sectors = 32;
+       cylinders = size / (heads * sectors);
+
+       if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
+       {
+               heads = 255;
+               sectors = 63;
+               cylinders = size / (heads * sectors);
+       }
 
-    geom[0] = heads;
-    geom[1] = sectors;
-    geom[2] = cylinders;
+       geom[0] = heads;
+       geom[1] = sectors;
+       geom[2] = cylinders;
+    }
 
     return (0);
 }
+#else
+int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
+{
+    return scsicam_bios_param (disk, devno, geom);
+};
+#endif
+
+
+void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB)
+{
+    USHORT pstat; PDEVDECL1;
+
+    if (pSRB) 
+    {
+       printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n",
+               pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState,
+               pSRB->ScsiPhase);
+       printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus);
+    };
+    printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus);
+    printk ("DC390: Register dump: SCSI block:\n");
+    printk ("DC390: XferCnt  Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n");
+    printk ("DC390:  %06x   %02x   %02x   %02x",
+           DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16),
+           DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State));
+    printk ("   %02x   %02x   %02x   %02x   %02x   %02x\n",
+           DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
+           DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
+    printk ("DC390: Register dump: DMA engine:\n");
+    printk ("DC390: Cmd   STrCnt    SBusA    WrkBC    WrkAC Stat SBusCtrl\n");
+    printk ("DC390:  %02x %08x %08x %08x %08x   %02x %08x\n",
+           DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr),
+           DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr),
+           DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl));
+    PDEVSET1; PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstat);
+    printk ("DC390: Register dump: PCI Status: %04x\n", pstat);
+    printk ("DC390: Please report driver trouble to K.Garloff@ping.de\n");
+};
 
 
 /***********************************************************************
@@ -703,35+1078,28 @@ int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
  * Returns : 0 on success, -1 on failure.
  ***********************************************************************/
 
-int
-DC390_abort (Scsi_Cmnd *cmd)
+int DC390_abort (Scsi_Cmnd *cmd)
 {
-    ULONG flags;
-    PACB  pACB;
-    PDCB  pDCB, pdcb;
+    PDCB  pDCB;
     PSRB  pSRB, psrb;
-    USHORT count, i;
+    ULONG count, i;
     PSCSICMD  pcmd, pcmd1;
     int   status;
+    ULONG sbac;
+    DC390_AFLAGS
+    PACB  pACB = (PACB) cmd->host->hostdata;
 
+    DC390_LOCK_ACB;
 
-#ifdef DC390_DEBUG0
-    printk("DC390 : Abort Cmd.");
-#endif
-
-    save_flags(flags);
-    cli();
+    pDCB = dc390_findDCB (pACB, cmd);
+    /* abort() is too buggy at the moment. If it's called we are in trouble anyway.
+     * so let's dump some info into the syslog at least. (KG, 98/08/20) */
+    if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0;
+    printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n",
+           cmd->pid, pDCB, pSRB);
+    dc390_dumpinfo (pACB, pDCB, pSRB);
 
-    pACB = (PACB) cmd->host->hostdata;
-    pDCB = pACB->pLinkDCB;
-    pdcb = pDCB;
-    while( (pDCB->UnitSCSIID != cmd->target) ||
-          (pDCB->UnitSCSILUN != cmd->lun) )
-    {
-       pDCB = pDCB->pNextDCB;
-       if( pDCB == pdcb )
-           goto  NOT_RUN;
-    }
+    if( !pDCB ) goto  NOT_RUN;
 
     if( pDCB->QIORBCnt )
     {
@@ -761,7+1129,12 @@ DC390_abort (Scsi_Cmnd *cmd)
            }
        }
     }
-
+       
+    /* Added 98/07/02 KG */
+    pSRB = pDCB->pActiveSRB;
+    if (pSRB && pSRB->pcmd == cmd )
+       goto ON_GOING;
+       
     pSRB = pDCB->pWaitingSRB;
     if( !pSRB )
        goto  ON_GOING;
@@ -778,7+1151,7 @@ DC390_abort (Scsi_Cmnd *cmd)
        while( psrb->pNextSRB->pcmd != cmd )
        {
            psrb = psrb->pNextSRB;
-           if( !(psrb->pNextSRB) )
+           if( !(psrb->pNextSRB) || psrb == pSRB)
                goto ON_GOING;
        }
        pSRB = psrb->pNextSRB;
@@ -795,6+1168,8 @@ IN_WAIT:
 
 ON_GOING:
     pSRB = pDCB->pGoingSRB;
+    pDCB->DCBFlag |= ABORT_DEV_;
+    /* Now for the hard part: The command is currently processed */
     for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
     {
        if( pSRB->pcmd != cmd )
@@ -804,6+1179,8 @@ ON_GOING:
            if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
            {
                status = SCSI_ABORT_BUSY;
+               printk ("DC390: Abort current command (pid %li, SRB %p)\n",
+                       cmd->pid, pSRB);
                goto  ABO_X;
            }
            else
@@ -819,20+1196,51 @@ NOT_RUN:
 
 ABO_X:
     cmd->result = DID_ABORT << 16;
+    printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status);
+    if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */
+       {
+               /* Let's do something to help the bus getting clean again */
+               DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+               DC390_write8 (ScsiCmd, DMA_COMMAND);
+                       //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+               //DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+               DC390_write8 (ScsiCmd, NOP_CMD);
+               //udelay (10000);
+               //DC390_read8 (INT_Status);
+               //DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+       };
+    sbac = DC390_read32 (DMA_ScsiBusCtrl);
+    if (sbac & SCSI_BUSY)
+    {  /* clear BSY, SEL and ATN */
+       printk (KERN_WARNING "DC390: Reset SCSI device: ");
+       //DC390_write32 (DMA_ScsiBusCtrl, (sbac | SCAM) & ~SCSI_LINES);
+       //udelay (250);
+       //sbac = DC390_read32 (DMA_ScsiBusCtrl);
+       //printk ("%08lx ", sbac);
+       //DC390_write32 (DMA_ScsiBusCtrl, sbac & ~(SCSI_LINES | SCAM));
+       //udelay (100);
+       //sbac = DC390_read32 (DMA_ScsiBusCtrl);
+       //printk ("%08lx ", sbac);
+       DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+       udelay (250);
+       DC390_write8 (ScsiCmd, NOP_CMD);
+       sbac = DC390_read32 (DMA_ScsiBusCtrl);
+       printk ("%08lx\n", sbac);
+    };
+    dc390_lastabortedpid = cmd->pid;
+    DC390_UNLOCK_ACB;
+    //do_DC390_Interrupt (pACB->IRQLevel, 0, 0);
     cmd->scsi_done(cmd);
-    restore_flags(flags);
     return( status );
 }
 
 
-static void
-ResetDevParam( PACB pACB )
+static void dc390_ResetDevParam( PACB pACB )
 {
     PDCB   pDCB, pdcb;
 
     pDCB = pACB->pLinkDCB;
-    if( pDCB == NULL )
-       return;
+    if (! pDCB) return;
     pdcb = pDCB;
     do
     {
@@ -840,24+1248,22 @@ ResetDevParam( PACB pACB )
        pDCB->SyncPeriod = 0;
        pDCB->SyncOffset = 0;
        pDCB->CtrlR3 = FAST_CLK;
-       pDCB->CtrlR4 &= NEGATE_REQACKDATA;
-       pDCB->CtrlR4 |= EATER_25NS;
+       pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK;
+       pDCB->CtrlR4 |= pACB->glitch_cfg;
        pDCB = pDCB->pNextDCB;
     }
     while( pdcb != pDCB );
 }
 
 
-static void
-RecoverSRB( PACB pACB )
+static void dc390_RecoverSRB( PACB pACB )
 {
     PDCB   pDCB, pdcb;
     PSRB   psrb, psrb2;
-    USHORT cnt, i;
+    ULONG  cnt, i;
 
     pDCB = pACB->pLinkDCB;
-    if( pDCB == NULL )
-       return;
+    if( !pDCB ) return;
     pdcb = pDCB;
     do
     {
@@ -867,7+1273,7 @@ RecoverSRB( PACB pACB )
        {
            psrb2 = psrb;
            psrb = psrb->pNextSRB;
-/*         RewaitSRB( pDCB, psrb ); */
+/*         dc390_RewaitSRB( pDCB, psrb ); */
            if( pdcb->pWaitingSRB )
            {
                psrb2->pNextSRB = pdcb->pWaitingSRB;
@@ -884,8+1290,7 @@ RecoverSRB( PACB pACB )
        pdcb->pGoingSRB = NULL;
        pdcb->TagMask = 0;
        pdcb = pdcb->pNextDCB;
-    }
-    while( pdcb != pDCB );
+    } while( pdcb != pDCB );
 }
 
 
@@ -901,77+1306,80 @@ RecoverSRB( PACB pACB )
 
 int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
 {
-    USHORT   ioport;
-    unsigned long flags;
-    PACB  pACB;
-    UCHAR    bval;
-    USHORT  i;
+    UCHAR   bval;
+    ULONG   i;
+    DC390_AFLAGS
+    PACB    pACB = (PACB) cmd->host->hostdata;
 
+    printk(KERN_INFO "DC390: RESET ... ");
 
-#ifdef DC390_DEBUG1
-    printk("DC390: RESET,");
-#endif
-
-    pACB = (PACB ) cmd->host->hostdata;
-    ioport = pACB->IOPortBase;
-    save_flags(flags);
-    cli();
-    bval = inb(ioport+CtrlReg1);
+    DC390_LOCK_ACB;
+    bval = DC390_read8 (CtrlReg1);
     bval |= DIS_INT_ON_SCSI_RST;
-    outb(bval,ioport+CtrlReg1);  /* disable interrupt */
-    DC390_ResetSCSIBus( pACB );
-    for( i=0; i<500; i++ )
-       mdelay(1);
-    bval = inb(ioport+CtrlReg1);
-    bval &= ~DIS_INT_ON_SCSI_RST;
-    outb(bval,ioport+CtrlReg1); /* re-enable interrupt */
+    DC390_write8 (CtrlReg1, bval);     /* disable interrupt */
+
+    dc390_ResetSCSIBus( pACB );
+    /* Unlock ? */
+    for( i=0; i<600; i++ )
+       udelay(1000);
 
-    bval = DMA_IDLE_CMD;
-    outb(bval,ioport+DMA_Cmd);
-    bval = CLEAR_FIFO_CMD;
-    outb(bval,ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    DC390_read8 (INT_Status);          /* Reset Pending INT */
 
-    ResetDevParam( pACB );
-    DoingSRB_Done( pACB );
+    dc390_ResetDevParam( pACB );
+    dc390_DoingSRB_Done( pACB );
+    /* dc390_RecoverSRB (pACB); */
     pACB->pActiveDCB = NULL;
 
     pACB->ACBFlag = 0;
-    DoWaitingSRB( pACB );
+    bval = DC390_read8 (CtrlReg1);
+    bval &= ~DIS_INT_ON_SCSI_RST;
+    DC390_write8 (CtrlReg1, bval);     /* re-enable interrupt */
 
-    restore_flags(flags);
-#ifdef DC390_DEBUG1
-    printk("DC390: RESET1,");
-#endif
+    dc390_DoWaitingSRB( pACB );
+
+    DC390_UNLOCK_ACB;
+    printk("done\n");
     return( SCSI_RESET_SUCCESS );
 }
 
-
 #include "scsiiom.c"
 
 
 /***********************************************************************
- * Function : static void DC390_initDCB
+ * Function : static void dc390_initDCB
  *
  * Purpose :  initialize the internal structures for a given DCB
  *
  * Inputs : cmd - pointer to this scsi cmd request block structure
  *
  ***********************************************************************/
-void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
+void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd )
 {
     PEEprom    prom;
-    UCHAR      bval;
-    USHORT     index;
-
-    if( pACB->DeviceCnt == 0 )
+    UCHAR      index;
+    PDCB pDCB;
+
+    pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC);
+    DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n",   \
+           cmd->target, cmd->lun, (int)pDCB);)
+    *ppDCB = pDCB;
+    if (!pDCB) return;
+    if( pACB->DCBCnt == 0 )
     {
        pACB->pLinkDCB = pDCB;
        pACB->pDCBRunRobin = pDCB;
-       pDCB->pNextDCB = pDCB;
-       pPrevDCB = pDCB;
     }
     else
-       pPrevDCB->pNextDCB = pDCB;
+    {
+       pACB->pLastDCB->pNextDCB = pDCB;
+    };
+   
+    pACB->DCBCnt++;
+   
+    pACB->pLastDCB = pDCB;
+    pDCB->pNextDCB = pACB->pLinkDCB;
 
     pDCB->pDCBACB = pACB;
     pDCB->QIORBCnt = 0;
@@ -983,122+1391,143 @@ void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
     pDCB->pActiveSRB = NULL;
     pDCB->TagMask = 0;
     pDCB->MaxCommand = 1;
-    pDCB->AdaptIndex = pACB->AdapterIndex;
     index = pACB->AdapterIndex;
     pDCB->DCBFlag = 0;
 
-    prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
+    prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2];
     pDCB->DevMode = prom->EE_MODE1;
-    pDCB->AdpMode = eepromBuf[index][EE_MODE2];
-
-    if( pDCB->DevMode & EN_DISCONNECT_ )
-       bval = 0xC0;
-    else
-       bval = 0x80;
-    bval |= cmd->lun;
-    pDCB->IdentifyMsg = bval;
 
     pDCB->SyncMode = 0;
-    if( pDCB->DevMode & SYNC_NEGO_ )
-    {
-       if( !(cmd->lun) || CurrSyncOffset )
-           pDCB->SyncMode = SYNC_ENABLE;
-    }
+    dc390_updateDCB(pACB, pDCB);
 
     pDCB->SyncPeriod = 0;
     pDCB->SyncOffset = 0;
-    pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
-
-    pDCB->CtrlR1 = pACB->AdaptSCSIID;
-    if( pDCB->DevMode & PARITY_CHK_ )
-       pDCB->CtrlR1 |= PARITY_ERR_REPO;
+    pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2;
 
     pDCB->CtrlR3 = FAST_CLK;
 
-    pDCB->CtrlR4 = EATER_25NS;
-    if( pDCB->AdpMode & ACTIVE_NEGATION)
-       pDCB->CtrlR4 |= NEGATE_REQACKDATA;
+    pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED;
+    if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION)
+       pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK;
 }
 
+/***********************************************************************
+ * Function : static void dc390_updateDCB
+ *
+ * Purpose :  Set the configuration dependent DCB parameters
+ *
+ ***********************************************************************/
+void dc390_updateDCB (PACB pACB, PDCB pDCB)
+{
+  pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN);
+  
+  if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP;
+  else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP;
+  
+  if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) )
+     pDCB->SyncMode |= SYNC_ENABLE;
+  else
+     {
+       pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE);
+       pDCB->SyncOffset &= ~0x0f;
+     };
+   
+  if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; 
+  
+  pDCB->CtrlR1 = pACB->pScsiHost->this_id;
+  if( pDCB->DevMode & PARITY_CHK_ )
+    pDCB->CtrlR1 |= PARITY_ERR_REPO;
+};  
+
 
 /***********************************************************************
- * Function : static void DC390_initSRB
+ * Function : static void dc390_updateDCBs
+ *
+ * Purpose :  Set the configuration dependent DCB params for all DCBs
+ *
+ ***********************************************************************/
+static void dc390_updateDCBs (PACB pACB)
+{
+  int i;
+  PDCB pDCB = pACB->pLinkDCB;
+  for (i = 0; i < pACB->DeviceCnt; i++)
+    {
+      dc390_updateDCB (pACB, pDCB);
+      pDCB = pDCB->pNextDCB;
+    };
+};
+  
+
+/***********************************************************************
+ * Function : static void dc390_initSRB
  *
  * Purpose :  initialize the internal structures for a given SRB
  *
  * Inputs : psrb - pointer to this scsi request block structure
  *
  ***********************************************************************/
-void DC390_initSRB( PSRB psrb )
+static void __inline__ dc390_initSRB( PSRB psrb )
 {
-#ifdef DC390_DEBUG0
-   printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
-#endif
-       psrb->PhysSRB = virt_to_bus( psrb );
+  /* psrb->PhysSRB = virt_to_phys( psrb ); */
 }
 
 
-void DC390_linkSRB( PACB pACB )
+void dc390_linkSRB( PACB pACB )
 {
-    USHORT  count, i;
-    PSRB    psrb;
+    ULONG   count, i;
 
     count = pACB->SRBCount;
-
     for( i=0; i< count; i++)
     {
        if( i != count - 1)
            pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
        else
            pACB->SRB_array[i].pNextSRB = NULL;
-       psrb = (PSRB) &pACB->SRB_array[i];
-       DC390_initSRB( psrb );
+       dc390_initSRB( &pACB->SRB_array[i] );
     }
 }
 
 
 /***********************************************************************
- * Function : static void DC390_initACB
+ * Function : static void dc390_initACB
  *
  * Purpose :  initialize the internal structures for a given SCSI host
  *
  * Inputs : psh - pointer to this host adapter's structure
  *
  ***********************************************************************/
-__initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ))
+void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
     PACB    pACB;
-    USHORT  i;
+    UCHAR   i;
+    DC390_AFLAGS
 
     psh->can_queue = MAX_CMD_QUEUE;
     psh->cmd_per_lun = MAX_CMD_PER_LUN;
-    psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
+    psh->this_id = (int) dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
     psh->io_port = io_port;
     psh->n_io_port = 0x80;
     psh->irq = Irq;
 
     pACB = (PACB) psh->hostdata;
+    DC390_LOCK_INIT;
+    DC390_LOCK_ACB;
 
+    pACB->pScsiHost = psh;
+    pACB->IOPortBase = (USHORT) io_port;
+    pACB->IRQLevel = Irq;
+
+    DEBUG0(printk (KERN_DEBUG "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n",       \
+           index, psh->this_id, (int)io_port, Irq);)
+   
     psh->max_id = 8;
-#ifdef CONFIG_SCSI_MULTI_LUN
-    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+
+    if( psh->max_id - 1 == dc390_eepromBuf[index][EE_ADAPT_SCSI_ID] )
+       psh->max_id--;
+    psh->max_lun = 1;
+    if( dc390_eepromBuf[index][EE_MODE2] & LUN_CHECK )
        psh->max_lun = 8;
-    else
-#endif
-       psh->max_lun = 1;
-
-    pACB->max_id = 7;
-    if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
-       pACB->max_id--;
-#ifdef CONFIG_SCSI_MULTI_LUN
-    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
-       pACB->max_lun = 7;
-    else
-#endif
-       pACB->max_lun = 0;
 
-    pACB->pScsiHost = psh;
-    pACB->IOPortBase = (USHORT) io_port;
     pACB->pLinkDCB = NULL;
     pACB->pDCBRunRobin = NULL;
     pACB->pActiveDCB = NULL;
@@ -1106,42+1535,39 @@ __initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
     pACB->SRBCount = MAX_SRB_CNT;
     pACB->AdapterIndex = index;
     pACB->status = 0;
-    pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
-    pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
-    pACB->AdaptSCSILUN = 0;
+    psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
     pACB->DeviceCnt = 0;
-    pACB->IRQLevel = Irq;
-    pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2;
+    pACB->DCBCnt = 0;
+    pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM];
     pACB->ACBFlag = 0;
     pACB->scan_devices = 1;
-    pACB->Gmode2 = eepromBuf[index][EE_MODE2];
-    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
-       pACB->LUNchk = 1;
-    pACB->pDCB_free = &pACB->DCB_array[0];
-    DC390_linkSRB( pACB );
+    pACB->Gmode2 = dc390_eepromBuf[index][EE_MODE2];
+    dc390_linkSRB( pACB );
     pACB->pTmpSRB = &pACB->TmpSRB;
-    DC390_initSRB( pACB->pTmpSRB );
+    dc390_initSRB( pACB->pTmpSRB );
     for(i=0; i<MAX_SCSI_ID; i++)
        pACB->DCBmap[i] = 0;
+    pACB->sel_timeout = SEL_TIMEOUT;
+    pACB->glitch_cfg = EATER_25NS;
+    pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0;
 }
 
 
 /***********************************************************************
- * Function : static int DC390_initAdapter
+ * Function : static int dc390_initAdapter
  *
  * Purpose :  initialize the SCSI chip ctrl registers
  *
  * Inputs : psh - pointer to this host adapter's structure
  *
  ***********************************************************************/
-__initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index))
+int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
-    USHORT ioport;
-    UCHAR  bval;
     PACB   pACB, pacb;
-    USHORT used_irq = 0;
+    UCHAR  used_irq = 0, dstate;
+    int    i;
 
-    pacb = pACB_start;
+    pacb = dc390_pACB_start;
     if( pacb != NULL )
     {
        for ( ; (pacb != (PACB) -1) ; )
@@ -1158,49+1584,54 @@ __initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT inde
 
     if( !used_irq )
     {
-       if( request_irq(Irq, do_DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
+       if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) ))
+           {
+                   printk(KERN_ERR "DC390: register IRQ error!\n");
+                   return( -1 );
+           }
+    }
+
+    if (check_region (io_port, psh->n_io_port))
        {
-           printk("DC390: register IRQ error!\n");
+           printk(KERN_ERR "DC390: register IO ports error!\n");
            return( -1 );
        }
-    }
-
-    request_region(io_port,psh->n_io_port,"tmscsim");
-
-    ioport = (USHORT) io_port;
-
+    else
+       request_region (io_port, psh->n_io_port, "tmscsim");
+   
     pACB = (PACB) psh->hostdata;
-    bval = SEL_TIMEOUT;                /* 250ms selection timeout */
-    outb(bval,ioport+Scsi_TimeOut);
-
-    bval = CLK_FREQ_40MHZ;             /* Conversion factor = 0 , 40MHz clock */
-    outb(bval,ioport+Clk_Factor);
-
-    bval = NOP_CMD;                    /* NOP cmd - clear command register */
-    outb(bval,ioport+ScsiCmd);
+    /* pACB->IOPortBase = (USHORT) io_port; */
 
-    bval = EN_FEATURE+EN_SCSI2_CMD;    /* Enable Feature and SCSI-2 */
-    outb(bval,ioport+CtrlReg2);
+    DC390_write8_ (CtrlReg1, DIS_INT_ON_SCSI_RST | psh->this_id, io_port);     /* Disable SCSI bus reset interrupt */
 
-    bval = FAST_CLK;                   /* fast clock */
-    outb(bval,ioport+CtrlReg3);
-
-    bval = EATER_25NS;
-    if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
-        bval |= NEGATE_REQACKDATA;
-    outb(bval,ioport+CtrlReg4);
-
-    bval = DIS_INT_ON_SCSI_RST;        /* Disable SCSI bus reset interrupt */
-    outb(bval,ioport+CtrlReg1);
+    if (pACB->Gmode2 & RST_SCSI_BUS)
+    {
+       dc390_ResetSCSIBus( pACB );
+       /* Unlock before ? */
+       for( i=0; i<600; i++ )
+               udelay(1000);
+    };
+    pACB->ACBFlag = 0;
+    
+    DC390_write8 (Scsi_TimeOut, SEL_TIMEOUT);          /* 250ms selection timeout */
+    DC390_write8 (Clk_Factor, CLK_FREQ_40MHZ);         /* Conversion factor = 0 , 40MHz clock */
+    DC390_write8 (ScsiCmd, NOP_CMD);                   /* NOP cmd - clear command register */
+    DC390_write8 (CtrlReg2, EN_FEATURE+EN_SCSI2_CMD);  /* Enable Feature and SCSI-2 */
+    DC390_write8 (CtrlReg3, FAST_CLK);                 /* fast clock */
+    DC390_write8 (CtrlReg4, pACB->glitch_cfg |                 /* glitch eater */
+               (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0);  /* Negation */
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    dstate = DC390_read8 (DMA_Status);
+    DC390_write8 (DMA_Status, dstate); /* clear */
 
     return(0);
 }
 
 
-void
-DC390_EnDisableCE( UCHAR mode, struct pci_dev *pdev, PUCHAR regval )
+static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval )
 {
-
     UCHAR bval;
 
     bval = 0;
@@ -1208,15+1639,68 @@ DC390_EnDisableCE( UCHAR mode, struct pci_dev *pdev, PUCHAR regval )
        *regval = 0xc0;
     else
        *regval = 0x80;
-    pci_write_config_byte(pdev, *regval, bval);
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     if(mode == DISABLE_CE)
-       pci_write_config_byte(pdev, *regval, bval);
+        PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     udelay(160);
 }
 
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+static void __init dc390_EEpromDefaults (UCHAR index)
+{
+    PUCHAR ptr;
+    UCHAR  id;
+    ptr = (PUCHAR) dc390_eepromBuf[index];
+    
+    /* Adapter Settings */
+    ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */
+    ptr[EE_MODE2] = (UCHAR)tmscsim[3];
+    ptr[EE_DELAY] = 0; /* ?? */
+    ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */
+    
+    /* Device Settings */
+    for (id = 0; id < MAX_SCSI_ID; id++)
+    {
+      ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */
+      ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */
+    };
+    dc390_adapname = "AM53C974";
+}
 
-void
-DC390_EEpromOutDI( struct pci_dev *pdev, PUCHAR regval, USHORT Carry )
+static void __init dc390_checkparams (void)
+{
+       PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\
+                     tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);)
+       if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */
+       {
+               tmscsim[0] = 7; tmscsim[1] = 4; 
+               tmscsim[2] = 9; tmscsim[3] = 15;
+               tmscsim[4] = 2;
+               printk (KERN_INFO "DC390: Using safe settings.\n");
+       }
+       else
+       {
+               /* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */
+               if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4;
+               if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4;
+       };
+};
+/* Override defaults on cmdline:
+ * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
+ */
+void __init dc390_setup (char *str, int *ints)
+{
+       int i;
+       for (i = 0; i < ints[0]; i++)
+               tmscsim[i] = ints[i+1];
+       if (ints[0] > 5)
+               printk (KERN_NOTICE "DC390: ignore extra params!\n");
+       /* dc390_checkparams (); */
+};
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
+
+static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry )
 {
     UCHAR bval;
 
@@ -1225,28+1709,27 @@ DC390_EEpromOutDI( struct pci_dev *pdev, PUCHAR regval, USHORT Carry )
     {
        bval = 0x40;
        *regval = 0x80;
-       pci_write_config_byte(pdev, *regval, bval);
+       PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     }
     udelay(160);
     bval |= 0x80;
-    pci_write_config_byte(pdev, *regval, bval);
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     udelay(160);
     bval = 0;
-    pci_write_config_byte(pdev, *regval, bval);
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     udelay(160);
 }
 
 
-UCHAR
-DC390_EEpromInDO( struct pci_dev *pdev )
+static UCHAR __init dc390_EEpromInDO( PDEVDECL )
 {
     UCHAR bval;
 
-    pci_write_config_byte(pdev, 0x80, 0x80);
+    PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x80);
     udelay(160);
-    pci_write_config_byte(pdev, 0x80, 0x40);
+    PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x40);
     udelay(160);
-    pci_read_config_byte(pdev, 0x00, &bval);
+    PCI_READ_CONFIG_BYTE(PDEV, 0x00, &bval);
     if(bval == 0x22)
        return(1);
     else
@@ -1254,8+1737,7 @@ DC390_EEpromInDO( struct pci_dev *pdev )
 }
 
 
-USHORT
-EEpromGetData1( struct pci_dev *pdev )
+static USHORT __init dc390_EEpromGetData1( PDEVDECL )
 {
     UCHAR i;
     UCHAR carryFlag;
@@ -1265,67+1747,59 @@ EEpromGetData1( struct pci_dev *pdev )
     for(i=0; i<16; i++)
     {
        wval <<= 1;
-       carryFlag = DC390_EEpromInDO(pdev);
+       carryFlag = dc390_EEpromInDO(PDEV);
        wval |= carryFlag;
     }
     return(wval);
 }
 
 
-void
-DC390_Prepare( struct pci_dev *pdev, PUCHAR regval, UCHAR EEpromCmd )
+static void __init dc390_Prepare( PDEVDECL, PUCHAR regval, UCHAR EEpromCmd )
 {
     UCHAR i,j;
-    USHORT carryFlag;
+    UCHAR carryFlag;
 
     carryFlag = 1;
     j = 0x80;
     for(i=0; i<9; i++)
     {
-       DC390_EEpromOutDI(pdev,regval,carryFlag);
+       dc390_EEpromOutDI(PDEV,regval,carryFlag);
        carryFlag = (EEpromCmd & j) ? 1 : 0;
        j >>= 1;
     }
 }
 
 
-void
-DC390_ReadEEprom( struct pci_dev *pdev, int index )
+static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr)
 {
     UCHAR   regval,cmd;
-    PUSHORT ptr;
-    USHORT  i;
+    UCHAR   i;
 
-    ptr = (PUSHORT) &eepromBuf[index][0];
     cmd = EEPROM_READ;
     for(i=0; i<0x40; i++)
     {
-       DC390_EnDisableCE(ENABLE_CE, pdev, &regval);
-       DC390_Prepare(pdev, &regval, cmd);
-       *ptr = EEpromGetData1(pdev);
-       ptr++;
-       cmd++;
-       DC390_EnDisableCE(DISABLE_CE, pdev, &regval);
+       dc390_EnDisableCE(ENABLE_CE, PDEV, &regval);
+       dc390_Prepare(PDEV, &regval, cmd++);
+       *ptr++ = dc390_EEpromGetData1(PDEV);
+       dc390_EnDisableCE(DISABLE_CE, PDEV, &regval);
     }
 }
 
 
-USHORT
-DC390_CheckEEpromCheckSum( struct pci_dev *pdev, int index )
+static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index )
 {
-    USHORT wval, rc, *ptr;
     UCHAR  i;
+    char  EEbuf[128];
+    USHORT wval, *ptr = (PUSHORT)EEbuf;
 
-    DC390_ReadEEprom( pdev, index );
+    dc390_ReadEEprom( PDEV, ptr );
+    memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
+    memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], 
+           &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
     wval = 0;
-    ptr = (PUSHORT) &eepromBuf[index][0];
-    for(i=0; i<128 ;i+=2, ptr++)
+    for(i=0; i<0x40; i++, ptr++)
        wval += *ptr;
-    if( wval == 0x1234 )
-       rc = 0;
-    else
-       rc = -1;
-    return( rc );
+    return (wval == 0x1234 ? 0 : 1);
 }
 
 
@@ -1338,71+1812,95 @@ DC390_CheckEEpromCheckSum( struct pci_dev *pdev, int index )
  *
  * Preconditions : when this function is called, the chip_type
  *     field of the pACB structure MUST have been set.
+ *
+ * Note: written in capitals, because the locking is only done here,
+ *     not in DC390_detect, called from outside 
  ***********************************************************************/
 
-__initfunc(static int
-DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, int index))
+static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, int index)
 {
     PSH   psh;
     PACB  pACB;
-
-    if( !DC390_CheckEEpromCheckSum( pdev, index ) )
+    DC390_AFLAGS
+    
+    if (dc390_CheckEEpromCheckSum (PDEV, index))
     {
-       psh = scsi_register( psht, sizeof(DC390_ACB) );
-       if( !psh )
-           return( -1 );
-       if( !pSH_start )
-       {
-           pSH_start = psh;
-           pSH_current = psh;
-       }
-       else
-       {
-           pSH_current->next = psh;
-           pSH_current = psh;
-       }
+#ifdef CONFIG_SCSI_DC390T_NOGENSUPP
+       printk (KERN_ERR "DC390_init: No EEPROM found!\n");
+       return( -1 );
+#else
+       int period;
+       printk (KERN_INFO "DC390_init: No EEPROM found!\n");
+       printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n");
+       dc390_checkparams ();
+       period = dc390_clock_period1[tmscsim[1]];
+       printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz),"
+               " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1],
+               40 / period, ((40%period)*10 + period/2) / period,
+               (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]));
+       dc390_EEpromDefaults (index);
+#endif
+    };
+   
+    psh = scsi_register( psht, sizeof(DC390_ACB) );
+    if( !psh ) return( -1 );
+       
+    pACB = (PACB) psh->hostdata;
+    DC390_LOCK_INIT;
+    DC390_LOCK_ACB;
 
-#ifdef DC390_DEBUG0
-       printk("DC390: pSH = %8x,", (UINT) psh);
-       printk("DC390: Index %02i,", index);
+#if 0
+    if( !dc390_pSH_start )
+    {
+        dc390_pSH_start = psh;
+        dc390_pSH_current = psh;
+    }
+    else
+    {
+        dc390_pSH_current->next = psh;
+        dc390_pSH_current = psh;
+    }
 #endif
 
-       DC390_initACB( psh, io_port, Irq, index );
-       if( !DC390_initAdapter( psh, io_port, Irq, index ) )
-       {
-           pACB = (PACB) psh->hostdata;
-           if( !pACB_start )
-           {
-               pACB_start = pACB;
-               pACB_current = pACB;
-               pACB->pNextACB = (PACB) -1;
-           }
-           else
-           {
-               pACB_current->pNextACB = pACB;
-               pACB_current = pACB;
-               pACB->pNextACB = (PACB)  -1;
-           }
+    DEBUG0(printk("DC390: pSH = %8x,", (UINT) psh);)
+    DEBUG0(printk("DC390: Index %02i,", index);)
 
-#ifdef DC390_DEBUG0
-       printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
-             (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
-       printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
-             sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
-#endif
+    dc390_initACB( psh, io_port, Irq, index );
+    PDEVSET;
+
+    DC390_read8_ (INT_Status, io_port);                /* Reset Pending INT */
 
+    if( !dc390_initAdapter( psh, io_port, Irq, index ) )
+    {
+       pACB = (PACB) psh->hostdata;
+       if( !dc390_pACB_start )
+       {
+           dc390_pACB_start = pACB;
+           dc390_pACB_current = pACB;
+           pACB->pNextACB = (PACB) -1;
        }
        else
        {
-           pSH_start = NULL;
-           scsi_unregister( psh );
-           return( -1 );
+           dc390_pACB_current->pNextACB = pACB;
+           dc390_pACB_current = pACB;
+           pACB->pNextACB = (PACB)  -1;
        }
-       return( 0 );
+        
+       DEBUG0(printk("DC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
+               (UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array);)
+       DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\
+               sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );)
+
+       DC390_read8_ (INT_Status, io_port);             /* Reset Pending INT */
+
+       DC390_UNLOCK_ACB;
+        return (0);
     }
     else
     {
-       printk("DC390_init: EEPROM reading error!\n");
+       //dc390_pSH_start = NULL;
+       scsi_unregister( psh );
+       DC390_UNLOCK_ACB;
        return( -1 );
     }
 }
@@ -1421,54+1919,437 @@ DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, int index
  *
  ***********************************************************************/
 
-__initfunc(int
-DC390_detect(Scsi_Host_Template *psht))
+#ifndef NEW_PCI
+/* Acc. to PCI 2.1 spec it's up to the driver to enable Bus mastering:
+ * We use pci_set_master () for 2.1.x and this func for 2.0.x: */
+static void __init dc390_set_master (PDEVDECL)
 {
-    struct pci_dev *pdev = NULL;
-    UINT    irq;
-    UINT    io_port;
-    USHORT  adaptCnt = 0;      /* Number of boards detected */
+       USHORT cmd;
+       UCHAR lat;
+       
+       PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
+       
+        if (! (cmd & PCI_COMMAND_MASTER)) {    
+               printk("PCI: Enabling bus mastering for device %02x:%02x\n",
+                      PCI_BUS_DEV);
+               cmd |= PCI_COMMAND_MASTER;
+               PCI_WRITE_CONFIG_WORD(PDEV, PCI_COMMAND, cmd);
+       }
+       PCI_READ_CONFIG_BYTE (PDEV, PCI_LATENCY_TIMER, &lat);
+       if (lat < 16 /* || lat == 255 */) {
+               printk("PCI: Setting latency timer of device %02x:%02x from %i to 64\n",
+                      PCI_BUS_DEV, lat);
+               PCI_WRITE_CONFIG_BYTE(PDEV, PCI_LATENCY_TIMER, 64);
+       }
+       
+};
+#endif /* ! NEW_PCI */
 
-    psht->proc_dir = &proc_scsi_tmscsim;
+static void __init dc390_set_pci_cfg (PDEVDECL)
+{
+       USHORT cmd;
+       PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
+       cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
+       PCI_WRITE_CONFIG_WORD (PDEV, PCI_COMMAND, cmd);
+       PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));
+};
+       
+
+int __init DC390_detect (Scsi_Host_Template *psht)
+{
+    PDEVDECL0;
+    UCHAR   irq;
+    UINT    io_port;
+    UCHAR   adaptCnt = 0;      /* Number of boards detected */
+    DC390_IFLAGS DC390_DFLAGS
 
-    InitialTime = 1;
-    pSHT_start = psht;
-    pACB_start = NULL;
+    DC390_LOCK_DRV;
+    //dc390_pSHT_start = psht;
+    dc390_pACB_start = NULL;
 
-    if ( pci_present() )
-       while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, pdev)))
+    if ( PCI_PRESENT )
+       while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974))
        {
-           io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
-           irq = pdev->irq;
-#ifdef DC390_DEBUG0
-           printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
-#endif
-           if( !DC390_init(psht, io_port, irq, pdev, adaptCnt))
+           DC390_LOCK_IO;              /* Remove this when going to new eh */
+           PCI_GET_IO_AND_IRQ;
+           DEBUG0(printk(KERN_DEBUG "DC390(%i): IO_PORT=%04x,IRQ=%x\n", adaptCnt, (UINT) io_port, irq);)
+
+           if( !DC390_init(psht, io_port, irq, PDEV, adaptCnt))
+           {
+               PCI_SET_MASTER;
+               dc390_set_pci_cfg (PDEV);
                adaptCnt++;
+           };
+           DC390_UNLOCK_IO;            /* Remove when going to new eh */
        }
-
-    InitialTime = 0;
-    adapterCnt = adaptCnt;
+    else
+       printk (KERN_ERR "DC390: No PCI BIOS found!\n");
+   
+    if (adaptCnt)
+       psht->proc_dir = &DC390_proc_scsi_tmscsim;
+
+    printk(KERN_INFO "DC390: %i adapters found\n", adaptCnt);
+    dc390_adapterCnt = adaptCnt;
+    DC390_UNLOCK_DRV;
     return( adaptCnt );
 }
 
 
+static void dc390_inquiry_done (Scsi_Cmnd* cmd)
+{
+   printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n",
+          cmd->target, cmd->lun, cmd->result);
+   if (cmd->result)
+   {
+       PACB pACB = (PACB)cmd->host->hostdata;
+       PDCB pDCB = dc390_findDCB (pACB, cmd);
+       printk ("DC390: Unsetting DsCn, Sync and TagQ!\n");
+       if (pDCB)
+       {
+               pDCB->DevMode &= ~(SYNC_NEGO_ | TAG_QUEUEING_ | EN_DISCONNECT_ );
+               dc390_updateDCB (pACB, pDCB);
+       };
+   };
+   kfree (cmd->buffer);
+   kfree (cmd);
+};
+
+void dc390_inquiry (PACB pACB, PDCB pDCB)
+{
+   char* buffer;
+   Scsi_Cmnd* cmd;
+   buffer = kmalloc (256, GFP_ATOMIC);
+   cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC);
+
+   memset (buffer, 0, 256);
+   memset (cmd, 0, sizeof(Scsi_Cmnd));
+   cmd->cmnd[0] = INQUIRY;
+   cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0;
+   cmd->cmnd[4] = 0xff;
+   
+   cmd->cmd_len = 6; cmd->old_cmd_len = 6;
+   cmd->host = pACB->pScsiHost;
+   cmd->target = pDCB->UnitSCSIID;
+   cmd->lun = pDCB->UnitSCSILUN; 
+   cmd->serial_number = 1;
+   cmd->bufflen = 128;
+   cmd->buffer = buffer;
+   cmd->request_bufflen = 128;
+   cmd->request_buffer = &buffer[128];
+   cmd->done = dc390_inquiry_done;
+   cmd->scsi_done = dc390_inquiry_done;
+   cmd->timeout_per_command = HZ;
+
+   cmd->request.rq_status = RQ_SCSI_BUSY;
+
+   printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n",
+          pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+   DC390_queue_command (cmd, dc390_inquiry_done);
+};
+
 /********************************************************************
- * Function: tmscsim_set_info()
- *
- * Purpose: Set adapter info (!)
+ * Function: dc390_set_info()
  *
- * Not yet implemented
+ * Purpose: Change adapter config
  *
+ * Strings are parsed similar to the output of tmscsim_proc_info ()
+ * '-' means no change
  *******************************************************************/
 
-int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+static int dc390_scanf (char** p1, char** p2, int* var)
+{
+   *p2 = *p1;
+   *var = simple_strtoul (*p2, p1, 10);
+   if (*p2 == *p1) return -1;
+   *p1 = strtok (0, " \t\n:=,;.");
+   return 0;
+};
+
+#define SCANF(p1, p2, var, min, max)           \
+if (dc390_scanf (&p1, &p2, &var)) goto einv;   \
+else if (var<min || var>max) goto einv2
+
+static int dc390_yesno (char** p, char* var, char bmask)
+{
+   switch (**p)
+     {
+      case 'Y': *var |= bmask; break;
+      case 'N': *var &= ~bmask; break;
+      case '-': break;
+      default: return -1;
+     }
+   *p = strtok (0, " \t\n:=,;");
+   return 0;
+};
+
+#define YESNO(p, var, bmask)                   \
+if (dc390_yesno (&p, &var, bmask)) goto einv;  \
+else dc390_updateDCB (pACB, pDCB);             \
+if (!p) goto ok
+
+static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign)
 {
-  return(-ENOSYS);  /* Currently this is a no-op */
+   int dum;
+   if (! memcmp (*p1, txt, strlen(txt)))
+     {
+       *p2 = strtok (0, " \t\n:=,;");
+       if (!*p2) return -1;
+       dum = simple_strtoul (*p2, p1, 10);
+       if (*p2 == *p1) return -1;
+       if (dum >= 0 && dum <= max) 
+         { *var = (dum * 100) / scale; }
+       else return -2;
+       *p1 = strtok (0, " \t\n:=,;");
+       if (*ign && *p1 && strlen(*p1) >= strlen(ign) && 
+           !(memcmp (*p1, ign, strlen(ign)))) 
+               *p1 = strtok (0, " \t\n:=,;");
+
+     }
+   return 0;
+};
+
+#define SEARCH(p1, p2, var, txt, max)                                          \
+if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2;    \
+else if (!p1) goto ok2
+
+#define SEARCH2(p1, p2, var, txt, max, scale)                                  \
+if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2;            \
+else if (!p1) goto ok2
+
+#define SEARCH3(p1, p2, var, txt, max, scale, ign)                             \
+if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2;           \
+else if (!p1) goto ok2
+
+
+#ifdef DC390_PARSEDEBUG
+static char _prstr[256];
+char* prstr (char* p, char* e)
+{
+   char* c = _prstr;
+   while (p < e)
+     if (*p == 0) { *c++ = ':'; p++; }
+     else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; }
+     else *c++ = *p++;
+   *c = 0;
+   return _prstr;
+};
+#endif
+
+int dc390_set_info (char *buffer, int length, PACB pACB)
+{
+  char *pos = buffer, *p0 = buffer;
+  char needs_inquiry = 0; 
+  int dum = 0;
+  char dev;
+  PDCB pDCB = pACB->pLinkDCB;
+  DC390_IFLAGS
+  DC390_AFLAGS 
+  pos[length] = 0;
+
+  DC390_LOCK_IO;
+  DC390_LOCK_ACB;
+  /* UPPERCASE */ 
+  /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */
+  while (*pos) 
+    { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; };
+  
+  /* We should protect __strtok ! */
+  /* spin_lock (strtok_lock); */
+
+  /* Remove WS */
+  pos = strtok (buffer, " \t:\n=,;");
+  if (!pos) goto ok;
+   
+ next:
+  if (!memcmp (pos, "RESET", 5)) goto reset;
+  else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry;
+  else if (!memcmp (pos, "REMOVE", 6)) goto remove;
+  
+  if (isdigit (*pos))
+    {
+      /* Device config line */
+      int dev, id, lun; char* pdec;
+      char olddevmode;
+      
+      SCANF (pos, p0, dev, 0, pACB->DCBCnt-1);
+      if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
+      if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+      if (!pos) goto einv;
+      
+      PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));)
+      pDCB = pACB->pLinkDCB;
+      for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+      /* Sanity Check */
+      if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun) 
+        {
+           printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n",
+                   dev, id, lun);
+           goto einv2;
+        };
+
+      olddevmode = pDCB->DevMode;
+      YESNO (pos, pDCB->DevMode, PARITY_CHK_);
+      needs_inquiry++;
+      YESNO (pos, pDCB->DevMode, SYNC_NEGO_);
+      if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
+      needs_inquiry++;
+      YESNO (pos, pDCB->DevMode, EN_DISCONNECT_);
+      if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
+      YESNO (pos, pDCB->DevMode, SEND_START_);
+      needs_inquiry++;
+      YESNO (pos, pDCB->DevMode, TAG_QUEUEING_);
+      if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
+      YESNO (pos, pDCB->SyncMode, EN_ATN_STOP);
+      
+      dc390_updateDCB (pACB, pDCB);
+      if (!pos) goto ok;
+       
+      olddevmode = pDCB->NegoPeriod;
+      /* Look for decimal point (Speed) */
+      pdec = pos; 
+      while (pdec++ < &buffer[length]) if (*pdec == '.') break;
+      /* NegoPeriod */
+      if (*pos != '-')
+       {
+         SCANF (pos, p0, dum, 76, 800); 
+         pDCB->NegoPeriod = dum >> 2;
+         if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
+         if (!pos) goto ok;
+         if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;.");
+       }
+      else pos = strtok (0, " \t\n:=,;.");
+      if (!pos) goto ok;
+      
+      /* Speed: NegoPeriod */
+      if (*pos != '-')
+       {
+         SCANF (pos, p0, dum, 1, 13); 
+         pDCB->NegoPeriod = (1000/dum) >> 2;
+         if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
+         if (!pos) goto ok;
+         /* decimal */
+         if (pos-1 == pdec)
+            {
+               int dumold = dum;
+               dum = simple_strtoul (pos, &p0, 10) * 10;
+               for (; p0-pos > 1; p0--) dum /= 10;
+               pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
+               if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
+               if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
+               pos = strtok (0, " \t\n:=,;");
+               if (!pos) goto ok;
+            };
+         if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
+       }
+      else pos = strtok (0, " \t\n:=,;");
+      /* dc390_updateDCB (pACB, pDCB); */
+      if (!pos) goto ok;
+
+      olddevmode = pDCB->SyncOffset;
+      /* SyncOffs */
+      if (*pos != '-')
+       {
+         SCANF (pos, p0, dum, 0, 0x0f); 
+         pDCB->SyncOffset = dum;
+         if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
+       }
+      else pos = strtok (0, " \t\n:=,;");
+      dc390_updateDCB (pACB, pDCB);
+    }
+  else
+    {
+      char* p1 = pos; UCHAR dum;
+      PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
+      dum = GLITCH_TO_NS (pACB->glitch_cfg);
+      /* Adapter setting */
+      SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); 
+      SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); 
+      SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7); 
+      SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
+      SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
+      SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
+      SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
+    ok2:
+      pACB->glitch_cfg = NS_TO_GLITCH (dum);
+      if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
+      dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
+      pACB->TagMaxNum &= (1 << --dum);
+      if (pos == p1) goto einv;
+      dc390_updateDCBs (pACB);
+    }
+  if (pos) goto next;
+      
+ ok:
+  /* spin_unlock (strtok_lock); */
+  DC390_UNLOCK_ACB;
+  if (needs_inquiry) 
+     { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); };
+  DC390_UNLOCK_IO;
+  return (length);
+
+ einv2:
+  pos = p0;
+ einv:
+  /* spin_unlock (strtok_lock); */
+  DC390_UNLOCK_ACB;
+  DC390_UNLOCK_IO;
+  printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
+  return (-EINVAL);
+   
+ reset:
+     {
+       Scsi_Cmnd cmd; cmd.host = pACB->pScsiHost;
+       printk (KERN_WARNING "DC390: Driver reset requested!\n");
+       DC390_UNLOCK_ACB;
+       DC390_reset (&cmd, 0);
+       DC390_UNLOCK_IO;
+     };
+  return (length);
+  
+ inquiry:
+     {
+       pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+       dev = simple_strtoul (pos, &p0, 10);
+       if (dev >= pACB->DCBCnt) goto einv_dev;
+       for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+       printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n",
+               dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+       DC390_UNLOCK_ACB;
+       dc390_inquiry (pACB, pDCB);
+       DC390_UNLOCK_IO;
+     };
+   return (length);
+
+ remove:
+     {
+       pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+       dev = simple_strtoul (pos, &p0, 10);
+       if (dev >= pACB->DCBCnt) goto einv_dev;
+       for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+       printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n",
+               dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+       dc390_remove_dev (pACB, pDCB);
+       DC390_UNLOCK_ACB;
+       DC390_UNLOCK_IO;
+     };
+   return (length);
+
+ einv_dev:
+   printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", 
+          dev, pACB->DCBCnt - 1);
+   DC390_UNLOCK_ACB;
+   DC390_UNLOCK_IO;
+   return (-EINVAL);
+            
+            
 }
 
+#undef SEARCH
+#undef YESNO
+#undef SCANF
+
 /********************************************************************
- * Function: tmscsim_proc_info(char* buffer, char **start,
+ * Function: DC390_proc_info(char* buffer, char **start,
  *                          off_t offset, int length, int hostno, int inout)
  *
  * Purpose: return SCSI Adapter/Device Info
@@ -1491,79+2372,86 @@ int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
 #undef SPRINTF
 #define SPRINTF(args...) pos += sprintf(pos, ## args)
 
-#define YESNO(YN)\
-if (YN) SPRINTF(" Yes ");\
-else SPRINTF(" No  ")
+#define YESNO(YN)              \
+ if (YN) SPRINTF(" Yes ");     \
+ else SPRINTF(" No  ")
+
 
-int tmscsim_proc_info(char *buffer, char **start,
-                     off_t offset, int length, int hostno, int inout)
+int DC390_proc_info (char *buffer, char **start,
+                    off_t offset, int length, int hostno, int inout)
 {
   int dev, spd, spd1;
   char *pos = buffer;
   PSH shpnt;
-  PACB acbpnt;
-  PDCB dcbpnt;
-  unsigned long flags;
-/*  Scsi_Cmnd *ptr; */
+  PACB pACB;
+  PDCB pDCB;
+  DC390_AFLAGS
 
-  acbpnt = pACB_start;
+  pACB = dc390_pACB_start;
 
-  while(acbpnt != (PACB)-1)
+  while(pACB != (PACB)-1)
      {
-       shpnt = acbpnt->pScsiHost;
+       shpnt = pACB->pScsiHost;
        if (shpnt->host_no == hostno) break;
-       acbpnt = acbpnt->pNextACB;
+       pACB = pACB->pNextACB;
      }
 
-  if (acbpnt == (PACB)-1) return(-ESRCH);
+  if (pACB == (PACB)-1) return(-ESRCH);
   if(!shpnt) return(-ESRCH);
 
   if(inout) /* Has data been written to the file ? */
-    return(tmscsim_set_info(buffer, length, shpnt));
+      return dc390_set_info(buffer, length, pACB);
+   
+  SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, ");
+  SPRINTF("Driver Version %s\n", DC390_VERSION);
 
-  SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
-  SPRINTF("Driver Version 1.12, 1998/02/25\n");
-
-  save_flags(flags);
-  cli();
+  DC390_LOCK_ACB;
 
   SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
-  SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
-  SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
-  SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
+  SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex);
+  SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase);
+  SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel);
 
-  SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun);
-  SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
+  SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun);
+  SPRINTF("AdapterID %i, SelTimeout %i ms\n", 
+         shpnt->this_id, (pACB->sel_timeout*164)/100);
 
-  SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
+  SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n",
+         pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12);
 
-  SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
+  SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n",
+         pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB);
+  SPRINTF("            Lost arbitrations %li\n", pACB->SelLost);
+   
+  SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt);
 
-  SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n");
+  SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n");
 
-  dcbpnt = acbpnt->pLinkDCB;
-  for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
+  pDCB = pACB->pLinkDCB;
+  for (dev = 0; dev < pACB->DCBCnt; dev++)
      {
-      SPRINTF("%02i %02i  %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
-      YESNO(dcbpnt->DevMode & PARITY_CHK_);
-      YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE);
-      YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
-      YESNO(dcbpnt->DevMode & SEND_START_);
-      YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
-      SPRINTF("  %03i ns ", (dcbpnt->NegoPeriod) << 2);
-      if (dcbpnt->SyncOffset & 0x0f)
+      SPRINTF("%02i  %02i  %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+      YESNO(pDCB->DevMode & PARITY_CHK_);
+      YESNO(pDCB->SyncMode & SYNC_NEGO_DONE);
+      YESNO(pDCB->DevMode & EN_DISCONNECT_);
+      //YESNO(pDCB->SyncMode & EN_ATN_STOP);
+      YESNO(pDCB->DevMode & SEND_START_);
+      YESNO(pDCB->SyncMode & EN_TAG_QUEUEING);
+      YESNO(pDCB->SyncMode & EN_ATN_STOP);
+      if (pDCB->SyncOffset & 0x0f)
       {
-        spd = 1000/(dcbpnt->NegoPeriod <<2);
-        spd1 = 1000%(dcbpnt->NegoPeriod <<2);
-        spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
-        SPRINTF("   %2i.%1i M      %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
+        int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++;
+        SPRINTF("  %03i ns ", (pDCB->NegoPeriod) << 2);
+        spd = 40/(sp); spd1 = 40%(sp);
+        spd1 = (spd1 * 10 + sp/2) / (sp);
+        SPRINTF("   %2i.%1i M      %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f));
       }
-      else SPRINTF("\n");
+      else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2);
       /* Add more info ...*/
-      dcbpnt = dcbpnt->pNextDCB;
+      pDCB = pDCB->pNextDCB;
      }
 
-  restore_flags(flags);
+  DC390_UNLOCK_ACB;
   *start = buffer + offset;
 
   if (pos - buffer < offset)
@@ -1574,75+2462,92 @@ int tmscsim_proc_info(char *buffer, char **start,
     return length;
 }
 
+#undef YESNO
+#undef SPRINTF
 
 #ifdef MODULE
 
 /***********************************************************************
- * Function : static int DC390_shutdown (struct Scsi_Host *host)
+ * Function : static int dc390_shutdown (struct Scsi_Host *host)
  *
  * Purpose : does a clean (we hope) shutdown of the SCSI chip.
  *          Use prior to dumping core, unloading the driver, etc.
  *
  * Returns : 0 on success
  ***********************************************************************/
-static int
-DC390_shutdown (struct Scsi_Host *host)
+static int dc390_shutdown (struct Scsi_Host *host)
 {
     UCHAR    bval;
-    USHORT   ioport;
-    unsigned long flags;
     PACB pACB = (PACB)(host->hostdata);
-
-    ioport = (unsigned int) pACB->IOPortBase;
-
-    save_flags (flags);
-    cli();
-
+   
 /*  pACB->soft_reset(host); */
 
-#ifdef DC390_DEBUG0
-    printk("DC390: shutdown,");
-#endif
+    printk(KERN_INFO "DC390: shutdown\n");
 
-    bval = inb(ioport+CtrlReg1);
+    pACB->ACBFlag = RESET_DONE;
+    bval = DC390_read8 (CtrlReg1);
     bval |= DIS_INT_ON_SCSI_RST;
-    outb(bval,ioport+CtrlReg1);  /* disable interrupt */
-    DC390_ResetSCSIBus( pACB );
+    DC390_write8 (CtrlReg1, bval);     /* disable interrupt */
+    if (pACB->Gmode2 & RST_SCSI_BUS)
+               dc390_ResetSCSIBus (pACB);
 
-    restore_flags (flags);
     return( 0 );
 }
 
+void dc390_freeDCBs (struct Scsi_Host *host)
+{
+    PDCB pDCB, nDCB;
+    PACB pACB = (PACB)(host->hostdata);
+    
+    pDCB = pACB->pLinkDCB;
+    if (!pDCB) return;
+    do
+    {
+       nDCB = pDCB->pNextDCB;
+       DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\
+               pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
+       kfree (pDCB);
+       pDCB = nDCB;
+    } while (pDCB && pDCB != pACB->pLinkDCB);
+
+};
 
 int DC390_release(struct Scsi_Host *host)
 {
-    int irq_count;
-    struct Scsi_Host *tmp;
+    int irq_count; 
+    PACB pACB;
+    DC390_AFLAGS DC390_IFLAGS
+#if USE_SPINLOCKS > 1
+    PACB pACB = (PACB)(host->hostdata);
+#endif
+
+    DC390_LOCK_IO;
+    DC390_LOCK_ACB;
 
-    DC390_shutdown (host);
+    dc390_shutdown (host);
 
     if (host->irq != IRQ_NONE)
     {
-       for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
+       for (irq_count = 0, pACB = dc390_pACB_start; 
+            pACB && pACB != (PACB)-1; pACB = pACB->pNextACB)
        {
-           if ( tmp->irq == host->irq )
+           if ( pACB->IRQLevel == host->irq )
                ++irq_count;
        }
        if (irq_count == 1)
         {
-#ifdef DC390_DEBUG0
-           printk("DC390: Free IRQ %i.",host->irq);
-#endif
+           DEBUG0(printk(KERN_DEBUG "DC390: Free IRQ %i\n",host->irq);)
            free_irq(host->irq,NULL);
         }
     }
 
     release_region(host->io_port,host->n_io_port);
-
+    dc390_freeDCBs (host);
+    DC390_UNLOCK_ACB;
+    DC390_UNLOCK_IO;
     return( 1 );
 }
 
 Scsi_Host_Template driver_template = DC390_T;
 #include "scsi_module.c"
 #endif /* def MODULE */
-
index bdc5826..6cee558 100644 (file)
 ;*                 TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter  *
 ;*                 Device Driver                                      *
 ;***********************************************************************/
+/* $Id: tmscsim.h,v 2.1 1998/10/14 10:31:48 garloff Exp $ */
 
 #ifndef _TMSCSIM_H
 #define _TMSCSIM_H
 
 #define IRQ_NONE 255
 
+#define MAX_ADAPTER_NUM        4
+#define MAX_SG_LIST_BUF        16
+#define MAX_CMD_PER_LUN        8
+#define MAX_CMD_QUEUE          2*MAX_CMD_PER_LUN+1     
+#define MAX_SCSI_ID            8
+#define MAX_SRB_CNT            MAX_CMD_QUEUE+1 /* Max number of started commands */
+#define END_SCAN               2
+
+#define SEL_TIMEOUT            153     /* 250 ms selection timeout (@ 40 MHz) */
+
 typedef unsigned char  UCHAR;
 typedef unsigned short USHORT;
 typedef unsigned long  ULONG;
@@ -54,17+65,6 @@ ULONG                SGXPtr;
 } SGentry1, *PSGE;
 
 
-#define MAX_ADAPTER_NUM        4
-#define MAX_DEVICES            10
-#define MAX_SG_LIST_BUF        16
-#define MAX_CMD_QUEUE          20
-#define MAX_CMD_PER_LUN        8
-#define MAX_SCSI_ID            8
-#define MAX_SRB_CNT            MAX_CMD_QUEUE+4
-#define END_SCAN               2
-
-#define SEL_TIMEOUT            153     /* 250 ms selection timeout (@ 40 MHz) */
-
 /*
 ;-----------------------------------------------------------------------
 ; SCSI Request Block
@@ -79,40+79,46 @@ struct _DCB *pSRBDCB;
 PSCSICMD       pcmd;
 PSGL           pSegmentList;
 
-ULONG          PhysSRB;
+ULONG          Segment0[2];
+ULONG          Segment1[2];
+
+/* 0x2c:*/
 ULONG          TotalXferredLen;
-ULONG          SGPhysAddr;     /*;a segment starting address */
+ULONG          SGBusAddr;      /*;a segment starting address as seen by AM53C974A*/
 ULONG          SGToBeXferLen;  /*; to be xfer length */
+ULONG          SRBState;
 
+/* 0x3c: */
+UCHAR          MsgInBuf[6];
+UCHAR          MsgOutBuf[6];
+
+/* 0x48: */
 SGL            Segmentx;       /* make a one entry of S/G list table */
 
 PUCHAR         pMsgPtr;
-USHORT         SRBState;
-USHORT         Revxx2;         /* ??? */
 
-UCHAR          MsgInBuf[6];
-UCHAR          MsgOutBuf[6];
+UCHAR          ScsiCmdLen;
+UCHAR          ScsiPhase;
 
 UCHAR          AdaptStatus;
 UCHAR          TargetStatus;
+
+/* 0x5c: */
 UCHAR          MsgCnt;
 UCHAR          EndMessage;
+UCHAR          RetryCnt;
+UCHAR          SRBFlag;        /*; b0-AutoReqSense,b6-Read,b7-write */
+                               /*; b4-settimeout,b5-Residual valid */
 UCHAR          TagNumber;
 UCHAR          SGcount;
 UCHAR          SGIndex;
-UCHAR          IORBFlag;       /*;81h-Reset, 2-retry */
-
 UCHAR          SRBStatus;
-UCHAR          RetryCnt;
-UCHAR          SRBFlag;        /*; b0-AutoReqSense,b6-Read,b7-write */
-                               /*; b4-settimeout,b5-Residual valid */
-UCHAR          ScsiCmdLen;
-UCHAR          ScsiPhase;
-UCHAR          Reserved3[3];   /*;for dword alignment */
-ULONG          Segment0[2];
-ULONG          Segment1[2];
+  //UCHAR              IORBFlag;       /*;81h-Reset, 2-retry */
+
+/* 0x64: */
 };
 
+
 typedef  struct  _SRB   DC390_SRB, *PSRB;
 
 /*
@@ -129,42+135,44 @@ PSCSICMD  pQIORBhead;
 PSCSICMD       pQIORBtail;
 PSCSICMD       AboIORBhead;
 PSCSICMD       AboIORBtail;
-USHORT         QIORBCnt;
-USHORT         AboIORBcnt;
+ULONG          QIORBCnt;
+ULONG          AboIORBcnt;
 
+/* 0x20: */
 PSRB           pWaitingSRB;
 PSRB           pWaitLast;
 PSRB           pGoingSRB;
 PSRB           pGoingLast;
 PSRB           pActiveSRB;
-USHORT         GoingSRBCnt;
-USHORT         WaitSRBCnt;     /* ??? */
+UCHAR          GoingSRBCnt;
+UCHAR          WaitSRBCnt;     /* ??? */
+UCHAR          DevType;
+UCHAR          MaxCommand;
 
+/* 0x38: */
 ULONG          TagMask;
 
-USHORT         MaxCommand;
-USHORT         AdaptIndex;     /*; UnitInfo struc start */
-USHORT         UnitIndex;      /*; nth Unit on this card */
 UCHAR          UnitSCSIID;     /*; SCSI Target ID  (SCSI Only) */
 UCHAR          UnitSCSILUN;    /*; SCSI Log.  Unit (SCSI Only) */
-
+UCHAR          DevMode;
 UCHAR          IdentifyMsg;
+
 UCHAR          CtrlR1;
 UCHAR          CtrlR3;
 UCHAR          CtrlR4;
 
-UCHAR          InqDataBuf[8];
-UCHAR          CapacityBuf[8];
-UCHAR          DevMode;
-UCHAR          AdpMode;
+UCHAR          DCBFlag;
+
+/* 0x44: */
 UCHAR          SyncMode;       /*; 0:async mode */
 UCHAR          NegoPeriod;     /*;for nego. */
 UCHAR          SyncPeriod;     /*;for reg. */
 UCHAR          SyncOffset;     /*;for reg. and nego.(low nibble) */
-UCHAR          UnitCtrlFlag;
-UCHAR          DCBFlag;
-UCHAR          DevType;
-UCHAR          Reserved2[3];   /*;for dword alignment */
+
+/* 0x48:*/
+//UCHAR                InqDataBuf[8];
+//UCHAR                CapacityBuf[8];
+/* 0x58: */
 };
 
 typedef  struct  _DCB   DC390_DCB, *PDCB;
@@ -175,40+183,55 @@ typedef  struct  _DCB      DC390_DCB, *PDCB;
 */
 struct _ACB
 {
-ULONG          PhysACB;
 PSH            pScsiHost;
 struct _ACB    *pNextACB;
 USHORT         IOPortBase;
-USHORT         Revxx1;         /* ??? */
+UCHAR          IRQLevel;
+UCHAR          status;
+
+UCHAR          SRBCount;
+UCHAR          AdapterIndex;   /*; nth Adapter this driver */
+UCHAR          DeviceCnt;
+UCHAR          DCBCnt;
+
+/* 0x10: */
+UCHAR          TagMaxNum;
+UCHAR          ACBFlag;
+UCHAR          Gmode2;
+UCHAR          scan_devices;
 
 PDCB           pLinkDCB;
+PDCB           pLastDCB;
 PDCB           pDCBRunRobin;
 PDCB           pActiveDCB;
-PDCB           pDCB_free;
 PSRB           pFreeSRB;
 PSRB           pTmpSRB;
-USHORT         SRBCount;
-USHORT         AdapterIndex;   /*; nth Adapter this driver */
-USHORT         max_id;
-USHORT         max_lun;
+
+/* 0x2c: */
 
 UCHAR          msgin123[4];
-UCHAR          status;
-UCHAR          AdaptSCSIID;    /*; Adapter SCSI Target ID */
-UCHAR          AdaptSCSILUN;   /*; Adapter SCSI LUN */
-UCHAR          DeviceCnt;
-UCHAR          IRQLevel;
-UCHAR          TagMaxNum;
-UCHAR          ACBFlag;
-UCHAR          Gmode2;
-UCHAR          LUNchk;
-UCHAR          scan_devices;
-UCHAR          HostID_Bit;
-UCHAR          Reserved1[1];   /*;for dword alignment */
 UCHAR          DCBmap[MAX_SCSI_ID];
-DC390_DCB      DCB_array[MAX_DEVICES];         /* +74h,  Len=3E8 */
-DC390_SRB      SRB_array[MAX_SRB_CNT];         /* +45Ch, Len=  */
+
+#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0)
+spinlock_t     lock;
+#endif
+UCHAR          sel_timeout;
+UCHAR          glitch_cfg;
+
+UCHAR          reserved[2];    /* alignment */
+
+PDEVDECL1;                     /* Pointer to PCI cfg. space */
+/* 0x44/0x40: */
+ULONG          Cmds;
+ULONG          CmdInQ;
+ULONG          CmdOutOfSRB;
+ULONG          SelLost;
+       
+/* 0x50/0x4c: */       
 DC390_SRB      TmpSRB;
+/* 0xb4/0xb0: */
+DC390_SRB      SRB_array[MAX_SRB_CNT];         /* 18 SRBs */
+/* 0x7bc/0x7b8: */
 };
 
 typedef  struct  _ACB   DC390_ACB, *PACB;
@@ -278,14+301,6 @@ typedef  struct  _ACB       DC390_ACB, *PACB;
 #define DO_SYNC_NEGO   BIT13
 #define SRB_UNEXPECT_RESEL BIT14
 
-/*;---ACBFlag */
-#define RESET_DEV      BIT0
-#define RESET_DETECT   BIT1
-#define RESET_DONE     BIT2
-
-/*;---DCBFlag */
-#define ABORT_DEV_     BIT0
-
 /*;---SRBstatus */
 #define SRB_OK         BIT0
 #define ABORTION       BIT1
@@ -294,6+309,14 @@ typedef  struct  _ACB       DC390_ACB, *PACB;
 #define PARITY_ERROR   BIT4
 #define SRB_ERROR      BIT5
 
+/*;---ACBFlag */
+#define RESET_DEV      BIT0
+#define RESET_DETECT   BIT1
+#define RESET_DONE     BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_     BIT0
+
 /*;---SRBFlag */
 #define DATAOUT        BIT7
 #define DATAIN         BIT6
@@ -316,7+339,7 @@ typedef  struct  _ACB        DC390_ACB, *PACB;
 #define H_BAD_CCB_OR_SG  0x1A
 #define H_ABORT         0x0FF
 
-/*; SCSI Status byte codes*/
+/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */
 #define SCSI_STAT_GOOD         0x0     /*;  Good status */
 #define SCSI_STAT_CHECKCOND    0x02    /*;  SCSI Check Condition */
 #define SCSI_STAT_CONDMET      0x04    /*;  Condition Met */
@@ -335,9+358,9 @@ typedef  struct  _ACB        DC390_ACB, *PACB;
 #define SYNC_DISABLE   0
 #define SYNC_ENABLE    BIT0
 #define SYNC_NEGO_DONE BIT1
-#define WIDE_ENABLE    BIT2
-#define WIDE_NEGO_DONE BIT3
-#define EN_TAG_QUEUING BIT4
+#define WIDE_ENABLE    BIT2    /* Not used ;-) */
+#define WIDE_NEGO_DONE BIT3    /* Not used ;-) */
+#define EN_TAG_QUEUEING        BIT4
 #define EN_ATN_STOP    BIT5
 
 #define SYNC_NEGO_OFFSET 15
@@ -352,7+375,7 @@ typedef  struct  _ACB        DC390_ACB, *PACB;
 #define SCSI_MSG_OUT   6
 #define SCSI_MSG_IN    7
 
-/*;----SCSI MSG BYTE*/
+/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */
 #define MSG_COMPLETE           0x00
 #define MSG_EXTENDED           0x01
 #define MSG_SAVE_PTR           0x02
@@ -373,13+396,6 @@ typedef  struct  _ACB       DC390_ACB, *PACB;
 #define MSG_IDENTIFY           0x80
 #define MSG_HOST_ID            0x0C0
 
-/*;----SCSI STATUS BYTE*/
-#define STATUS_GOOD            0x00
-#define CHECK_CONDITION_       0x02
-#define STATUS_BUSY            0x08
-#define STATUS_INTERMEDIATE    0x10
-#define RESERVE_CONFLICT       0x18
-
 /* cmd->result */
 #define STATUS_MASK_           0xFF
 #define MSG_MASK               0xFF00
@@ -389,7+405,7 @@ typedef  struct  _ACB        DC390_ACB, *PACB;
 **  Inquiry Data format
 */
 
-typedef struct _SCSIInqData { /* INQ */
+typedef struct _SCSIInqData { /* INQUIRY */
 
        UCHAR    DevType;               /* Periph Qualifier & Periph Dev Type*/
        UCHAR    RMB_TypeMod;           /* rem media bit & Dev Type Modifier */
@@ -412,6+428,7 @@ typedef struct      _SCSIInqData { /* INQ */
 
 #define SCSI_DEVTYPE       0x1F      /* Peripheral Device Type             */
 #define SCSI_PERIPHQUAL     0xE0      /* Peripheral Qualifier              */
+#define TYPE_NODEV         SCSI_DEVTYPE    /* Unknown or no device type    */
 
 
 /*  Inquiry byte 1 mask */
@@ -420,18+437,10 @@ typedef struct    _SCSIInqData { /* INQ */
 
 
 /*  Peripheral Device Type definitions */
+/*  see include/scsi/scsi.h for the rest */
 
-#define SCSI_DASD               0x00      /* Direct-access Device         */
-#define SCSI_SEQACESS           0x01      /* Sequential-access device     */
-#define SCSI_PRINTER            0x02      /* Printer device               */
-#define SCSI_PROCESSOR          0x03      /* Processor device             */
-#define SCSI_WRITEONCE          0x04      /* Write-once device            */
-#define SCSI_CDROM              0x05      /* CD-ROM device                */
-#define SCSI_SCANNER            0x06      /* Scanner device               */
-#define SCSI_OPTICAL            0x07      /* Optical memory device        */
-#define SCSI_MEDCHGR            0x08      /* Medium changer device        */
-#define SCSI_COMM               0x09      /* Communications device        */
-#define SCSI_NODEV              0x1F      /* Unknown or no device type    */
+#define TYPE_PRINTER            0x02      /* Printer device               */
+#define TYPE_COMM               0x09      /* Communications device        */
 
 /*
 ** Inquiry flag definitions (Inq data byte 7)
@@ -459,17+468,24 @@ UCHAR     xx1;
 UCHAR  xx2;
 } EEprom, *PEEprom;
 
-#define EE_ADAPT_SCSI_ID 64
-#define EE_MODE2       65
-#define EE_DELAY       66
-#define EE_TAG_CMD_NUM 67
+#define REAL_EE_ADAPT_SCSI_ID 64
+#define REAL_EE_MODE2  65
+#define REAL_EE_DELAY  66
+#define REAL_EE_TAG_CMD_NUM    67
+
+#define EE_ADAPT_SCSI_ID 32
+#define EE_MODE2       33
+#define EE_DELAY       34
+#define EE_TAG_CMD_NUM 35
+
+#define EE_LEN         40
 
 /*; EE_MODE1 bits definition*/
 #define PARITY_CHK_    BIT0
 #define SYNC_NEGO_     BIT1
 #define EN_DISCONNECT_ BIT2
 #define SEND_START_    BIT3
-#define TAG_QUEUING_   BIT4
+#define TAG_QUEUEING_  BIT4
 
 /*; EE_MODE2 bits definition*/
 #define MORE2_DRV      BIT0
@@ -494,34+510,42 @@ UCHAR     xx2;
 ;====================
 */
 
-/*; Command Reg.(+0CH) */
+/*; Command Reg.(+0CH) (rw) */
 #define DMA_COMMAND            BIT7
 #define NOP_CMD                0
 #define CLEAR_FIFO_CMD         1
 #define RST_DEVICE_CMD         2
 #define RST_SCSI_BUS_CMD       3
+
 #define INFO_XFER_CMD          0x10
 #define INITIATOR_CMD_CMPLTE   0x11
 #define MSG_ACCEPTED_CMD       0x12
 #define XFER_PAD_BYTE          0x18
 #define SET_ATN_CMD            0x1A
 #define RESET_ATN_CMD          0x1B
-#define SELECT_W_ATN           0x42
+
+#define SEL_WO_ATN             0x41    /* currently not used */
+#define SEL_W_ATN              0x42
 #define SEL_W_ATN_STOP         0x43
+#define SEL_W_ATN3             0x46
 #define EN_SEL_RESEL           0x44
-#define SEL_W_ATN2             0x46
+#define DIS_SEL_RESEL          0x45    /* currently not used */
+#define RESEL                  0x40    /* " */
+#define RESEL_ATN3             0x47    /* " */
+
 #define DATA_XFER_CMD          INFO_XFER_CMD
 
 
-/*; SCSI Status Reg.(+10H) */
+/*; SCSI Status Reg.(+10H) (r) */
 #define INTERRUPT              BIT7
 #define ILLEGAL_OP_ERR         BIT6
 #define PARITY_ERR             BIT5
 #define COUNT_2_ZERO           BIT4
 #define GROUP_CODE_VALID       BIT3
-#define SCSI_PHASE_MASK        (BIT2+BIT1+BIT0)
+#define SCSI_PHASE_MASK        (BIT2+BIT1+BIT0) 
+/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */
 
-/*; Interrupt Status Reg.(+14H) */
+/*; Interrupt Status Reg.(+14H) (r) */
 #define SCSI_RESET             BIT7
 #define INVALID_CMD            BIT6
 #define DISCONNECTED           BIT5
@@ -531,11+555,12 @@ UCHAR     xx2;
 #define SEL_ATTENTION          BIT1
 #define SELECTED               BIT0
 
-/*; Internal State Reg.(+18H) */
+/*; Internal State Reg.(+18H) (r) */
 #define SYNC_OFFSET_FLAG       BIT3
 #define INTRN_STATE_MASK       (BIT2+BIT1+BIT0)
+/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */
 
-/*; Clock Factor Reg.(+24H) */
+/*; Clock Factor Reg.(+24H) (w) */
 #define CLK_FREQ_40MHZ         0
 #define CLK_FREQ_35MHZ         (BIT2+BIT1+BIT0)
 #define CLK_FREQ_30MHZ         (BIT2+BIT1)
@@ -544,47+569,54 @@ UCHAR     xx2;
 #define CLK_FREQ_15MHZ         (BIT1+BIT0)
 #define CLK_FREQ_10MHZ         BIT1
 
-/*; Control Reg. 1(+20H) */
+/*; Control Reg. 1(+20H) (rw) */
 #define EXTENDED_TIMING        BIT7
 #define DIS_INT_ON_SCSI_RST    BIT6
 #define PARITY_ERR_REPO        BIT4
-#define SCSI_ID_ON_BUS         (BIT2+BIT1+BIT0)
+#define SCSI_ID_ON_BUS         (BIT2+BIT1+BIT0) /* host adapter ID */
 
-/*; Control Reg. 2(+2CH) */
+/*; Control Reg. 2(+2CH) (rw) */
 #define EN_FEATURE             BIT6
 #define EN_SCSI2_CMD           BIT3
 
-/*; Control Reg. 3(+30H) */
+/*; Control Reg. 3(+30H) (rw) */
 #define ID_MSG_CHECK           BIT7
 #define EN_QTAG_MSG            BIT6
 #define EN_GRP2_CMD            BIT5
 #define FAST_SCSI              BIT4    /* ;10MB/SEC */
 #define FAST_CLK               BIT3    /* ;25 - 40 MHZ */
 
-/*; Control Reg. 4(+34H) */
+/*; Control Reg. 4(+34H) (rw) */
 #define EATER_12NS             0
 #define EATER_25NS             BIT7
 #define EATER_35NS             BIT6
 #define EATER_0NS              (BIT7+BIT6)
+#define REDUCED_POWER          BIT5
+#define CTRL4_RESERVED         BIT4    /* must be 1 acc. to AM53C974.c */
 #define NEGATE_REQACKDATA      BIT2
 #define NEGATE_REQACK          BIT3
+
+#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2)))
+#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0)
+
 /*
 ;====================
 ; DMA Register
 ;====================
 */
-/*; DMA Command Reg.(+40H) */
+/*; DMA Command Reg.(+40H) (rw) */
 #define READ_DIRECTION         BIT7
 #define WRITE_DIRECTION        0
 #define EN_DMA_INT             BIT6
-#define MAP_TO_MDL             BIT5
-#define DIAGNOSTIC             BIT4
+#define EN_PAGE_INT            BIT5    /* page transfer interrupt enable */
+#define MAP_TO_MDL             BIT4
+#define DIAGNOSTIC             BIT2
 #define DMA_IDLE_CMD           0
 #define DMA_BLAST_CMD          BIT0
 #define DMA_ABORT_CMD          BIT1
 #define DMA_START_CMD          (BIT1+BIT0)
 
-/*; DMA Status Reg.(+54H) */
+/*; DMA Status Reg.(+54H) (r) */
 #define PCI_MS_ABORT           BIT6
 #define BLAST_COMPLETE         BIT5
 #define SCSI_INTERRUPT         BIT4
@@ -593,71+625,77 @@ UCHAR     xx2;
 #define DMA_XFER_ERROR         BIT1
 #define POWER_DOWN             BIT0
 
-/*
-; DMA SCSI Bus and Ctrl.(+70H)
-;EN_INT_ON_PCI_ABORT
-*/
+/*; DMA SCSI Bus and Ctrl.(+70H) */
+#define EN_INT_ON_PCI_ABORT    BIT25
+#define WRT_ERASE_DMA_STAT     BIT24
+#define PW_DOWN_CTRL           BIT21
+#define SCSI_BUSY              BIT20
+#define SCLK                   BIT19
+#define SCAM                   BIT18
+#define SCSI_LINES             0x0003ffff
 
 /*
 ;==========================================================
 ; SCSI Chip register address offset
 ;==========================================================
+;Registers are rw unless declared otherwise 
 */
-#define CtcReg_Low     0x00
-#define CtcReg_Mid     0x04
+#define CtcReg_Low     0x00    /* r    curr. transfer count */
+#define CtcReg_Mid     0x04    /* r */
+#define CtcReg_High    0x38    /* r */
 #define ScsiFifo       0x08
 #define ScsiCmd        0x0C
-#define Scsi_Status    0x10
-#define INT_Status     0x14
-#define Sync_Period    0x18
-#define Sync_Offset    0x1C
-#define CtrlReg1       0x20
-#define Clk_Factor     0x24
+#define Scsi_Status    0x10    /* r */
+#define INT_Status     0x14    /* r */
+#define Sync_Period    0x18    /* w */
+#define Sync_Offset    0x1C    /* w */
+#define Clk_Factor     0x24    /* w */
+#define CtrlReg1       0x20    
 #define CtrlReg2       0x2C
 #define CtrlReg3       0x30
 #define CtrlReg4       0x34
-#define CtcReg_High    0x38
 #define DMA_Cmd        0x40
-#define DMA_XferCnt    0x44
-#define DMA_XferAddr   0x48
-#define DMA_Wk_ByteCntr 0x4C
-#define DMA_Wk_AddrCntr 0x50
-#define DMA_Status     0x54
-#define DMA_MDL_Addr   0x58
-#define DMA_Wk_MDL_Cntr 0x5C
-#define DMA_ScsiBusCtrl 0x70
-
-#define StcReg_Low     CtcReg_Low
-#define StcReg_Mid     CtcReg_Mid
-#define Scsi_Dest_ID   Scsi_Status
-#define Scsi_TimeOut   INT_Status
-#define Intern_State   Sync_Period
-#define Current_Fifo   Sync_Offset
-#define StcReg_High    CtcReg_High
-
-#define am_target      Scsi_Status
-#define am_timeout     INT_Status
-#define am_seq_step    Sync_Period
-#define am_fifo_count  Sync_Offset
-
-
-#define DC390_read8(address)                          \
-       inb(DC390_ioport + (address)))
-
-#define DC390_read16(address)                         \
-       inw(DC390_ioport + (address)))
-
-#define DC390_read32(address)                         \
-       inl(DC390_ioport + (address)))
-
-#define DC390_write8(address,value)                   \
-       outb((value), DC390_ioport + (address)))
-
-#define DC390_write16(address,value)                  \
-       outw((value), DC390_ioport + (address)))
-
-#define DC390_write32(address,value)                  \
-       outl((value), DC390_ioport + (address)))
+#define DMA_XferCnt    0x44    /* rw   starting transfer count (32 bit) */
+#define DMA_XferAddr   0x48    /* rw   starting physical address (32 bit) */
+#define DMA_Wk_ByteCntr 0x4C   /* r    working byte counter */
+#define DMA_Wk_AddrCntr 0x50   /* r    working address counter */
+#define DMA_Status     0x54    /* r */
+#define DMA_MDL_Addr   0x58    /* rw   starting MDL address */
+#define DMA_Wk_MDL_Cntr 0x5C   /* r    working MDL counter */
+#define DMA_ScsiBusCtrl 0x70   /* rw   SCSI Bus, PCI/DMA Ctrl */
+
+#define StcReg_Low     CtcReg_Low      /* w    start transfer count */
+#define StcReg_Mid     CtcReg_Mid      /* w */
+#define StcReg_High    CtcReg_High     /* w */
+#define Scsi_Dest_ID   Scsi_Status     /* w */
+#define Scsi_TimeOut   INT_Status      /* w */
+#define Intern_State   Sync_Period     /* r */
+#define Current_Fifo   Sync_Offset     /* r    Curr. FIFO / int. state */
+
+
+#define DC390_read8(address)                   \
+       (inb (pACB->IOPortBase + (address)))
+
+#define DC390_read8_(address, base)            \
+       (inb ((USHORT)(base) + (address)))
+
+#define DC390_read16(address)                  \
+       (inw (pACB->IOPortBase + (address)))
+
+#define DC390_read32(address)                  \
+       (inl (pACB->IOPortBase + (address)))
+
+#define DC390_write8(address,value)            \
+       outb ((value), pACB->IOPortBase + (address))
+
+#define DC390_write8_(address,value,base)      \
+       outb ((value), (USHORT)(base) + (address))
+
+#define DC390_write16(address,value)           \
+       outw ((value), pACB->IOPortBase + (address))
+
+#define DC390_write32(address,value)           \
+       outl ((value), pACB->IOPortBase + (address))
 
 
 #endif /* _TMSCSIM_H */
index 56af7f9..3d91302 100644 (file)
@@ -2,7+2,7 @@
  *   
  * linux/fs/autofs/autofs_i.h
  *
- *   Copyright 1997 Transmeta Corporation - All Rights Reserved
+ *   Copyright 1997-1998 Transmeta Corporation - All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
 
 struct autofs_dir_ent {
        int hash;
-       struct autofs_dir_ent *next;
-       struct autofs_dir_ent **back;
        char *name;
        int len;
        ino_t ino;
+       struct dentry *dentry;
+       /* Linked list of entries */
+       struct autofs_dir_ent *next;
+       struct autofs_dir_ent **back;
        /* The following entries are for the expiry system */
        unsigned long last_usage;
        struct autofs_dir_ent *exp_next;
@@ -123,7+125,7 @@ void autofs_initialize_hash(struct autofs_dirhash *);
 struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,struct qstr *);
 void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
 void autofs_hash_delete(struct autofs_dir_ent *);
-struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
+struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *,struct autofs_dir_ent *);
 void autofs_hash_nuke(struct autofs_dirhash *);
 
 /* Expiration-handling functions */
index 67b2c04..63efe9b 100644 (file)
@@ -2,7+2,7 @@
  *
  * linux/fs/autofs/dir.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
index bd9f33a..2fd6594 100644 (file)
@@ -59,13+59,11 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
                        return ent; /* Symlinks are always expirable */
 
                /* Get the dentry for the autofs subdirectory */
-               dentry = lookup_dentry(ent->name, dget(sb->s_root), 0);
+               dentry = ent->dentry;
 
-               if ( IS_ERR(dentry) ) {
-                       printk("autofs: no such dentry on expiry queue: %s\n",
-                              ent->name);
+               if ( !dentry ) {
+                       printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name);
                        autofs_delete_usage(ent);
-                       continue;
                }
 
                if ( !dentry->d_inode ) {
@@ -79,24+77,12 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
                /* Make sure entry is mounted and unused; note that dentry will
                   point to the mounted-on-top root. */
                if ( !S_ISDIR(dentry->d_inode->i_mode)
-                    || dentry->d_covers == dentry ) {
-                       dput(dentry);
+                    || dentry->d_mounts == dentry ) {
                        DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
                        continue;
                }
 
-               /*
-                * Now, this is known to be a mount point; therefore the dentry
-                * will be held by the superblock.  is_root_busy() will break if
-                * we hold a use count here, so we have to dput() it before calling
-                * is_root_busy().  However, since it is a mount point (already
-                * verified), dput() will be a nonblocking operation and the use
-                * count will not go to zero; therefore the call to is_root_busy()
-                * here is legal.
-                */
-               dput(dentry);
-
-               if ( !is_root_busy(dentry) ) {
+               if ( !is_root_busy(dentry->d_mounts) ) {
                        DPRINTK(("autofs: signaling expire on %s\n", ent->name));
                        return ent; /* Expirable! */
                }
@@ -136,6+122,8 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
        autofs_say(ent->name,ent->len);
 
        autofs_init_usage(dh,ent);
+       if ( ent->dentry )
+               ent->dentry->d_count++;
 
        dhnp = &dh->h[(unsigned) ent->hash % AUTOFS_HASH_SIZE];
        ent->next = *dhnp;
@@ -153,6+141,8 @@ void autofs_hash_delete(struct autofs_dir_ent *ent)
 
        autofs_delete_usage(ent);
 
+       if ( ent->dentry )
+               dput(ent->dentry);
        kfree(ent->name);
        kfree(ent);
 }
@@ -161,8+151,12 @@ void autofs_hash_delete(struct autofs_dir_ent *ent)
  * Used by readdir().  We must validate "ptr", so we can't simply make it
  * a pointer.  Values below 0xffff are reserved; calling with any value
  * <= 0x10000 will return the first entry found.
+ *
+ * "last" can be NULL or the value returned by the last search *if* we
+ * want the next sequential entry.
  */
-struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, off_t *ptr)
+struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh,
+                                       off_t *ptr, struct autofs_dir_ent *last)
 {
        int bucket, ecount, i;
        struct autofs_dir_ent *ent;
@@ -176,19+170,23 @@ struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, off_t *
 
        DPRINTK(("autofs_hash_enum: bucket %d, entry %d\n", bucket, ecount));
 
-       ent = NULL;
-
-       while  ( bucket < AUTOFS_HASH_SIZE ) {
-               ent = dh->h[bucket];
-               for ( i = ecount ; ent && i ; i-- )
-                       ent = ent->next;
-
-               if (ent) {
-                       ecount++; /* Point to *next* entry */
-                       break;
+       ent = last ? last->next : NULL;
+
+       if ( ent ) {
+               ecount++;
+       } else {
+               while  ( bucket < AUTOFS_HASH_SIZE ) {
+                       ent = dh->h[bucket];
+                       for ( i = ecount ; ent && i ; i-- )
+                               ent = ent->next;
+                       
+                       if (ent) {
+                               ecount++; /* Point to *next* entry */
+                               break;
+                       }
+                       
+                       bucket++; ecount = 0;
                }
-
-               bucket++; ecount = 0;
        }
 
 #ifdef DEBUG
@@ -214,6+212,8 @@ void autofs_hash_nuke(struct autofs_dirhash *dh)
        for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
                for ( ent = dh->h[i] ; ent ; ent = nent ) {
                        nent = ent->next;
+                       if ( ent->dentry )
+                               dput(ent->dentry);
                        kfree(ent->name);
                        kfree(ent);
                }
index 7c05082..2afca05 100644 (file)
@@ -2,7+2,7 @@
  *
  * linux/fs/autofs/init.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
index d171152..8461645 100644 (file)
@@ -2,7+2,7 @@
  *
  * linux/fs/autofs/inode.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
index 41694e8..89acd37 100644 (file)
@@ -2,7+2,7 @@
  *
  * linux/fs/autofs/root.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -66,7+66,7 @@ struct inode_operations autofs_root_inode_operations = {
 
 static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-       struct autofs_dir_ent *ent;
+       struct autofs_dir_ent *ent = NULL;
        struct autofs_dirhash *dirhash;
        struct inode * inode = filp->f_dentry->d_inode;
        off_t onr, nr;
@@ -90,10+90,12 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
                filp->f_pos = ++nr;
                /* fall through */
        default:
-               while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr) ) {
-                       if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
-                               return 0;
-                       filp->f_pos = nr;
+               while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
+                       if ( !ent->dentry || ent->dentry->d_mounts != ent->dentry ) {
+                               if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
+                                       return 0;
+                               filp->f_pos = nr;
+                       }
                }
                break;
        }
@@ -110,8+112,8 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
        if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
                do {
                        if ( status && dentry->d_inode ) {
-                               printk("autofs warning: lookup failure on existing dentry, status = %d, name = %s\n", status, dentry->d_name.name);
-                               break;
+                               printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
+                               return 0; /* Try to get the kernel to invalidate this dentry */
                        }
 
                        /* Turn this into a real negative dentry? */
@@ -148,8+150,9 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
 
        /* We don't update the usages for the autofs daemon itself, this
           is necessary for recursive autofs mounts */
-       if ( !autofs_oz_mode(sbi) )
+       if ( !autofs_oz_mode(sbi) ) {
                autofs_update_usage(&sbi->dirhash,ent);
+       }
 
        dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
        return 1;
@@ -193,7+196,8 @@ static int autofs_revalidate(struct dentry * dentry)
        /* Update the usage list */
        if ( !autofs_oz_mode(sbi) ) {
                ent = (struct autofs_dir_ent *) dentry->d_time;
-               autofs_update_usage(&sbi->dirhash,ent);
+               if ( ent )
+                       autofs_update_usage(&sbi->dirhash,ent);
        }
        return 1;
 }
@@ -207,7+211,6 @@ static struct dentry_operations autofs_dentry_operations = {
 static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
 {
        struct autofs_sb_info *sbi;
-       struct inode *res;
        int oz_mode;
 
        DPRINTK(("autofs_root_lookup: name = "));
@@ -216,7+219,6 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
        if (!S_ISDIR(dir->i_mode))
                return -ENOTDIR;
 
-       res = NULL;
        sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
 
        oz_mode = autofs_oz_mode(sbi);
@@ -249,6+251,15 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
                        return -ERESTARTNOINTR;
        }
 
+       /*
+        * If this dentry is unhashed, then we shouldn't honour this
+        * lookup even if the dentry is positive.  Returning ENOENT here
+        * doesn't do the right thing for all system calls, but it should
+        * be OK for the operations we permit from an autofs.
+        */
+       if ( dentry->d_inode && list_empty(&dentry->d_hash) )
+               return -ENOENT;
+
        return 0;
 }
 
@@ -304,6+315,7 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
        ent->ino = AUTOFS_FIRST_SYMLINK + n;
        ent->hash = dentry->d_name.hash;
        memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len));
+       ent->dentry = NULL;     /* We don't keep the dentry for symlinks */
 
        autofs_hash_insert(dh,ent);
        d_instantiate(dentry, iget(dir->i_sb,ent->ino));
@@ -339,7+351,8 @@ static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
        n = ent->ino - AUTOFS_FIRST_SYMLINK;
        if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap) )
                return -EINVAL; /* Not a symlink inode, can't unlink */
-
+       
+       dentry->d_time = (unsigned long)(struct autofs_dirhash *)NULL;
        autofs_hash_delete(ent);
        clear_bit(n,sbi->symlink_bitmap);
        kfree(sbi->symlink[n].data);
@@ -364,6+377,11 @@ static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)
        if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO )
                return -ENOTDIR; /* Not a directory */
 
+       if ( ent->dentry != dentry ) {
+               printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name);
+       }
+
+       dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL;
        autofs_hash_delete(ent);
        dir->i_nlink--;
        d_drop(dentry);
@@ -399,12+417,14 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                return -ENOSPC;
        }
 
+       dir->i_nlink++;
+       d_instantiate(dentry, iget(dir->i_sb,ent->ino));
+
        ent->hash = dentry->d_name.hash;
        memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len));
        ent->ino = sbi->next_dir_ino++;
+       ent->dentry = dentry;
        autofs_hash_insert(dh,ent);
-       dir->i_nlink++;
-       d_instantiate(dentry, iget(dir->i_sb,ent->ino));
 
        return 0;
 }
index 00ea2df..a4cb515 100644 (file)
@@ -2,7+2,7 @@
  *
  * linux/fs/autofs/symlink.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
index 607b431..7ac28e2 100644 (file)
@@ -2,7+2,7 @@
  *
  * linux/fs/autofs/waitq.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
    is better if we don't reassign numbers easily even across filesystems */
 static int autofs_next_wait_queue = 1;
 
+/* These are the signals we allow interrupting a pending mount */
+#define SHUTDOWN_SIGS  (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
+
 void autofs_catatonic_mode(struct autofs_sb_info *sbi)
 {
        struct autofs_wait_queue *wq, *nwq;
@@ -133,9+136,25 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name)
        } else
                wq->wait_ctr++;
 
+       /* wq->name is NULL if and only if the lock is already released */
+
        if ( wq->name ) {
-               /* wq->name is NULL if and only if the lock is released */
+               /* Block all but "shutdown" signals while waiting */
+               sigset_t oldset;
+               unsigned long irqflags;
+
+               spin_lock_irqsave(&current->sigmask_lock, irqflags);
+               oldset = current->blocked;
+               siginitsetinv(&current->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
+               recalc_sigpending(current);
+               spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+
                interruptible_sleep_on(&wq->queue);
+
+               spin_lock_irqsave(&current->sigmask_lock, irqflags);
+               current->blocked = oldset;
+               recalc_sigpending(current);
+               spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
        } else {
                DPRINTK(("autofs_wait: skipped sleeping\n"));
        }
index de08cf1..8be2fc4 100644 (file)
@@ -608,7+608,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
           base, as well as whatever program they might try to exec.  This
           is because the brk will follow the loader, and is not movable.  */
 
-       load_bias = (elf_ex.e_type == ET_DYN ? ELF_ET_DYN_BASE : 0);
+       load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0);
 
        /* Now we do a little grungy work by mmaping the ELF image into
           the correct location in memory.  At this point, we assume that
@@ -618,51+618,50 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        old_fs = get_fs();
        set_fs(get_ds());
        for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
-               if (elf_ppnt->p_type == PT_LOAD) {
-                       int elf_prot = 0, elf_flags;
-                       unsigned long vaddr;
+               int elf_prot = 0, elf_flags;
+               unsigned long vaddr;
 
-                       if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
-                       if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-                       if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+               if (elf_ppnt->p_type != PT_LOAD)
+                       continue;
 
-                       elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+               if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
+               if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+               if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
 
-                       vaddr = elf_ppnt->p_vaddr;
-                       if (elf_ex.e_type == ET_EXEC || load_addr_set) {
-                               elf_flags |= MAP_FIXED;
-                       }
+               elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+
+               vaddr = elf_ppnt->p_vaddr;
+               if (elf_ex.e_type == ET_EXEC || load_addr_set) {
+                       elf_flags |= MAP_FIXED;
+               }
 
-                       error = do_mmap(file,
-                                       ELF_PAGESTART(load_bias + vaddr),
-                                       (elf_ppnt->p_filesz +
-                                        ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
-                                       elf_prot, elf_flags,
-                                       (elf_ppnt->p_offset -
-                                        ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-
-                       if (!load_addr_set) {
-                               load_addr_set = 1;
-                               load_addr = (elf_ppnt->p_vaddr -
-                                            elf_ppnt->p_offset);
-                               if (elf_ex.e_type == ET_DYN) {
-                                       load_bias = error - ELF_PAGESTART(load_bias + vaddr);
-                                       load_addr += error;
-                               }
+               error = do_mmap(file, ELF_PAGESTART(load_bias + vaddr),
+                               (elf_ppnt->p_filesz +
+                               ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+                               elf_prot, elf_flags, (elf_ppnt->p_offset -
+                               ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+
+               if (!load_addr_set) {
+                       load_addr_set = 1;
+                       load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
+                       if (elf_ex.e_type == ET_DYN) {
+                               load_bias += error -
+                                            ELF_PAGESTART(load_bias + vaddr);
+                               load_addr += error;
                        }
-                       k = elf_ppnt->p_vaddr;
-                       if (k < start_code) start_code = k;
-                       k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
-                       if (k > elf_bss)
-                               elf_bss = k;
-                       if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
-                               end_code = k;
-                       if (end_data < k)
-                               end_data = k;
-                       k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-                       if (k > elf_brk)
-                               elf_brk = k;
                }
+               k = elf_ppnt->p_vaddr;
+               if (k < start_code) start_code = k;
+               k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+               if (k > elf_bss)
+                       elf_bss = k;
+               if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
+                       end_code = k;
+               if (end_data < k)
+                       end_data = k;
+               k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+               if (k > elf_brk)
+                       elf_brk = k;
        }
        set_fs(old_fs);
        fput(file); /* all done with the file */
index 154bb6c..a5230c1 100644 (file)
 #include <asm/unaligned.h>
 #include <asm/semaphore.h>
 #include <asm/spinlock.h>
-#include <asm/namei.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
+/*
+ * The bitmask for a lookup event:
+ *  - follow links at the end
+ *  - require a directory
+ *  - ending slashes ok even for nonexistent files
+ *  - internal "there are more path compnents" flag
+ */
+#define LOOKUP_FOLLOW          (1)
+#define LOOKUP_DIRECTORY       (2)
+#define LOOKUP_SLASHOK         (4)
+#define LOOKUP_CONTINUE                (8)
+
+#include <asm/namei.h>
+
 /* This can be removed after the beta phase. */
 #define CACHE_SUPERVISE        /* debug the correctness of dcache entries */
 #undef DEBUG           /* some other debugging */
@@ -282,18+295,6 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
        return result;
 }
 
-/*
- * The bitmask for a lookup event:
- *  - follow links at the end
- *  - require a directory
- *  - ending slashes ok even for nonexistent files
- *  - internal "there are more path compnents" flag
- */
-#define LOOKUP_FOLLOW          (1)
-#define LOOKUP_DIRECTORY       (2)
-#define LOOKUP_SLASHOK         (4)
-#define LOOKUP_CONTINUE                (8)
-
 static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow)
 {
        struct inode * inode = dentry->d_inode;
@@ -342,10+343,10 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
        if (*name == '/') {
                if (base)
                        dput(base);
-               base = dget(current->fs->root);
                do {
                        name++;
                } while (*name == '/');
+               base = dget(current->fs->root);
        } else if (!base) {
                base = dget(current->fs->pwd);
        }
index c2346d4..81a4316 100644 (file)
@@ -43,5+43,14 @@ nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
                current->fsgid = exp->ex_anon_gid;
        for (i = 0; i < NGROUPS; i++)
                current->groups[i] = cred->cr_groups[i];
+
+       if ((cred->cr_uid)) {
+               cap_lower(current->cap_effective, CAP_DAC_OVERRIDE);
+               cap_lower(current->cap_effective, CAP_DAC_READ_SEARCH);
+       } else {
+               cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
+               cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH);
+       }
+
        rqstp->rq_userset = 1;
 }
index d6d7c52..81bd84b 100644 (file)
@@ -457,14+457,17 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
           char *path, struct knfs_fh *f)
 {
        struct svc_export       *exp;
-       struct dentry           *dentry;
+       struct dentry           *dentry = NULL;
        struct inode            *inode;
        struct svc_fh           fh;
        int                     err;
 
+       err = -EPERM;
        if (path) {
-               dentry = lookup_dentry(path, NULL, 0);
-
+               if (!(dentry = lookup_dentry(path, NULL, 0))) {
+                       printk("nfsd: exp_rootfh path not found %s", path);
+                       return -EPERM;
+               }
                dev = dentry->d_inode->i_dev;
                ino = dentry->d_inode->i_ino;
        
@@ -474,17+477,21 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
        } else {
                dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
                         clp->cl_ident, dev, ino);
-               exp = exp_get(clp, dev, ino);
-               dentry = dget(exp->ex_dentry);
+               if ((exp = exp_get(clp, dev, ino)))
+                       if (!(dentry = dget(exp->ex_dentry))) {
+                               printk("exp_rootfh: Aieee, NULL dentry\n");
+                               return -EPERM;
+                       }
        }
-       err = -EPERM;
-       if (!exp)
+       if (!exp) {
+               dprintk("nfsd: exp_rootfh export not found.\n");
                goto out;
+       }
 
        inode = dentry->d_inode;
        if (!inode) {
                printk("exp_rootfh: Aieee, NULL d_inode\n");
-               return -EPERM;
+               goto out;
        }
        if (inode->i_dev != dev || inode->i_ino != ino) {
                printk("exp_rootfh: Aieee, ino/dev mismatch\n");
index 542f3f8..8c3d91f 100644 (file)
@@ -1061,31+1061,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                goto out;
 
        /*
-        * Security: Check that the export is valid for dentry <gam3@acm.org>
-        */
-       if (fh->fh_dev != fh->fh_xdev) {
-               printk("fh_verify: Security: export on other device"
-                      " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
-               goto out;
-       } else {
-               struct dentry *tdentry = dentry;
-
-               do {
-                       if (exp->ex_dentry == tdentry) {
-                               error = 0;
-                               break;
-                       }
-                       if (tdentry->d_parent == tdentry)
-                               break;
-               } while ((tdentry = tdentry->d_parent));
-               if (error) {
-                       printk("fh_verify: Security: %s/%s bad export.\n",
-                              dentry->d_parent->d_name.name,
-                              dentry->d_name.name);
-                       goto out;
-               }
-       }
-       /*
         * Note:  it's possible the returned dentry won't be the one in the
         * file handle.  We can correct the file handle for our use, but
         * unfortunately the client will keep sending the broken one.  Let's
@@ -1105,6+1080,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
 check_type:
        dentry = fhp->fh_dentry;
        inode = dentry->d_inode;
+       exp = fhp->fh_export;
        if (type > 0 && (inode->i_mode & S_IFMT) != type) {
                error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
                goto out;
@@ -1114,9+1090,45 @@ check_type:
                goto out;
        }
 
+       /*
+        * Security: Check that the export is valid for dentry <gam3@acm.org>
+        */
+       if (fh->fh_dev != fh->fh_xdev) {
+               printk("fh_verify: Security: export on other device"
+                      " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
+               goto out;
+       } else if (exp->ex_dentry != dentry) {
+               struct dentry *tdentry = dentry;
+               int err2 = 0;
+
+               error = nfserr_stale;
+               do {
+                       tdentry = tdentry->d_parent;
+                       if (exp->ex_dentry == tdentry) {
+                               error = 0;
+                               break;
+                       }
+                       if ((err2 = nfsd_permission(exp, tdentry, MAY_READ))) {
+                               error = err2;
+#ifdef NFSD_PARANOIA
+                               goto out1;
+#else
+                               goto out;
+#endif
+                       }
+               } while ((tdentry != tdentry->d_parent));
+               if (error) {
+                       printk("fh_verify: Security: %s/%s bad export.\n",
+                              dentry->d_parent->d_name.name,
+                              dentry->d_name.name);
+                       goto out;
+               }
+       }
+
        /* Finally, check access permissions. */
-       error = nfsd_permission(fhp->fh_export, dentry, access);
+       error = nfsd_permission(exp, dentry, access);
 #ifdef NFSD_PARANOIA
+out1:
 if (error)
 printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, access, error);
index 3d10fc2..c442db4 100644 (file)
@@ -199,7+199,6 @@ out:
                free_wait(&wait_table);
                free_page((unsigned long) wait_table.entry);
        }
-out_nowait:
        unlock_kernel();
        return retval;
 }
index e6fdf42..9d3fec9 100644 (file)
  */
 #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
   typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { }
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
 #else
   typedef struct { int gcc_is_buggy; } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { 0 }
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 #endif
 
 #define spin_lock_init(lock)   do { } while(0)
 typedef struct {
        volatile unsigned int lock;
 } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0 }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 
 #define spin_lock_init(x)      do { (x)->lock = 0; } while (0)
 #define spin_trylock(lock)     (!test_and_set_bit(0,(lock)))
@@ -61,7+61,7 @@ typedef struct {
        volatile unsigned int babble;
        const char *module;
 } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0, 25, __BASE_FILE__ }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ }
 
 #include <linux/kernel.h>
 
@@ -90,7+90,7 @@ typedef struct {
  * read-locks.
  */
 typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+#define RW_LOCK_UNLOCKED (rwlock_t) { }
 
 #define read_lock(lock)                do { } while(0)
 #define read_unlock(lock)      do { } while(0)
@@ -120,7+120,7 @@ typedef struct {
        volatile unsigned int lock;
 } spinlock_t;
 
-#define SPIN_LOCK_UNLOCKED { 0 }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 
 #define spin_lock_init(x)      do { (x)->lock = 0; } while(0)
 /*
@@ -188,7+188,7 @@ typedef struct {
        unsigned long previous;
 } rwlock_t;
 
-#define RW_LOCK_UNLOCKED { 0, 0 }
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
 /*
  * On x86, we implement read-write locks as a 32-bit counter
index 64886fc..65012f6 100644 (file)
@@ -88,7+88,7 @@ static inline unsigned long _get_base(char * addr)
                "1:\t"                          \
                "movl %0,%%" #seg "\n"          \
                "2:\n"                          \
-               ".section fixup,\"ax\"\n"       \
+               ".section .fixup,\"ax\"\n"      \
                "3:\t"                          \
                "pushl $0\n\t"                  \
                "popl %%" #seg "\n\t"           \
index d2f9a58..2775b89 100644 (file)
 #define ASIZ_task_cap_inheritable      0x00000004
 #define AOFF_task_cap_permitted        0x0000016c
 #define ASIZ_task_cap_permitted        0x00000004
-#define AOFF_task_rlim 0x00000170
+#define AOFF_task_user 0x00000170
+#define ASIZ_task_user 0x00000004
+#define AOFF_task_rlim 0x00000174
 #define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math    0x000001c0
+#define AOFF_task_used_math    0x000001c4
 #define ASIZ_task_used_math    0x00000002
-#define AOFF_task_comm 0x000001c2
+#define AOFF_task_comm 0x000001c6
 #define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count   0x000001d4
+#define AOFF_task_link_count   0x000001d8
 #define ASIZ_task_link_count   0x00000004
-#define AOFF_task_tty  0x000001d8
+#define AOFF_task_tty  0x000001dc
 #define ASIZ_task_tty  0x00000004
-#define AOFF_task_semundo      0x000001dc
+#define AOFF_task_semundo      0x000001e0
 #define ASIZ_task_semundo      0x00000004
-#define AOFF_task_semsleeping  0x000001e0
+#define AOFF_task_semsleeping  0x000001e4
 #define ASIZ_task_semsleeping  0x00000004
 #define AOFF_task_tss  0x000001e8
 #define ASIZ_task_tss  0x00000388
 #define AOFF_task_mm   0x00000578
 #define ASIZ_task_mm   0x00000004
 #define AOFF_task_sigmask_lock 0x0000057c
-#define ASIZ_task_sigmask_lock 0x00000000
-#define AOFF_task_sig  0x0000057c
+#define ASIZ_task_sigmask_lock 0x00000001
+#define AOFF_task_sig  0x00000580
 #define ASIZ_task_sig  0x00000004
-#define AOFF_task_signal       0x00000580
+#define AOFF_task_signal       0x00000584
 #define ASIZ_task_signal       0x00000008
-#define AOFF_task_blocked      0x00000588
+#define AOFF_task_blocked      0x0000058c
 #define ASIZ_task_blocked      0x00000008
-#define AOFF_task_sigqueue     0x00000590
+#define AOFF_task_sigqueue     0x00000594
 #define ASIZ_task_sigqueue     0x00000004
-#define AOFF_task_sigqueue_tail        0x00000594
+#define AOFF_task_sigqueue_tail        0x00000598
 #define ASIZ_task_sigqueue_tail        0x00000004
-#define AOFF_task_sas_ss_sp    0x00000598
+#define AOFF_task_sas_ss_sp    0x0000059c
 #define ASIZ_task_sas_ss_sp    0x00000004
-#define AOFF_task_sas_ss_size  0x0000059c
+#define AOFF_task_sas_ss_size  0x000005a0
 #define ASIZ_task_sas_ss_size  0x00000004
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000004
 #define ASIZ_task_cap_inheritable      0x00000004
 #define AOFF_task_cap_permitted        0x00000264
 #define ASIZ_task_cap_permitted        0x00000004
-#define AOFF_task_rlim 0x00000268
+#define AOFF_task_user 0x00000268
+#define ASIZ_task_user 0x00000004
+#define AOFF_task_rlim 0x0000026c
 #define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math    0x000002b8
+#define AOFF_task_used_math    0x000002bc
 #define ASIZ_task_used_math    0x00000002
-#define AOFF_task_comm 0x000002ba
+#define AOFF_task_comm 0x000002be
 #define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count   0x000002cc
+#define AOFF_task_link_count   0x000002d0
 #define ASIZ_task_link_count   0x00000004
-#define AOFF_task_tty  0x000002d0
+#define AOFF_task_tty  0x000002d4
 #define ASIZ_task_tty  0x00000004
-#define AOFF_task_semundo      0x000002d4
+#define AOFF_task_semundo      0x000002d8
 #define ASIZ_task_semundo      0x00000004
-#define AOFF_task_semsleeping  0x000002d8
+#define AOFF_task_semsleeping  0x000002dc
 #define ASIZ_task_semsleeping  0x00000004
 #define AOFF_task_tss  0x000002e0
 #define ASIZ_task_tss  0x00000388
 #define AOFF_task_mm   0x00000670
 #define ASIZ_task_mm   0x00000004
 #define AOFF_task_sigmask_lock 0x00000674
-#define ASIZ_task_sigmask_lock 0x00000001
-#define AOFF_task_sig  0x00000678
+#define ASIZ_task_sigmask_lock 0x00000008
+#define AOFF_task_sig  0x0000067c
 #define ASIZ_task_sig  0x00000004
-#define AOFF_task_signal       0x0000067c
+#define AOFF_task_signal       0x00000680
 #define ASIZ_task_signal       0x00000008
-#define AOFF_task_blocked      0x00000684
+#define AOFF_task_blocked      0x00000688
 #define ASIZ_task_blocked      0x00000008
-#define AOFF_task_sigqueue     0x0000068c
+#define AOFF_task_sigqueue     0x00000690
 #define ASIZ_task_sigqueue     0x00000004
-#define AOFF_task_sigqueue_tail        0x00000690
+#define AOFF_task_sigqueue_tail        0x00000694
 #define ASIZ_task_sigqueue_tail        0x00000004
-#define AOFF_task_sas_ss_sp    0x00000694
+#define AOFF_task_sas_ss_sp    0x00000698
 #define ASIZ_task_sas_ss_sp    0x00000004
-#define AOFF_task_sas_ss_size  0x00000698
+#define AOFF_task_sas_ss_size  0x0000069c
 #define ASIZ_task_sas_ss_size  0x00000004
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000004
index cb45374..7c502a1 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: dma.h,v 1.26 1998/04/13 07:27:05 davem Exp $
+/* $Id: dma.h,v 1.28 1998/10/26 20:03:09 davem Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
 #include <asm/sbus.h>
 #include <asm/delay.h>
 #include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&dma_spin_lock, flags);
+       return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+       spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
 
 /* These are irrelevant for Sparc DMA, but we leave it in so that
  * things can compile.
index fc9887a..84367de 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: fcntl.h,v 1.10 1998/08/26 10:33:29 davem Exp $ */
+/* $Id: fcntl.h,v 1.11 1998/10/26 20:03:10 davem Exp $ */
 #ifndef _SPARC_FCNTL_H
 #define _SPARC_FCNTL_H
 
index c3b5013..359ad6e 100644 (file)
@@ -1,6+1,7 @@
 /* hardirq.h: 32-bit Sparc hard IRQ support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
  */
 
 #ifndef __SPARC_HARDIRQ_H
 #include <linux/tasks.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+       (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
 
 #ifndef __SMP__
 
 #define hardirq_trylock(cpu)   (local_irq_count[cpu] == 0)
-#define hardirq_endlock(cpu)   do { } while(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()      barrier()
 
-#else /* __SMP__ */
+#else
 
 #include <asm/atomic.h>
 #include <asm/spinlock.h>
@@ -32,37+39,33 @@ extern unsigned char global_irq_holder;
 extern spinlock_t global_irq_lock;
 extern atomic_t global_irq_count;
 
-#define release_irqlock(cpu)                           \
-do {   if(global_irq_holder == (unsigned char) cpu) {  \
-               global_irq_holder = NO_PROC_ID;         \
-               spin_unlock(&global_irq_lock);          \
-       }                                               \
-} while(0)
-
-/* Ordering of the counter bumps is _deadly_ important. */
-#define hardirq_enter(cpu) \
-       do { ++local_irq_count[cpu]; atomic_inc(&global_irq_count); } while(0)
-
-#define hardirq_exit(cpu) \
-       do { atomic_dec(&global_irq_count); --local_irq_count[cpu]; } while(0)
-
-#define hardirq_trylock(cpu)                                   \
-({     unsigned long flags; int ret = 1;                       \
-       __save_flags(flags);                                    \
-       __cli();                                                \
-       if(atomic_add_return(1, &global_irq_count) != 1 ||      \
-          *(((unsigned char *)(&global_irq_lock)))) {          \
-               atomic_dec(&global_irq_count);                  \
-               __restore_flags(flags);                         \
-               ret = 0;                                        \
-       } else {                                                \
-               ++local_irq_count[cpu];                         \
-               __sti();                                        \
-       }                                                       \
-       ret;                                                    \
-})
-
-#define hardirq_endlock(cpu) do { __cli(); hardirq_exit(cpu); __sti(); } while(0)
+static inline void release_irqlock(int cpu)
+{
+       /* if we didn't own the irq lock, just ignore.. */
+       if (global_irq_holder == (unsigned char) cpu) {
+               global_irq_holder = NO_PROC_ID;
+               spin_unlock(&global_irq_lock);
+       }
+}
+
+static inline void hardirq_enter(int cpu)
+{
+       ++local_irq_count[cpu];
+       atomic_inc(&global_irq_count);
+}
+
+static inline void hardirq_exit(int cpu)
+{
+       atomic_dec(&global_irq_count);
+       --local_irq_count[cpu];
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+       return !atomic_read(&global_irq_count) && !*(((volatile unsigned char *)(&global_irq_lock)));
+}
+
+#define hardirq_endlock(cpu)   do { } while (0)
 
 extern void synchronize_irq(void);
 
diff --git a/include/asm-sparc/perfctr.h b/include/asm-sparc/perfctr.h
new file mode 100644 (file)
index 0000000..67756e8
--- /dev/null
@@ -0,0 +1,101 @@
+/*----------------------------------------
+  PERFORMANCE INSTRUMENTATION  
+  Guillaume Thouvenin           08/10/98
+  David S. Miller               10/06/98
+  ---------------------------------------*/
+#ifndef PERF_COUNTER_API
+#define PERF_COUNTER_API
+
+/* sys_perfctr() interface.  First arg is operation code
+ * from enumeration below.  The meaning of further arguments
+ * are determined by the operation code.
+ *
+ * int sys_perfctr(int opcode, unsigned long arg0,
+ *                 unsigned long arg1, unsigned long arg2)
+ *
+ * Pointers which are passed by the user are pointers to 64-bit
+ * integers.
+ *
+ * Once enabled, performance counter state is retained until the
+ * process either exits or performs an exec.  That is, performance
+ * counters remain enabled for fork/clone children.
+ */
+enum perfctr_opcode {
+       /* Enable UltraSparc performance counters, ARG0 is pointer
+        * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer
+        * to 64-bit accumulator for D1 counter.  ARG2 is a pointer to
+        * the initial PCR register value to use.
+        */
+       PERFCTR_ON,
+
+       /* Disable UltraSparc performance counters.  The PCR is written
+        * with zero and the user counter accumulator pointers and
+        * working PCR register value are forgotten.
+        */
+       PERFCTR_OFF,
+
+       /* Add current D0 and D1 PIC values into user pointers given
+        * in PERFCTR_ON operation.  The PIC is cleared before returning.
+        */
+       PERFCTR_READ,
+
+       /* Clear the PIC register. */
+       PERFCTR_CLRPIC,
+
+       /* Begin using a new PCR value, the pointer to which is passed
+        * in ARG0.  The PIC is also cleared after the new PCR value is
+        * written.
+        */
+       PERFCTR_SETPCR,
+
+       /* Store in pointer given in ARG0 the current PCR register value
+        * being used.
+        */
+       PERFCTR_GETPCR
+};
+
+/* I don't want the kernel's namespace to be polluted with this
+ * stuff when this file is included.  --DaveM
+ */
+#ifndef __KERNEL__
+
+#define  PRIV 0x00000001
+#define  USR  0x00000002
+#define  SYS  0x00000004
+
+/* Pic.S0 Selection Bit Field Encoding  */
+#define  CYCLE_CNT            0x00000000
+#define  INSTR_CNT            0x00000010
+#define  DISPATCH0_IC_MISS    0x00000020
+#define  DISPATCH0_STOREBUF   0x00000030
+#define  IC_REF               0x00000080
+#define  DC_RD                0x00000090
+#define  DC_WR                0x000000A0
+#define  LOAD_USE             0x000000B0
+#define  EC_REF               0x000000C0
+#define  EC_WRITE_HIT_RDO     0x000000D0
+#define  EC_SNOOP_INV         0x000000E0
+#define  EC_RD_HIT            0x000000F0
+
+/* Pic.S1 Selection Bit Field Encoding  */
+#define  CYCLE_CNT_D1         0x00000000
+#define  INSTR_CNT_D1         0x00000800
+#define  DISPATCH0_IC_MISPRED 0x00001000
+#define  DISPATCH0_FP_USE     0x00001800
+#define  IC_HIT               0x00004000
+#define  DC_RD_HIT            0x00004800
+#define  DC_WR_HIT            0x00005000
+#define  LOAD_USE_RAW         0x00005800
+#define  EC_HIT               0x00006000
+#define  EC_WB                0x00006800
+#define  EC_SNOOP_CB          0x00007000
+#define  EC_IT_HIT            0x00007800
+
+struct vcounter_struct {
+  unsigned long long vcnt0;
+  unsigned long long vcnt1;
+};
+
+#endif /* !(__KERNEL__) */
+
+#endif /* !(PERF_COUNTER_API) */
index ec61074..3c85783 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sigcontext.h,v 1.12 1997/03/03 16:51:52 jj Exp $ */
+/* $Id: sigcontext.h,v 1.13 1998/10/06 09:28:35 jj Exp $ */
 #ifndef __SPARC_SIGCONTEXT_H
 #define __SPARC_SIGCONTEXT_H
 
@@ -52,6+52,16 @@ typedef struct {
        } si_fpqueue [16];
 } __siginfo_fpu_t;
 
+/* This magic should be in g_upper[0] for all upper parts
+   to be valid.
+   This is generated by sparc64 only, but for 32bit processes,
+   so we define it here as well.  */
+#define SIGINFO_EXTRA_V8PLUS_MAGIC      0x130e269
+typedef struct {
+       unsigned   int g_upper[8];
+       unsigned   int o_upper[8];
+} siginfo_extra_v8plus_t;
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC_SIGCONTEXT_H) */
dissimilarity index 85%
index 5cabdc0..80c5d2e 100644 (file)
-/* softirq.h: 32-bit Sparc soft IRQ support.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef __SPARC_SOFTIRQ_H
-#define __SPARC_SOFTIRQ_H
-
-#include <asm/atomic.h>
-#include <asm/hardirq.h>
-
-/* 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.
- */
-#define get_active_bhs()       (bh_mask & bh_active)
-
-#ifdef __SMP__
-
-extern atomic_t __sparc_bh_counter;
-
-#define start_bh_atomic() \
-       do { atomic_inc(&__sparc_bh_counter); synchronize_irq(); } while(0)
-
-#define end_bh_atomic()                atomic_dec(&__sparc_bh_counter)
-
-#include <asm/spinlock.h>
-
-extern spinlock_t global_bh_lock;
-
-#define init_bh(nr, routine)                           \
-do {   unsigned long flags;                            \
-       int ent = nr;                                   \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_base[ent] = routine;                         \
-       bh_mask_count[ent] = 0;                         \
-       bh_mask |= 1 << ent;                            \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define remove_bh(nr)                                  \
-do {   unsigned long flags;                            \
-       int ent = nr;                                   \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_base[ent] = NULL;                            \
-       bh_mask &= ~(1 << ent);                         \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define mark_bh(nr)                                    \
-do {   unsigned long flags;                            \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_active |= (1 << nr);                         \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define disable_bh(nr)                                 \
-do {   unsigned long flags;                            \
-       int ent = nr;                                   \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_mask &= ~(1 << ent);                         \
-       bh_mask_count[ent]++;                           \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define enable_bh(nr)                                  \
-do {   unsigned long flags;                            \
-       int ent = nr;                                   \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       if (!--bh_mask_count[ent])                      \
-               bh_mask |= 1 << ent;                    \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define softirq_trylock(cpu)                                   \
-({                                                             \
-       int ret = 1;                                            \
-       if(atomic_add_return(1, &__sparc_bh_counter) != 1) {    \
-               atomic_dec(&__sparc_bh_counter);                \
-               ret = 0;                                        \
-       }                                                       \
-       ret;                                                    \
-})
-#define softirq_endlock(cpu)   atomic_dec(&__sparc_bh_counter)
-#define clear_active_bhs(mask)                         \
-do {   unsigned long flags;                            \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_active &= ~(mask);                           \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#else /* !(__SMP__) */
-
-extern int __sparc_bh_counter;
-
-#define start_bh_atomic()      do { __sparc_bh_counter++; barrier(); } while(0)
-#define end_bh_atomic()                do { barrier(); __sparc_bh_counter--; } while(0)
-
-#define softirq_trylock(cpu) (__sparc_bh_counter ? 0 : (__sparc_bh_counter=1))
-#define softirq_endlock(cpu) (__sparc_bh_counter = 0)
-#define clear_active_bhs(x)    (bh_active &= ~(x))
-#define synchronize_bh()       barrier() /* XXX implement SMP version -DaveM */
-
-#define init_bh(nr, routine)   \
-do {   int ent = nr;           \
-       bh_base[ent] = routine; \
-       bh_mask_count[ent] = 0; \
-       bh_mask |= 1 << ent;    \
-} while(0)
-
-#define remove_bh(nr)          \
-do {   int ent = nr;           \
-       bh_base[ent] = NULL;    \
-       bh_mask &= ~(1 << ent); \
-} while(0)
-
-#define mark_bh(nr)            (bh_active |= (1 << (nr)))
-
-#define disable_bh(nr)         \
-do {   int ent = nr;           \
-       bh_mask &= ~(1 << ent); \
-       bh_mask_count[ent]++;   \
-} while(0)
-
-#define enable_bh(nr)                  \
-do {   int ent = nr;                   \
-       if (!--bh_mask_count[ent])      \
-               bh_mask |= 1 << ent;    \
-} while(0)
-
-#endif /* __SMP__ */
-
-#endif /* __SPARC_SOFTIRQ_H */
+/* softirq.h: 32-bit Sparc soft IRQ support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ */
+
+#ifndef __SPARC_SOFTIRQ_H
+#define __SPARC_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/hardirq.h>
+
+extern unsigned int local_bh_count[NR_CPUS];
+
+#define get_active_bhs()       (bh_mask & bh_active)
+
+#ifdef __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 atomic_t global_bh_lock;
+extern atomic_t global_bh_count;
+extern spinlock_t sparc_bh_lock;
+
+extern void synchronize_bh(void);
+
+static inline void clear_active_bhs(unsigned int mask)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&sparc_bh_lock, flags);
+       bh_active &= ~(mask);
+       spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+       unsigned long flags;
+       spin_lock_irqsave(&sparc_bh_lock, flags);
+       bh_base[nr] = routine;
+       bh_mask_count[nr] = 0;
+       bh_mask |= 1 << nr;
+       spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void remove_bh(int nr)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&sparc_bh_lock, flags);
+       bh_base[nr] = NULL;
+       bh_mask &= ~(1 << nr);
+       spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void mark_bh(int nr)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&sparc_bh_lock, flags);
+       bh_active |= (1 << nr);
+       spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&sparc_bh_lock, flags);
+       bh_mask &= ~(1 << nr);
+       bh_mask_count[nr]++;
+       spin_unlock_irqrestore(&sparc_bh_lock, flags);
+       synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&sparc_bh_lock, flags);
+       if (!--bh_mask_count[nr])
+               bh_mask |= 1 << nr;
+       spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+static inline void start_bh_atomic(void)
+{
+       atomic_inc(&global_bh_lock);
+       synchronize_bh();
+}
+
+static inline void end_bh_atomic(void)
+{
+       atomic_dec(&global_bh_lock);
+}
+
+/* These are for the IRQs testing the lock */
+static inline int softirq_trylock(int cpu)
+{
+       if (atomic_add_return(1, &global_bh_count) == 1) {
+               if (atomic_read(&global_bh_lock) == 0) {
+                       ++local_bh_count[cpu];
+                       return 1;
+               }
+       }
+       atomic_dec(&global_bh_count);
+       return 0;
+}
+
+static inline void softirq_endlock(int cpu)
+{
+       local_bh_count[cpu]--;
+       atomic_dec(&global_bh_count);
+}
+
+#else
+
+#define clear_active_bhs(x)    (bh_active &= ~(x))
+#define mark_bh(nr)            (bh_active |= (1 << (nr)))
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock(cpu)   (local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1))
+#define softirq_endlock(cpu)   (local_bh_count[cpu] = 0)
+#define synchronize_bh()       barrier()
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+       bh_mask &= ~(1 << nr);
+       bh_mask_count[nr]++;
+       synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+       if (!--bh_mask_count[nr])
+               bh_mask |= 1 << nr;
+}
+
+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 start_bh_atomic(void)
+{
+       local_bh_count[0]++;
+       barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+       barrier();
+       local_bh_count[0]--;
+}
+
+#endif /* SMP */
+
+#endif /* __SPARC_SOFTIRQ_H */
index 22fe5e2..517b0cc 100644 (file)
 
 #ifndef __SMP__
 
-#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { }
-#else
-  typedef unsigned char spinlock_t;
-  #define SPIN_LOCK_UNLOCKED 0
-#endif
+typedef unsigned char spinlock_t;
+#define SPIN_LOCK_UNLOCKED 0
 
 #define spin_lock_init(lock)   do { } while(0)
 #define spin_lock(lock)                do { } while(0)
@@ -270,18+265,16 @@ typedef struct { volatile unsigned int lock; } rwlock_t;
 /* Sort of like atomic_t's on Sparc, but even more clever.
  *
  *     ------------------------------------
- *     | 16-bit counter   | clock | wlock |  rwlock_t
+ *     | 24-bit counter           | wlock |  rwlock_t
  *     ------------------------------------
- *      31              16 15    8 7     0
+ *      31                       8 7     0
  *
- * wlock signifies the one writer is in, the clock protects
- * counter bumping, however a reader must acquire wlock
- * before he can bump the counter on a read_lock().
- * Similarly a writer, once he has the wlock, must await
- * for the top 24 bits to all clear before he can finish
- * going in (this includes the clock of course).
+ * wlock signifies the one writer is in or somebody is updating
+ * counter. For a writer, if he successfully acquires the wlock,
+ * but counter is non-zero, he has to release the lock and wait,
+ * till both counter and wlock are zero.
  *
- * Unfortunately this scheme limits us to ~65,000 cpus.
+ * Unfortunately this scheme limits us to ~16,000,000 cpus.
  */
 extern __inline__ void _read_lock(rwlock_t *rw)
 {
@@ -310,7+303,7 @@ extern __inline__ void _read_unlock(rwlock_t *rw)
        __asm__ __volatile__("
        mov     %%o7, %%g4
        call    ___rw_read_exit
-        ldstub [%%g1 + 2], %%g2
+        ldstub [%%g1 + 3], %%g2
 "      : /* no outputs */
        : "r" (lp)
        : "g2", "g4", "g7", "memory", "cc");
index 82244a3..6dc074c 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: system.h,v 1.70 1998/09/29 09:46:32 davem Exp $ */
+/* $Id: system.h,v 1.71 1998/10/13 03:51:06 jj Exp $ */
 #include <linux/config.h>
 
 #ifndef __SPARC_SYSTEM_H
@@ -235,18+235,16 @@ extern __inline__ unsigned long read_psr_and_cli(void)
 
 extern unsigned char global_irq_holder;
 
-#define save_flags(x) \
-do {   ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
-               ((getipl() & PSR_PIL) ? 2 : 0))); } while(0)
-
 #define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
 
 #ifdef DEBUG_IRQLOCK
 extern void __global_cli(void);
 extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
 extern void __global_restore_flags(unsigned long flags);
 #define cli()                  __global_cli()
 #define sti()                  __global_sti()
+#define save_flags(flags)      ((flags)=__global_save_flags())
 #define restore_flags(flags)   __global_restore_flags(flags)
 #else
 
index fdc7d1a..501197b 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: unistd.h,v 1.47 1998/09/21 05:07:22 jj Exp $ */
+/* $Id: unistd.h,v 1.48 1998/10/07 01:27:50 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
 #define __NR_chmod               15 /* Common                                      */
 #define __NR_lchown              16 /* Common                                      */
 #define __NR_brk                 17 /* Common                                      */
-/* #define __NR_ni_syscall       18    ENOSYS under SunOS                          */
+/* #define __NR_ni_syscall       18    RESERVED for sparc64 perf-counter syscall   */
 #define __NR_lseek               19 /* Common                                      */
 #define __NR_getpid              20 /* Common                                      */
 #define __NR_capget             21 /* Linux Specific                              */
index be0a2e2..2001925 100644 (file)
 #define AOFF_task_semsleeping  0x00000370
 #define ASIZ_task_semsleeping  0x00000008
 #define AOFF_task_tss  0x00000380
-#define ASIZ_task_tss  0x00000440
-#define AOFF_task_fs   0x000007c0
+#define ASIZ_task_tss  0x00000470
+#define AOFF_task_fs   0x000007f0
 #define ASIZ_task_fs   0x00000008
-#define AOFF_task_files        0x000007c8
+#define AOFF_task_files        0x000007f8
 #define ASIZ_task_files        0x00000008
-#define AOFF_task_mm   0x000007d0
+#define AOFF_task_mm   0x00000800
 #define ASIZ_task_mm   0x00000008
-#define AOFF_task_sigmask_lock 0x000007d8
-#define ASIZ_task_sigmask_lock 0x00000000
-#define AOFF_task_sig  0x000007d8
+#define AOFF_task_sigmask_lock 0x00000808
+#define ASIZ_task_sigmask_lock 0x00000001
+#define AOFF_task_sig  0x00000810
 #define ASIZ_task_sig  0x00000008
-#define AOFF_task_signal       0x000007e0
+#define AOFF_task_signal       0x00000818
 #define ASIZ_task_signal       0x00000008
-#define AOFF_task_blocked      0x000007e8
+#define AOFF_task_blocked      0x00000820
 #define ASIZ_task_blocked      0x00000008
-#define AOFF_task_sigqueue     0x000007f0
+#define AOFF_task_sigqueue     0x00000828
 #define ASIZ_task_sigqueue     0x00000008
-#define AOFF_task_sigqueue_tail        0x000007f8
+#define AOFF_task_sigqueue_tail        0x00000830
 #define ASIZ_task_sigqueue_tail        0x00000008
-#define AOFF_task_sas_ss_sp    0x00000800
+#define AOFF_task_sas_ss_sp    0x00000838
 #define ASIZ_task_sas_ss_sp    0x00000008
-#define AOFF_task_sas_ss_size  0x00000808
+#define AOFF_task_sas_ss_size  0x00000840
 #define ASIZ_task_sas_ss_size  0x00000008
-#define ASIZ_task      0x00000810
+#define ASIZ_task      0x00000850
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define AOFF_mm_mmap_cache     0x00000008
 #define ASIZ_thread_sig_address        0x00000008
 #define AOFF_thread_sig_desc   0x000003f0
 #define ASIZ_thread_sig_desc   0x00000008
-#define AOFF_thread_fpdepth    0x000003f8
+#define AOFF_thread_user_cntd0 0x000003f8
+#define ASIZ_thread_user_cntd0 0x00000008
+#define AOFF_thread_user_cntd1 0x00000400
+#define ASIZ_thread_user_cntd1 0x00000008
+#define AOFF_thread_kernel_cntd0       0x00000408
+#define ASIZ_thread_kernel_cntd0       0x00000008
+#define AOFF_thread_kernel_cntd1       0x00000410
+#define ASIZ_thread_kernel_cntd1       0x00000008
+#define AOFF_thread_pcr_reg    0x00000418
+#define ASIZ_thread_pcr_reg    0x00000008
+#define AOFF_thread_fpdepth    0x00000420
 #define ASIZ_thread_fpdepth    0x00000001
-#define AOFF_thread_fpsaved    0x000003f9
+#define AOFF_thread_fpsaved    0x00000421
 #define ASIZ_thread_fpsaved    0x00000007
-#define AOFF_thread_gsr        0x00000400
+#define AOFF_thread_gsr        0x00000428
 #define ASIZ_thread_gsr        0x00000007
-#define AOFF_thread_xfsr       0x00000408
+#define AOFF_thread_xfsr       0x00000430
 #define ASIZ_thread_xfsr       0x00000038
-#define ASIZ_thread    0x00000440
+#define ASIZ_thread    0x00000470
 
 #else /* __SMP__ */
 
+#ifndef SPIN_LOCK_DEBUG
+
 #define AOFF_task_state        0x00000000
 #define ASIZ_task_state        0x00000008
 #define AOFF_task_flags        0x00000008
 #define AOFF_task_semsleeping  0x00000560
 #define ASIZ_task_semsleeping  0x00000008
 #define AOFF_task_tss  0x00000570
-#define ASIZ_task_tss  0x00000440
-#define AOFF_task_fs   0x000009b0
+#define ASIZ_task_tss  0x00000470
+#define AOFF_task_fs   0x000009e0
 #define ASIZ_task_fs   0x00000008
-#define AOFF_task_files        0x000009b8
+#define AOFF_task_files        0x000009e8
 #define ASIZ_task_files        0x00000008
-#define AOFF_task_mm   0x000009c0
+#define AOFF_task_mm   0x000009f0
 #define ASIZ_task_mm   0x00000008
-#define AOFF_task_sigmask_lock 0x000009c8
+#define AOFF_task_sigmask_lock 0x000009f8
 #define ASIZ_task_sigmask_lock 0x00000001
-#define AOFF_task_sig  0x000009d0
+#define AOFF_task_sig  0x00000a00
+#define ASIZ_task_sig  0x00000008
+#define AOFF_task_signal       0x00000a08
+#define ASIZ_task_signal       0x00000008
+#define AOFF_task_blocked      0x00000a10
+#define ASIZ_task_blocked      0x00000008
+#define AOFF_task_sigqueue     0x00000a18
+#define ASIZ_task_sigqueue     0x00000008
+#define AOFF_task_sigqueue_tail        0x00000a20
+#define ASIZ_task_sigqueue_tail        0x00000008
+#define AOFF_task_sas_ss_sp    0x00000a28
+#define ASIZ_task_sas_ss_sp    0x00000008
+#define AOFF_task_sas_ss_size  0x00000a30
+#define ASIZ_task_sas_ss_size  0x00000008
+#define ASIZ_task      0x00000a40
+#define AOFF_mm_mmap   0x00000000
+#define ASIZ_mm_mmap   0x00000008
+#define AOFF_mm_mmap_cache     0x00000008
+#define ASIZ_mm_mmap_cache     0x00000008
+#define AOFF_mm_pgd    0x00000010
+#define ASIZ_mm_pgd    0x00000008
+#define AOFF_mm_count  0x00000018
+#define ASIZ_mm_count  0x00000004
+#define AOFF_mm_map_count      0x0000001c
+#define ASIZ_mm_map_count      0x00000004
+#define AOFF_mm_mmap_sem       0x00000020
+#define ASIZ_mm_mmap_sem       0x00000010
+#define AOFF_mm_context        0x00000030
+#define ASIZ_mm_context        0x00000008
+#define AOFF_mm_start_code     0x00000038
+#define ASIZ_mm_start_code     0x00000008
+#define AOFF_mm_end_code       0x00000040
+#define ASIZ_mm_end_code       0x00000008
+#define AOFF_mm_start_data     0x00000048
+#define ASIZ_mm_start_data     0x00000008
+#define AOFF_mm_end_data       0x00000050
+#define ASIZ_mm_end_data       0x00000008
+#define AOFF_mm_start_brk      0x00000058
+#define ASIZ_mm_start_brk      0x00000008
+#define AOFF_mm_brk    0x00000060
+#define ASIZ_mm_brk    0x00000008
+#define AOFF_mm_start_stack    0x00000068
+#define ASIZ_mm_start_stack    0x00000008
+#define AOFF_mm_arg_start      0x00000070
+#define ASIZ_mm_arg_start      0x00000008
+#define AOFF_mm_arg_end        0x00000078
+#define ASIZ_mm_arg_end        0x00000008
+#define AOFF_mm_env_start      0x00000080
+#define ASIZ_mm_env_start      0x00000008
+#define AOFF_mm_env_end        0x00000088
+#define ASIZ_mm_env_end        0x00000008
+#define AOFF_mm_rss    0x00000090
+#define ASIZ_mm_rss    0x00000008
+#define AOFF_mm_total_vm       0x00000098
+#define ASIZ_mm_total_vm       0x00000008
+#define AOFF_mm_locked_vm      0x000000a0
+#define ASIZ_mm_locked_vm      0x00000008
+#define AOFF_mm_def_flags      0x000000a8
+#define ASIZ_mm_def_flags      0x00000008
+#define AOFF_mm_cpu_vm_mask    0x000000b0
+#define ASIZ_mm_cpu_vm_mask    0x00000008
+#define AOFF_mm_segments       0x000000b8
+#define ASIZ_mm_segments       0x00000008
+#define ASIZ_mm        0x000000c0
+#define AOFF_thread_ksp        0x00000000
+#define ASIZ_thread_ksp        0x00000008
+#define AOFF_thread_wstate     0x00000008
+#define ASIZ_thread_wstate     0x00000002
+#define AOFF_thread_cwp        0x0000000a
+#define ASIZ_thread_cwp        0x00000002
+#define AOFF_thread_flags      0x0000000c
+#define ASIZ_thread_flags      0x00000002
+#define AOFF_thread_ctx        0x0000000e
+#define ASIZ_thread_ctx        0x00000002
+#define AOFF_thread_w_saved    0x00000010
+#define ASIZ_thread_w_saved    0x00000002
+#define AOFF_thread_new_signal 0x00000012
+#define ASIZ_thread_new_signal 0x00000002
+#define AOFF_thread____pad     0x00000014
+#define ASIZ_thread____pad     0x00000004
+#define AOFF_thread_current_ds 0x00000018
+#define ASIZ_thread_current_ds 0x00000008
+#define AOFF_thread_kregs      0x00000020
+#define ASIZ_thread_kregs      0x00000008
+#define AOFF_thread_utraps     0x00000028
+#define ASIZ_thread_utraps     0x00000008
+#define AOFF_thread_reg_window 0x00000030
+#define ASIZ_thread_reg_window 0x00000380
+#define AOFF_thread_rwbuf_stkptrs      0x000003b0
+#define ASIZ_thread_rwbuf_stkptrs      0x00000038
+#define AOFF_thread_sig_address        0x000003e8
+#define ASIZ_thread_sig_address        0x00000008
+#define AOFF_thread_sig_desc   0x000003f0
+#define ASIZ_thread_sig_desc   0x00000008
+#define AOFF_thread_user_cntd0 0x000003f8
+#define ASIZ_thread_user_cntd0 0x00000008
+#define AOFF_thread_user_cntd1 0x00000400
+#define ASIZ_thread_user_cntd1 0x00000008
+#define AOFF_thread_kernel_cntd0       0x00000408
+#define ASIZ_thread_kernel_cntd0       0x00000008
+#define AOFF_thread_kernel_cntd1       0x00000410
+#define ASIZ_thread_kernel_cntd1       0x00000008
+#define AOFF_thread_pcr_reg    0x00000418
+#define ASIZ_thread_pcr_reg    0x00000008
+#define AOFF_thread_fpdepth    0x00000420
+#define ASIZ_thread_fpdepth    0x00000001
+#define AOFF_thread_fpsaved    0x00000421
+#define ASIZ_thread_fpsaved    0x00000007
+#define AOFF_thread_gsr        0x00000428
+#define ASIZ_thread_gsr        0x00000007
+#define AOFF_thread_xfsr       0x00000430
+#define ASIZ_thread_xfsr       0x00000038
+#define ASIZ_thread    0x00000470
+
+#else /* SPIN_LOCK_DEBUG */
+
+#define AOFF_task_state        0x00000000
+#define ASIZ_task_state        0x00000008
+#define AOFF_task_flags        0x00000008
+#define ASIZ_task_flags        0x00000008
+#define AOFF_task_sigpending   0x00000010
+#define ASIZ_task_sigpending   0x00000004
+#define AOFF_task_addr_limit   0x00000018
+#define ASIZ_task_addr_limit   0x00000008
+#define AOFF_task_exec_domain  0x00000020
+#define ASIZ_task_exec_domain  0x00000008
+#define AOFF_task_need_resched 0x00000028
+#define ASIZ_task_need_resched 0x00000008
+#define AOFF_task_counter      0x00000030
+#define ASIZ_task_counter      0x00000008
+#define AOFF_task_priority     0x00000038
+#define ASIZ_task_priority     0x00000008
+#define AOFF_task_has_cpu      0x00000040
+#define ASIZ_task_has_cpu      0x00000004
+#define AOFF_task_processor    0x00000044
+#define ASIZ_task_processor    0x00000004
+#define AOFF_task_last_processor       0x00000048
+#define ASIZ_task_last_processor       0x00000004
+#define AOFF_task_lock_depth   0x0000004c
+#define ASIZ_task_lock_depth   0x00000004
+#define AOFF_task_next_task    0x00000050
+#define ASIZ_task_next_task    0x00000008
+#define AOFF_task_prev_task    0x00000058
+#define ASIZ_task_prev_task    0x00000008
+#define AOFF_task_next_run     0x00000060
+#define ASIZ_task_next_run     0x00000008
+#define AOFF_task_prev_run     0x00000068
+#define ASIZ_task_prev_run     0x00000008
+#define AOFF_task_binfmt       0x00000070
+#define ASIZ_task_binfmt       0x00000008
+#define AOFF_task_exit_code    0x00000078
+#define ASIZ_task_exit_code    0x00000004
+#define AOFF_task_exit_signal  0x0000007c
+#define ASIZ_task_exit_signal  0x00000004
+#define AOFF_task_pdeath_signal        0x00000080
+#define ASIZ_task_pdeath_signal        0x00000004
+#define AOFF_task_personality  0x00000088
+#define ASIZ_task_personality  0x00000008
+#define AOFF_task_pid  0x00000094
+#define ASIZ_task_pid  0x00000004
+#define AOFF_task_pgrp 0x00000098
+#define ASIZ_task_pgrp 0x00000004
+#define AOFF_task_tty_old_pgrp 0x0000009c
+#define ASIZ_task_tty_old_pgrp 0x00000004
+#define AOFF_task_session      0x000000a0
+#define ASIZ_task_session      0x00000004
+#define AOFF_task_leader       0x000000a4
+#define ASIZ_task_leader       0x00000004
+#define AOFF_task_p_opptr      0x000000a8
+#define ASIZ_task_p_opptr      0x00000008
+#define AOFF_task_p_pptr       0x000000b0
+#define ASIZ_task_p_pptr       0x00000008
+#define AOFF_task_p_cptr       0x000000b8
+#define ASIZ_task_p_cptr       0x00000008
+#define AOFF_task_p_ysptr      0x000000c0
+#define ASIZ_task_p_ysptr      0x00000008
+#define AOFF_task_p_osptr      0x000000c8
+#define ASIZ_task_p_osptr      0x00000008
+#define AOFF_task_pidhash_next 0x000000d0
+#define ASIZ_task_pidhash_next 0x00000008
+#define AOFF_task_pidhash_pprev        0x000000d8
+#define ASIZ_task_pidhash_pprev        0x00000008
+#define AOFF_task_tarray_ptr   0x000000e0
+#define ASIZ_task_tarray_ptr   0x00000008
+#define AOFF_task_wait_chldexit        0x000000e8
+#define ASIZ_task_wait_chldexit        0x00000008
+#define AOFF_task_timeout      0x000000f0
+#define ASIZ_task_timeout      0x00000008
+#define AOFF_task_policy       0x000000f8
+#define ASIZ_task_policy       0x00000008
+#define AOFF_task_rt_priority  0x00000100
+#define ASIZ_task_rt_priority  0x00000008
+#define AOFF_task_it_real_value        0x00000108
+#define ASIZ_task_it_real_value        0x00000008
+#define AOFF_task_it_prof_value        0x00000110
+#define ASIZ_task_it_prof_value        0x00000008
+#define AOFF_task_it_virt_value        0x00000118
+#define ASIZ_task_it_virt_value        0x00000008
+#define AOFF_task_it_real_incr 0x00000120
+#define ASIZ_task_it_real_incr 0x00000008
+#define AOFF_task_it_prof_incr 0x00000128
+#define ASIZ_task_it_prof_incr 0x00000008
+#define AOFF_task_it_virt_incr 0x00000130
+#define ASIZ_task_it_virt_incr 0x00000008
+#define AOFF_task_real_timer   0x00000138
+#define ASIZ_task_real_timer   0x00000028
+#define AOFF_task_times        0x00000160
+#define ASIZ_task_times        0x00000020
+#define AOFF_task_start_time   0x00000180
+#define ASIZ_task_start_time   0x00000008
+#define AOFF_task_per_cpu_utime        0x00000188
+#define ASIZ_task_per_cpu_utime        0x00000100
+#define AOFF_task_min_flt      0x00000388
+#define ASIZ_task_min_flt      0x00000008
+#define AOFF_task_maj_flt      0x00000390
+#define ASIZ_task_maj_flt      0x00000008
+#define AOFF_task_nswap        0x00000398
+#define ASIZ_task_nswap        0x00000008
+#define AOFF_task_cmin_flt     0x000003a0
+#define ASIZ_task_cmin_flt     0x00000008
+#define AOFF_task_cmaj_flt     0x000003a8
+#define ASIZ_task_cmaj_flt     0x00000008
+#define AOFF_task_cnswap       0x000003b0
+#define ASIZ_task_cnswap       0x00000008
+#define AOFF_task_swap_address 0x000003c0
+#define ASIZ_task_swap_address 0x00000008
+#define AOFF_task_old_maj_flt  0x000003c8
+#define ASIZ_task_old_maj_flt  0x00000008
+#define AOFF_task_dec_flt      0x000003d0
+#define ASIZ_task_dec_flt      0x00000008
+#define AOFF_task_swap_cnt     0x000003d8
+#define ASIZ_task_swap_cnt     0x00000008
+#define AOFF_task_uid  0x000003e0
+#define ASIZ_task_uid  0x00000004
+#define AOFF_task_euid 0x000003e4
+#define ASIZ_task_euid 0x00000004
+#define AOFF_task_suid 0x000003e8
+#define ASIZ_task_suid 0x00000004
+#define AOFF_task_fsuid        0x000003ec
+#define ASIZ_task_fsuid        0x00000004
+#define AOFF_task_gid  0x000003f0
+#define ASIZ_task_gid  0x00000004
+#define AOFF_task_egid 0x000003f4
+#define ASIZ_task_egid 0x00000004
+#define AOFF_task_sgid 0x000003f8
+#define ASIZ_task_sgid 0x00000004
+#define AOFF_task_fsgid        0x000003fc
+#define ASIZ_task_fsgid        0x00000004
+#define AOFF_task_ngroups      0x00000400
+#define ASIZ_task_ngroups      0x00000004
+#define AOFF_task_groups       0x00000404
+#define ASIZ_task_groups       0x00000080
+#define AOFF_task_cap_effective        0x00000484
+#define ASIZ_task_cap_effective        0x00000004
+#define AOFF_task_cap_inheritable      0x00000488
+#define ASIZ_task_cap_inheritable      0x00000004
+#define AOFF_task_cap_permitted        0x0000048c
+#define ASIZ_task_cap_permitted        0x00000004
+#define AOFF_task_user 0x00000490
+#define ASIZ_task_user 0x00000008
+#define AOFF_task_rlim 0x00000498
+#define ASIZ_task_rlim 0x000000a0
+#define AOFF_task_used_math    0x00000538
+#define ASIZ_task_used_math    0x00000002
+#define AOFF_task_comm 0x0000053a
+#define ASIZ_task_comm 0x00000010
+#define AOFF_task_link_count   0x0000054c
+#define ASIZ_task_link_count   0x00000004
+#define AOFF_task_tty  0x00000550
+#define ASIZ_task_tty  0x00000008
+#define AOFF_task_semundo      0x00000558
+#define ASIZ_task_semundo      0x00000008
+#define AOFF_task_semsleeping  0x00000560
+#define ASIZ_task_semsleeping  0x00000008
+#define AOFF_task_tss  0x00000570
+#define ASIZ_task_tss  0x00000470
+#define AOFF_task_fs   0x000009e0
+#define ASIZ_task_fs   0x00000008
+#define AOFF_task_files        0x000009e8
+#define ASIZ_task_files        0x00000008
+#define AOFF_task_mm   0x000009f0
+#define ASIZ_task_mm   0x00000008
+#define AOFF_task_sigmask_lock 0x000009f8
+#define ASIZ_task_sigmask_lock 0x0000000c
+#define AOFF_task_sig  0x00000a08
 #define ASIZ_task_sig  0x00000008
-#define AOFF_task_signal       0x000009d8
+#define AOFF_task_signal       0x00000a10
 #define ASIZ_task_signal       0x00000008
-#define AOFF_task_blocked      0x000009e0
+#define AOFF_task_blocked      0x00000a18
 #define ASIZ_task_blocked      0x00000008
-#define AOFF_task_sigqueue     0x000009e8
+#define AOFF_task_sigqueue     0x00000a20
 #define ASIZ_task_sigqueue     0x00000008
-#define AOFF_task_sigqueue_tail        0x000009f0
+#define AOFF_task_sigqueue_tail        0x00000a28
 #define ASIZ_task_sigqueue_tail        0x00000008
-#define AOFF_task_sas_ss_sp    0x000009f8
+#define AOFF_task_sas_ss_sp    0x00000a30
 #define ASIZ_task_sas_ss_sp    0x00000008
-#define AOFF_task_sas_ss_size  0x00000a00
+#define AOFF_task_sas_ss_size  0x00000a38
 #define ASIZ_task_sas_ss_size  0x00000008
-#define ASIZ_task      0x00000a10
+#define ASIZ_task      0x00000a40
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define AOFF_mm_mmap_cache     0x00000008
 #define ASIZ_thread_sig_address        0x00000008
 #define AOFF_thread_sig_desc   0x000003f0
 #define ASIZ_thread_sig_desc   0x00000008
-#define AOFF_thread_fpdepth    0x000003f8
+#define AOFF_thread_user_cntd0 0x000003f8
+#define ASIZ_thread_user_cntd0 0x00000008
+#define AOFF_thread_user_cntd1 0x00000400
+#define ASIZ_thread_user_cntd1 0x00000008
+#define AOFF_thread_kernel_cntd0       0x00000408
+#define ASIZ_thread_kernel_cntd0       0x00000008
+#define AOFF_thread_kernel_cntd1       0x00000410
+#define ASIZ_thread_kernel_cntd1       0x00000008
+#define AOFF_thread_pcr_reg    0x00000418
+#define ASIZ_thread_pcr_reg    0x00000008
+#define AOFF_thread_fpdepth    0x00000420
 #define ASIZ_thread_fpdepth    0x00000001
-#define AOFF_thread_fpsaved    0x000003f9
+#define AOFF_thread_fpsaved    0x00000421
 #define ASIZ_thread_fpsaved    0x00000007
-#define AOFF_thread_gsr        0x00000400
+#define AOFF_thread_gsr        0x00000428
 #define ASIZ_thread_gsr        0x00000007
-#define AOFF_thread_xfsr       0x00000408
+#define AOFF_thread_xfsr       0x00000430
 #define ASIZ_thread_xfsr       0x00000038
-#define ASIZ_thread    0x00000440
+#define ASIZ_thread    0x00000470
+#endif /* SPIN_LOCK_DEBUG */
 
 #endif /* __SMP__ */
 
index aedfa7d..6e756de 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: dma.h,v 1.8 1998/04/13 07:27:06 davem Exp $
+/* $Id: dma.h,v 1.9 1998/10/26 20:03:15 davem Exp $
  * include/asm-sparc64/dma.h
  *
  * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
 #include <asm/sbus.h>
 #include <asm/delay.h>
 #include <asm/oplib.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&dma_spin_lock, flags);
+       return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+       spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
 
 /* These are irrelevant for Sparc DMA, but we leave it in so that
  * things can compile.
index eaaf10a..e0352b8 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: fcntl.h,v 1.4 1998/08/26 10:33:36 davem Exp $ */
+/* $Id: fcntl.h,v 1.5 1998/10/26 20:03:15 davem Exp $ */
 #ifndef _SPARC64_FCNTL_H
 #define _SPARC64_FCNTL_H
 
index 342fbd9..ae408b0 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: floppy.h,v 1.15 1998/09/14 18:28:37 ecd Exp $
+/* $Id: floppy.h,v 1.16 1998/10/06 20:32:15 ecd Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -661,8+661,9 @@ __initfunc(static unsigned long sun_floppy_init(void))
                        tmp |= FCR_LDE;
                        ns87303_writeb(config, FCR, tmp);
 
+                       tmp = sun_floppy_types[0];
                        sun_floppy_types[0] = sun_floppy_types[1];
-                       sun_floppy_types[1] = 0;
+                       sun_floppy_types[1] = tmp;
 
                        if (sun_pci_broken_drive != -1) {
                                sun_pci_broken_drive = 1 - sun_pci_broken_drive;
index 64d30e8..6ab9ef7 100644 (file)
@@ -1,6+1,6 @@
 /* hardirq.h: 64-bit Sparc hard IRQ support.
  *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef __SPARC64_HARDIRQ_H
@@ -13,7+13,12 @@ extern unsigned int local_irq_count;
 #else
 #define local_irq_count                (cpu_data[smp_processor_id()].irq_count)
 #endif
-#define in_interrupt()         (local_irq_count != 0)
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ((local_irq_count + local_bh_count) != 0)
 
 #ifndef __SMP__
 
@@ -47,7+52,7 @@ static inline void release_irqlock(int cpu)
 
 static inline void hardirq_enter(int cpu)
 {
-       ++cpu_data[cpu].irq_count;
+       ++(cpu_data[cpu].irq_count);
        atomic_inc(&global_irq_count);
        membar("#StoreLoad | #StoreStore");
 }
@@ -56,31+61,16 @@ static inline void hardirq_exit(int cpu)
 {
        membar("#StoreStore | #LoadStore");
        atomic_dec(&global_irq_count);
-       --cpu_data[cpu].irq_count;
+       --(cpu_data[cpu].irq_count);
 }
 
 static inline int hardirq_trylock(int cpu)
 {
-       unsigned long flags;
-
-       __save_and_cli(flags);
-       atomic_inc(&global_irq_count);
-       if(atomic_read(&global_irq_count) != 1 ||
-          (*(((unsigned char *)(&global_irq_lock)))) != 0) {
-               atomic_dec(&global_irq_count);
-               __restore_flags(flags);
-               return 0;
-       }
-       ++cpu_data[cpu].irq_count;
-       return 1;
+       return (! atomic_read(&global_irq_count) &&
+               ! spin_is_locked (&global_irq_lock));
 }
 
-static inline void hardirq_endlock(int cpu)
-{
-       __cli();
-       hardirq_exit(cpu);
-       __sti();
-}
+#define hardirq_endlock(cpu)   do { } while (0)
 
 extern void synchronize_irq(void);
 
index 8e61043..2bf3134 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: ioctl.h,v 1.1 1996/12/02 00:05:36 davem Exp $ */
+/* $Id: ioctl.h,v 1.2 1998/10/15 05:40:38 jj Exp $ */
 #ifndef _SPARC64_IOCTL_H
 #define _SPARC64_IOCTL_H
 
 #define _IOC_NR(nr)         (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
 #define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
 
+/* ...and for the PCMCIA... */
+
+#define IOC_IN          (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT       ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK    (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT   (_IOC_SIZESHIFT)
+
 #endif /* !(_SPARC64_IOCTL_H) */
index 3e81eea..7fa3686 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: mmu_context.h,v 1.31 1998/09/24 03:22:01 davem Exp $ */
+/* $Id: mmu_context.h,v 1.32 1998/10/13 14:03:52 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -118,11+118,10 @@ extern __inline__ void __get_mmu_context(struct task_struct *tsk)
  * the context for the new mm so we see the new mappings.
  */
 #define activate_context(__tsk)                \
-do {   unsigned long __flags;          \
-       __save_and_cli(__flags);        \
-       flushw_user();                  \
+do {   flushw_user();                  \
+       spin_lock(&scheduler_lock);     \
        __get_mmu_context(__tsk);       \
-       __restore_flags(__flags);       \
+       spin_unlock(&scheduler_lock);   \
 } while(0)
 
 #endif /* !(__ASSEMBLY__) */
index 2c9c88c..dbd8930 100644 (file)
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
 static inline struct dentry *
-__sparc64_lookup_dentry(const char *name, int follow_link)
+__sparc64_lookup_dentry(const char *name, int lookup_flags)
 {
        struct dentry *base;
        char *emul;
@@ -29,18+29,18 @@ __sparc64_lookup_dentry(const char *name, int follow_link)
                return NULL;
        }
 
-       base = lookup_dentry (emul, dget (current->fs->root), 1);
+       base = lookup_dentry (emul, dget (current->fs->root), (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
                        
        if (IS_ERR (base)) return NULL;
        
-       base = lookup_dentry (name, base, follow_link);
+       base = lookup_dentry (name, base, lookup_flags);
        
        if (IS_ERR (base)) return NULL;
        
        if (!base->d_inode) {
                struct dentry *fromroot;
                
-               fromroot = lookup_dentry (name, dget (current->fs->root), follow_link);
+               fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags);
                
                if (IS_ERR (fromroot)) return base;
                
@@ -55,9+55,9 @@ __sparc64_lookup_dentry(const char *name, int follow_link)
        return base;
 }
 
-#define __prefix_lookup_dentry(name, follow_link)                              \
+#define __prefix_lookup_dentry(name, lookup_flags)                             \
        if (current->personality) {                                             \
-               dentry = __sparc64_lookup_dentry (name, follow_link);           \
+               dentry = __sparc64_lookup_dentry (name, lookup_flags);          \
                if (dentry) return dentry;                                      \
        }
 
index 6b2852c..a878a3e 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: oplib.h,v 1.8 1997/07/24 12:15:15 davem Exp $
+/* $Id: oplib.h,v 1.9 1998/10/06 20:56:05 ecd Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -117,8+117,8 @@ extern void prom_halt(void) __attribute__ ((noreturn));
  * kernel is still active, the prom will call this routine.
  *
  */
-typedef void (*sync_func_t)(long *cmd);
-extern void prom_setsync(sync_func_t func_ptr);
+typedef int (*callback_func_t)(long *cmd);
+extern void prom_setcallback(callback_func_t func_ptr);
 
 /* Acquire the IDPROM of the root node in the prom device tree.  This
  * gets passed a buffer where you would like it stuffed.  The return value
index fe33651..0894bb9 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: page.h,v 1.23 1998/06/12 14:54:33 jj Exp $ */
+/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
 
 #ifndef __ASSEMBLY__
 
-#define clear_page(page)               memset((void *)(page), 0, PAGE_SIZE)
+extern void clear_page(unsigned long page);
 extern void copy_page(unsigned long to, unsigned long from);
 
 /* GROSS, defining this makes gcc pass these types as aggregates,
diff --git a/include/asm-sparc64/perfctr.h b/include/asm-sparc64/perfctr.h
new file mode 100644 (file)
index 0000000..67756e8
--- /dev/null
@@ -0,0 +1,101 @@
+/*----------------------------------------
+  PERFORMANCE INSTRUMENTATION  
+  Guillaume Thouvenin           08/10/98
+  David S. Miller               10/06/98
+  ---------------------------------------*/
+#ifndef PERF_COUNTER_API
+#define PERF_COUNTER_API
+
+/* sys_perfctr() interface.  First arg is operation code
+ * from enumeration below.  The meaning of further arguments
+ * are determined by the operation code.
+ *
+ * int sys_perfctr(int opcode, unsigned long arg0,
+ *                 unsigned long arg1, unsigned long arg2)
+ *
+ * Pointers which are passed by the user are pointers to 64-bit
+ * integers.
+ *
+ * Once enabled, performance counter state is retained until the
+ * process either exits or performs an exec.  That is, performance
+ * counters remain enabled for fork/clone children.
+ */
+enum perfctr_opcode {
+       /* Enable UltraSparc performance counters, ARG0 is pointer
+        * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer
+        * to 64-bit accumulator for D1 counter.  ARG2 is a pointer to
+        * the initial PCR register value to use.
+        */
+       PERFCTR_ON,
+
+       /* Disable UltraSparc performance counters.  The PCR is written
+        * with zero and the user counter accumulator pointers and
+        * working PCR register value are forgotten.
+        */
+       PERFCTR_OFF,
+
+       /* Add current D0 and D1 PIC values into user pointers given
+        * in PERFCTR_ON operation.  The PIC is cleared before returning.
+        */
+       PERFCTR_READ,
+
+       /* Clear the PIC register. */
+       PERFCTR_CLRPIC,
+
+       /* Begin using a new PCR value, the pointer to which is passed
+        * in ARG0.  The PIC is also cleared after the new PCR value is
+        * written.
+        */
+       PERFCTR_SETPCR,
+
+       /* Store in pointer given in ARG0 the current PCR register value
+        * being used.
+        */
+       PERFCTR_GETPCR
+};
+
+/* I don't want the kernel's namespace to be polluted with this
+ * stuff when this file is included.  --DaveM
+ */
+#ifndef __KERNEL__
+
+#define  PRIV 0x00000001
+#define  USR  0x00000002
+#define  SYS  0x00000004
+
+/* Pic.S0 Selection Bit Field Encoding  */
+#define  CYCLE_CNT            0x00000000
+#define  INSTR_CNT            0x00000010
+#define  DISPATCH0_IC_MISS    0x00000020
+#define  DISPATCH0_STOREBUF   0x00000030
+#define  IC_REF               0x00000080
+#define  DC_RD                0x00000090
+#define  DC_WR                0x000000A0
+#define  LOAD_USE             0x000000B0
+#define  EC_REF               0x000000C0
+#define  EC_WRITE_HIT_RDO     0x000000D0
+#define  EC_SNOOP_INV         0x000000E0
+#define  EC_RD_HIT            0x000000F0
+
+/* Pic.S1 Selection Bit Field Encoding  */
+#define  CYCLE_CNT_D1         0x00000000
+#define  INSTR_CNT_D1         0x00000800
+#define  DISPATCH0_IC_MISPRED 0x00001000
+#define  DISPATCH0_FP_USE     0x00001800
+#define  IC_HIT               0x00004000
+#define  DC_RD_HIT            0x00004800
+#define  DC_WR_HIT            0x00005000
+#define  LOAD_USE_RAW         0x00005800
+#define  EC_HIT               0x00006000
+#define  EC_WB                0x00006800
+#define  EC_SNOOP_CB          0x00007000
+#define  EC_IT_HIT            0x00007800
+
+struct vcounter_struct {
+  unsigned long long vcnt0;
+  unsigned long long vcnt1;
+};
+
+#endif /* !(__KERNEL__) */
+
+#endif /* !(PERF_COUNTER_API) */
index e117243..ba204ce 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: pgtable.h,v 1.90 1998/09/24 03:21:56 davem Exp $
+/* $Id: pgtable.h,v 1.95 1998/10/22 03:05:57 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -169,10+169,9 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
 #define flush_cache_range(mm, start, end)      flushw_user()
 #define flush_cache_page(vma, page)            flushw_user()
 
-extern void flush_page_to_ram(unsigned long page);
-
-/* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
+/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_icache_range(start, end)         do { } while (0)
+#define flush_page_to_ram(page)                        do { } while (0)
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
 
@@ -379,7+378,7 @@ extern __inline__ pgd_t *get_pgd_fast(void)
                if(ret) {
                        struct page *page = mem_map + MAP_NR(ret);
                        
-                       clear_page(ret);
+                       memset(ret, 0, PAGE_SIZE);
                        (unsigned long)page->pprev_hash = 2;
                        (unsigned long *)page->next_hash = pgd_quicklist;
                        pgd_quicklist = (unsigned long *)page;
@@ -409,7+408,7 @@ extern __inline__ pgd_t *get_pgd_fast(void)
        } else {
                ret = (unsigned long *) __get_free_page(GFP_KERNEL);
                if(ret)
-                       clear_page(ret);
+                       memset(ret, 0, PAGE_SIZE);
        }
        return (pgd_t *)ret;
 }
@@ -562,26+561,41 @@ extern void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbu
 #define mmu_lockarea(vaddr, len)               (vaddr)
 #define mmu_unlockarea(vaddr, len)             do { } while(0)
 
+/* There used to be some funny code here which tried to guess which
+ * TLB wanted the mapping, that wasn't accurate enough to justify it's
+ * existance.  The real way to do that is to have each TLB miss handler
+ * pass in a distinct code to do_sparc64_fault() and do it more accurately
+ * there.
+ *
+ * What we do need to handle here is prevent I-cache corruption.  The
+ * deal is that the I-cache snoops stores from other CPUs and all DMA
+ * activity, however stores from the local processor are not snooped.
+ * The dynamic linker and our signal handler mechanism take care of
+ * the cases where they write into instruction space, but when a page
+ * is copied in the kernel and then executed in user-space is not handled
+ * right.  This leads to corruptions if things are "just right", consider
+ * the following scenerio:
+ * 1) Process 1 frees up a page that was used for the PLT of libc in
+ *    it's address space.
+ * 2) Process 2 writes into a page in the PLT of libc for the first
+ *    time.  do_wp_page() copies the page locally, the local I-cache of
+ *    the processor does not notice the writes during the page copy.
+ *    The new page used just so happens to be the one just freed in #1.
+ * 3) After the PLT write, later the cpu calls into an unresolved PLT
+ *    entry, the CPU executes old instructions from process 1's PLT
+ *    table.
+ * 4) Splat.
+ */
+extern void flush_icache_page(unsigned long phys_page);
 #define update_mmu_cache(__vma, __address, _pte) \
-__asm__ __volatile__( \
-       "rdpr   %%pstate, %%g1\n\t" \
-       "wrpr   %%g1, %0, %%pstate\n\t" \
-       "brz,pt %1, 1f\n\t" \
-       " mov   %2, %%g2\n\t" \
-       "stxa   %3, [%%g2] %5\n\t" \
-       "ba,pt  %%xcc, 2f\n\t" \
-       " stxa  %4, [%%g0] %6\n\t" \
-"1:    stxa    %3, [%%g2] %7\n\t" \
-"      stxa    %4, [%%g0] %8\n\t" \
-"2:    wrpr    %%g1, 0x0, %%pstate\n" \
-       : /* no outputs */ \
-       : "i" (PSTATE_IE), \
-          "r" (((__vma)->vm_flags&(VM_READ|VM_WRITE|VM_EXEC))==(VM_READ|VM_EXEC)), \
-         "i" (TLB_TAG_ACCESS), \
-         "r" ((__address) | ((__vma)->vm_mm->context & 0x3ff)), \
-         "r" (pte_val(_pte)), "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_IN), \
-         "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_IN) \
-       : "g1", "g2")
+do { \
+       unsigned short __flags = ((__vma)->vm_flags); \
+       if ((__flags & VM_EXEC) != 0 && \
+           ((pte_val(_pte) & (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED)) == \
+            (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED))) { \
+               flush_icache_page(pte_page(_pte) - page_offset); \
+       } \
+} while(0)
 
 /* Make a non-present pseudo-TTE. */
 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
index ab43482..a257475 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: processor.h,v 1.49 1998/07/31 10:42:40 jj Exp $
+/* $Id: processor.h,v 1.51 1998/10/21 03:21:19 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -61,6+61,11 @@ struct thread_struct {
        unsigned long sig_address __attribute__ ((aligned (8)));
        unsigned long sig_desc;
        
+       /* Performance counter state */
+       u64 *user_cntd0, *user_cntd1;
+       u64 kernel_cntd0, kernel_cntd1;
+       u64 pcr_reg;
+
        unsigned char fpdepth;
        unsigned char fpsaved[7];
        unsigned char gsr[7];
@@ -74,6+79,7 @@ struct thread_struct {
 #define SPARC_FLAG_NEWSIGNALS   0x040    /* task wants new-style signals */
 #define SPARC_FLAG_32BIT        0x080    /* task is older 32-bit binary */
 #define SPARC_FLAG_NEWCHILD     0x100    /* task is just-spawned child process */
+#define SPARC_FLAG_PERFCTR     0x200    /* task has performance counters active */
 
 #define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
                    PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
@@ -91,6+97,8 @@ struct thread_struct {
    { 0, 0, 0, 0, 0, 0, 0, },                                   \
 /* sig_address, sig_desc */                                    \
    0,           0,                                             \
+/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
+   0,          0,          0,           0,            0,       \
 /* fpdepth, fpsaved, gsr,   xfsr */                            \
    0,       { 0 },   { 0 }, { 0 },                             \
 }
index 22e9da3..12fa487 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: psrcompat.h,v 1.4 1997/06/20 11:54:39 davem Exp $ */
+/* $Id: psrcompat.h,v 1.5 1998/10/06 09:28:39 jj Exp $ */
 #ifndef _SPARC64_PSRCOMPAT_H
 #define _SPARC64_PSRCOMPAT_H
 
 #define PSR_VERS    0x0f000000         /* cpu-version field          */
 #define PSR_IMPL    0xf0000000         /* cpu-implementation field   */
 
+#define PSR_V8PLUS  0xff000000         /* fake impl/ver, meaning a 64bit CPU is present */
+#define PSR_XCC            0x000f0000         /* if PSR_V8PLUS, this is %xcc */
+
 extern inline unsigned int tstate_to_psr(unsigned long tstate)
 {
-       unsigned long vers;
-
-       __asm__ __volatile__("rdpr      %%ver, %0" : "=r" (vers));
        return ((tstate & TSTATE_CWP)                   |
                PSR_S                                   |
                ((tstate & TSTATE_ICC) >> 12)           |
-               (((vers << 8) >> 32) & PSR_IMPL)        |
-               (((vers << 24) >> 36) & PSR_VERS));
+               ((tstate & TSTATE_XCC) >> 20)           |
+               PSR_V8PLUS);
 }
 
 extern inline unsigned long psr_to_tstate_icc(unsigned int psr)
 {
-       return ((unsigned long)(psr & PSR_ICC)) << 12;
+       unsigned long tstate = ((unsigned long)(psr & PSR_ICC)) << 12;
+       if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS)
+               tstate |= ((unsigned long)(psr & PSR_XCC)) << 20;
+       return tstate;
 }
 
 #endif /* !(_SPARC64_PSRCOMPAT_H) */
index 09146f3..169e88d 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sab82532.h,v 1.3 1997/09/03 11:55:04 ecd Exp $
+/* $Id: sab82532.h,v 1.4 1998/10/25 23:04:29 ecd Exp $
  * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -143,7+143,7 @@ struct sab82532 {
        int                              xmit_fifo_size;
        int                              recv_fifo_size;
        int                              custom_divisor;
-       int                              quot;
+       int                              baud;
        int                              x_char;
        int                              close_delay;
        unsigned short                   closing_wait;
index 4a5912b..b0eb139 100644 (file)
@@ -24,17+24,24 @@ extern void __up(struct semaphore * sem);
 
 #define wake_one_more(sem)      atomic_inc(&sem->waking);
 
-#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; \
-})
+static __inline__ int waking_non_zero(struct semaphore *sem)
+{
+       int ret;
+
+       __asm__ __volatile__("
+1:     ldsw            [%1], %%g5
+       brlez,pt        %%g5, 2f
+        mov            0, %0
+       sub             %%g5, 1, %%g7
+       cas             [%1], %%g5, %%g7
+       cmp             %%g5, %%g7
+       bne,pn          %%icc, 1b
+        mov            1, %0
+2:"    : "=r" (ret)
+       : "r" (&((sem)->waking))
+       : "g5", "g7", "cc", "memory");
+       return ret;
+}
 
 extern __inline__ void down(struct semaphore * sem)
 {
index 102e733..4ce040a 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: sigcontext.h,v 1.10 1997/12/11 15:16:11 jj Exp $ */
+/* $Id: sigcontext.h,v 1.11 1998/10/06 09:28:37 jj Exp $ */
 #ifndef __SPARC64_SIGCONTEXT_H
 #define __SPARC64_SIGCONTEXT_H
 
@@ -77,6+77,14 @@ typedef struct {
        unsigned   long si_fprs;
 } __siginfo_fpu_t;
 
+/* This magic should be in g_upper[0] for all upper parts
+   to be valid.  */
+#define SIGINFO_EXTRA_V8PLUS_MAGIC     0x130e269
+typedef struct {
+       unsigned   int g_upper[8];
+       unsigned   int o_upper[8];
+} siginfo_extra_v8plus_t;
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC64_SIGCONTEXT_H) */
index b074a05..f15e6e7 100644 (file)
@@ -34,16+34,16 @@ extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 struct cpuinfo_sparc {
        /* Dcache line 1 */
        unsigned long   irq_count;
+       unsigned long   bh_count;
        unsigned int    multiplier;
        unsigned int    counter;
-       unsigned long   pgcache_size;
-       unsigned long   pgdcache_size;
+       unsigned long   udelay_val;
 
        /* Dcache line 2 */
-       unsigned long   *pgd_cache;
+       unsigned long   pgcache_size;
        unsigned long   *pte_cache;
-       unsigned long   udelay_val;
-       unsigned long   dummy;
+       unsigned long   pgdcache_size;
+       unsigned long   *pgd_cache;
 };
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
index e62326a..88a9e8b 100644 (file)
@@ -3,6+3,7 @@
  *
  * Default SMP lock implementation
  */
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <asm/spinlock.h>
 
@@ -36,14+37,14 @@ do { \
  * so we only need to worry about other
  * CPU's.
  */
-extern __inline__ void lock_kernel(void)
-{
-       if (!++current->lock_depth)
-               spin_lock(&kernel_flag);
-}
+#define lock_kernel() \
+do { \
+       if (!++current->lock_depth) \
+               spin_lock(&kernel_flag); \
+} while(0)
 
-extern __inline__ void unlock_kernel(void)
-{
-       if (--current->lock_depth < 0)
-               spin_unlock(&kernel_flag);
-}
+#define unlock_kernel() \
+do { \
+       if (--current->lock_depth < 0) \
+               spin_unlock(&kernel_flag); \
+} while(0)
dissimilarity index 85%
index 9fe325f..a8de6fb 100644 (file)
-/* softirq.h: 64-bit Sparc soft IRQ support.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef __SPARC64_SOFTIRQ_H
-#define __SPARC64_SOFTIRQ_H
-
-#include <asm/atomic.h>
-#include <asm/hardirq.h>
-
-/* 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.
- */
-
-#define get_active_bhs()       (bh_mask & bh_active)
-
-#ifndef __SMP__
-
-extern int __sparc64_bh_counter;
-
-#define softirq_trylock(cpu)   (__sparc64_bh_counter ? 0 : (__sparc64_bh_counter=1))
-#define softirq_endlock(cpu)   (__sparc64_bh_counter = 0)
-#define clear_active_bhs(x)    (bh_active &= ~(x))
-#define synchronize_bh()       barrier() /* XXX implement SMP version -DaveM */
-
-#define init_bh(nr, routine)   \
-do {   int ent = nr;           \
-       bh_base[ent] = routine; \
-       bh_mask_count[ent] = 0; \
-       bh_mask |= 1 << ent;    \
-} while(0)
-
-#define remove_bh(nr)          \
-do {   int ent = nr;           \
-       bh_base[ent] = NULL;    \
-       bh_mask &= ~(1 << ent); \
-} while(0)
-
-#define mark_bh(nr)            (bh_active |= (1 << (nr)))
-
-#define disable_bh(nr)         \
-do {   int ent = nr;           \
-       bh_mask &= ~(1 << ent); \
-       bh_mask_count[ent]++;   \
-       barrier();              \
-} while(0)
-
-#define enable_bh(nr)                  \
-do {   int ent = nr;                   \
-       barrier();                      \
-       if (!--bh_mask_count[ent])      \
-               bh_mask |= 1 << ent;    \
-} while(0)
-
-#define start_bh_atomic() do { __sparc64_bh_counter++; barrier(); } while(0)
-
-#define end_bh_atomic()          do { barrier(); __sparc64_bh_counter--; } while(0)
-
-#else /* (__SMP__) */
-
-extern atomic_t __sparc64_bh_counter;
-
-#define start_bh_atomic() \
-       do { atomic_inc(&__sparc64_bh_counter); synchronize_irq(); } while(0)
-
-#define end_bh_atomic()        atomic_dec(&__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;                                   \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_base[ent] = routine;                         \
-       bh_mask_count[ent] = 0;                         \
-       bh_mask |= 1 << ent;                            \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define remove_bh(nr)                                  \
-do {   unsigned long flags;                            \
-       int ent = nr;                                   \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_base[ent] = NULL;                            \
-       bh_mask &= ~(1 << ent);                         \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define mark_bh(nr)                                    \
-do {   unsigned long flags;                            \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_active |= (1 << nr);                         \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define disable_bh(nr)                                 \
-do {   unsigned long flags;                            \
-       int ent = nr;                                   \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_mask &= ~(1 << ent);                         \
-       bh_mask_count[ent]++;                           \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define enable_bh(nr)                                  \
-do {   unsigned long flags;                            \
-       int ent = nr;                                   \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       if (!--bh_mask_count[ent])                      \
-               bh_mask |= 1 << ent;                    \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#define softirq_trylock(cpu)                                   \
-({                                                             \
-       int ret = 1;                                            \
-       if(atomic_add_return(1, &__sparc64_bh_counter) != 1) {  \
-               atomic_dec(&__sparc64_bh_counter);              \
-               ret = 0;                                        \
-       }                                                       \
-       ret;                                                    \
-})
-#define softirq_endlock(cpu)   atomic_dec(&__sparc64_bh_counter)
-#define clear_active_bhs(mask)                         \
-do {   unsigned long flags;                            \
-       spin_lock_irqsave(&global_bh_lock, flags);      \
-       bh_active &= ~(mask);                           \
-       spin_unlock_irqrestore(&global_bh_lock, flags); \
-} while(0)
-
-#endif /* (__SMP__) */
-
-#endif /* !(__SPARC64_SOFTIRQ_H) */
+/* softirq.h: 64-bit Sparc soft IRQ support.
+ *
+ * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_SOFTIRQ_H
+#define __SPARC64_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+#ifndef __SMP__
+extern unsigned int local_bh_count;
+#else
+#define local_bh_count         (cpu_data[smp_processor_id()].bh_count)
+#endif
+
+/* 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.
+ */
+
+#define get_active_bhs()       (bh_mask & bh_active)
+#define clear_active_bhs(mask)                 \
+       __asm__ __volatile__(                   \
+"1:    ldx     [%1], %%g7\n"                   \
+"      andn    %%g7, %0, %%g5\n"               \
+"      casx    [%1], %%g7, %%g5\n"             \
+"      cmp     %%g7, %%g5\n"                   \
+"      bne,pn  %%xcc, 1b\n"                    \
+"       nop"                                   \
+       : /* no outputs */                      \
+       : "HIr" (mask), "r" (&bh_active)        \
+       : "g5", "g7", "cc", "memory")
+
+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);
+}
+
+#ifndef __SMP__
+
+extern inline void start_bh_atomic(void)
+{
+       local_bh_count++;
+       barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+       barrier();
+       local_bh_count--;
+}
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock(cpu)   (local_bh_count ? 0 : (local_bh_count=1))
+#define softirq_endlock(cpu)   (local_bh_count = 0)
+#define synchronize_bh()       barrier()
+
+#else /* (__SMP__) */
+
+extern atomic_t global_bh_lock;
+extern spinlock_t global_bh_count;
+
+extern void synchronize_bh(void);
+
+static inline void start_bh_atomic(void)
+{
+       atomic_inc(&global_bh_lock);
+       synchronize_bh();
+}
+
+static inline void end_bh_atomic(void)
+{
+       atomic_dec(&global_bh_lock);
+}
+
+/* These are for the IRQs testing the lock */
+static inline int softirq_trylock(int cpu)
+{
+       if (spin_trylock(&global_bh_count)) {
+               if (atomic_read(&global_bh_lock) == 0) {
+                       ++(cpu_data[cpu].bh_count);
+                       return 1;
+               }
+               spin_unlock(&global_bh_count);
+       }
+       return 0;
+}
+
+static inline void softirq_endlock(int cpu)
+{
+       (cpu_data[cpu].bh_count)--;
+       spin_unlock(&global_bh_count);
+}
+
+#endif /* (__SMP__) */
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+       bh_mask &= ~(1 << nr);
+       bh_mask_count[nr]++;
+       synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+       if (!--bh_mask_count[nr])
+               bh_mask |= 1 << nr;
+}
+
+#endif /* !(__SPARC64_SOFTIRQ_H) */
index 4e2dd6b..5c0133d 100644 (file)
 
 #ifndef __SMP__
 
-#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { }
-#else
-  typedef unsigned char spinlock_t;
-  #define SPIN_LOCK_UNLOCKED 0
-#endif
+typedef unsigned char spinlock_t;
+#define SPIN_LOCK_UNLOCKED 0
 
 #define spin_lock_init(lock)   do { } while(0)
 #define spin_lock(lock)                do { } while(0)
@@ -58,6+53,11 @@ typedef struct { } rwlock_t;
 
 #else /* !(__SMP__) */
 
+/* To get debugging spinlocks which detect and catch
+ * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
+ * specific makefile and rebuild your kernel.
+ */
+
 /* All of these locking primitives are expected to work properly
  * even in an RMO memory model, which currently is what the kernel
  * runs in.
@@ -71,10+71,13 @@ typedef struct { } rwlock_t;
  * must be pre-V9 branches.
  */
 
+#ifndef SPIN_LOCK_DEBUG
+
 typedef unsigned char spinlock_t;
 #define SPIN_LOCK_UNLOCKED     0
 
 #define spin_lock_init(lock)   (*((unsigned char *)(lock)) = 0)
+#define spin_is_locked(lock)   (*((volatile unsigned char *)(lock)) != 0)
 
 #define spin_unlock_wait(lock) \
 do {   membar("#LoadLoad");    \
@@ -177,8+180,42 @@ extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long fl
        : "memory");
 }
 
+#else /* !(SPIN_LOCK_DEBUG) */
+
+typedef struct {
+       unsigned char lock;
+       unsigned int owner_pc, owner_cpu;
+} spinlock_t;
+#define SPIN_LOCK_UNLOCKED { 0, 0, NO_PROC_ID }
+#define spin_lock_init(__lock) \
+do {   (__lock)->lock = 0; \
+       (__lock)->owner_pc = 0; \
+       (__lock)->owner_cpu = NO_PROC_ID; \
+} while(0)
+#define spin_is_locked(__lock) (*((volatile unsigned char *)(&((__lock)->lock))) != 0)
+#define spin_unlock_wait(__lock)       \
+do { \
+       membar("#LoadLoad"); \
+} while(*((volatile unsigned char *)(&((__lock)->lock))))
+
+extern void _do_spin_lock (spinlock_t *lock, char *str);
+extern void _do_spin_unlock (spinlock_t *lock);
+extern int _spin_trylock (spinlock_t *lock);
+
+#define spin_trylock(lp)       _spin_trylock(lp)
+#define spin_lock(lock)                _do_spin_lock(lock, "spin_lock")
+#define spin_lock_irq(lock)    do { __cli(); _do_spin_lock(lock, "spin_lock_irq"); } while(0)
+#define spin_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_spin_lock(lock, "spin_lock_irqsave"); } while(0)
+#define spin_unlock(lock)      _do_spin_unlock(lock)
+#define spin_unlock_irq(lock)  do { _do_spin_unlock(lock); __sti(); } while(0)
+#define spin_unlock_irqrestore(lock, flags) do { _do_spin_unlock(lock); __restore_flags(flags); } while(0)
+
+#endif /* SPIN_LOCK_DEBUG */
+
 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
 
+#ifndef SPIN_LOCK_DEBUG
+
 typedef unsigned long rwlock_t;
 #define RW_LOCK_UNLOCKED       0
 
@@ -278,6+315,58 @@ extern __inline__ void write_unlock(rwlock_t *rw)
 #define write_unlock_irqrestore(lock, flags) \
        do { write_unlock(lock); __restore_flags(flags); } while (0)
 
+#else /* !(SPIN_LOCK_DEBUG) */
+
+typedef struct {
+       unsigned long lock;
+       unsigned int writer_pc, writer_cpu;
+       unsigned int reader_pc[4];
+} rwlock_t;
+#define RW_LOCK_UNLOCKED       { 0, 0, NO_PROC_ID, { 0, 0, 0, 0 } }
+
+extern void _do_read_lock(rwlock_t *rw, char *str);
+extern void _do_read_unlock(rwlock_t *rw, char *str);
+extern void _do_write_lock(rwlock_t *rw, char *str);
+extern void _do_write_unlock(rwlock_t *rw);
+
+#define read_lock(lock)        \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _do_read_lock(lock, "read_lock"); \
+       __restore_flags(flags); \
+} while(0)
+#define read_lock_irq(lock)    do { __cli(); _do_read_lock(lock, "read_lock_irq"); } while(0)
+#define read_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_read_lock(lock, "read_lock_irqsave"); } while(0)
+
+#define read_unlock(lock) \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _do_read_unlock(lock, "read_unlock"); \
+       __restore_flags(flags); \
+} while(0)
+#define read_unlock_irq(lock)  do { _do_read_unlock(lock, "read_unlock_irq"); __sti() } while(0)
+#define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0)
+
+#define write_lock(lock) \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _do_write_lock(lock, "write_lock"); \
+       __restore_flags(flags); \
+} while(0)
+#define write_lock_irq(lock)   do { __cli(); _do_write_lock(lock, "write_lock_irq"); } while(0)
+#define write_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_write_lock(lock, "write_lock_irqsave"); } while(0)
+
+#define write_unlock(lock) \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _do_write_unlock(lock); \
+       __restore_flags(flags); \
+} while(0)
+#define write_unlock_irq(lock) do { _do_write_unlock(lock); __sti(); } while(0)
+#define write_unlock_irqrestore(lock, flags) do { _do_write_unlock(lock); __restore_flags(flags); } while(0)
+
+#endif /* SPIN_LOCK_DEBUG */
+
 #endif /* __SMP__ */
 
 #endif /* !(__ASSEMBLY__) */
index e08ed5b..c1a6707 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: string.h,v 1.12 1998/10/04 08:44:27 davem Exp $
+/* $Id: string.h,v 1.14 1998/10/20 03:09:18 jj Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -65,23+65,7 @@ extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_si
 
 #define __HAVE_ARCH_MEMSET
 
-extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
-{
-       extern __kernel_size_t __bzero(void *, __kernel_size_t);
-       extern void *__bzero_1page(void *);
-
-       if(!c) {
-               if (count == 8192)
-                       __bzero_1page(s);
-               else
-                       __bzero(s, count);
-       } else {
-               __memset(s, c, count);
-       }
-       return s;
-}
-
-extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count)
+extern inline void *__constant_memset(void *s, char c, __kernel_size_t count)
 {
        extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
@@ -100,10+84,9 @@ extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
 
 #undef memset
 #define memset(s, c, count) \
-(__builtin_constant_p(c) ? (__builtin_constant_p(count) ? \
-                            __constant_c_and_count_memset((s), (c), (count)) : \
-                            __constant_c_memset((s), (c), (count))) \
-                          : __nonconstant_memset((s), (c), (count)))
+(__builtin_constant_p(c) ? \
+ __constant_memset((s), (c), (count)) : \
+ __nonconstant_memset((s), (c), (count)))
 
 #define __HAVE_ARCH_MEMSCAN
 
@@ -128,14+111,19 @@ extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
 /* Now the str*() stuff... */
 #define __HAVE_ARCH_STRLEN
 
-/* Ugly but it works around a bug in our original sparc64-linux-gcc.  */
 extern __kernel_size_t __strlen(const char *);
+
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
+extern __kernel_size_t strlen(const char *);
+#else /* !EGCS */
+/* Ugly but it works around a bug in our original sparc64-linux-gcc.  */
 #undef strlen
 #define strlen(__arg0)                                 \
 ({     int __strlen_res = __strlen(__arg0) + 1;        \
        __strlen_res -= 1;                              \
        __strlen_res;                                   \
 })
+#endif /* !EGCS */
 
 #define __HAVE_ARCH_STRNCMP
 
index f103b3e..6212bd2 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: system.h,v 1.44 1998/09/21 03:57:22 davem Exp $ */
+/* $Id: system.h,v 1.47 1998/10/21 03:21:20 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -76,24+76,17 @@ extern unsigned long empty_zero_page;
 #else
 
 #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 unsigned long __global_save_flags(void);
 extern void __global_restore_flags(unsigned long flags);
 #endif
 
 #define cli()                  __global_cli()
 #define sti()                  __global_sti()
+#define save_flags(x)          ((x) = __global_save_flags())
 #define restore_flags(flags)   __global_restore_flags(flags)
+#define save_and_cli(flags)    do { save_flags(flags); cli(); } while(0)
 
 #endif
 
@@ -107,6+100,12 @@ extern void __global_restore_flags(unsigned long flags);
 
 #define flushw_all()   __asm__ __volatile__("flushw")
 
+/* Performance counter register access. */
+#define read_pcr(__p)  __asm__ __volatile__("rd        %%pcr, %0" : "=r" (__p))
+#define write_pcr(__p) __asm__ __volatile__("wr        %0, 0x0, %%pcr" : : "r" (__p));
+#define read_pic(__p)  __asm__ __volatile__("rd %%pic, %0" : "=r" (__p))
+#define reset_pic()    __asm__ __volatile__("wr        %g0, 0x0, %pic");
+
 #ifndef __ASSEMBLY__
 
 extern void synchronize_user_stack(void);
@@ -124,21+123,6 @@ extern __inline__ void flushw_user(void)
 
 #define flush_user_windows flushw_user
 
-#define DEBUG_SWITCH
-
-#ifdef DEBUG_SWITCH
-#define SWITCH_CTX_CHECK(__tsk) \
-do {   unsigned short ctx_now; \
-       ctx_now = spitfire_get_secondary_context(); \
-       if(ctx_now != (__tsk)->tss.ctx) \
-               printk("[%s:%d] Bogus ctx after switch [%x:%x]\n", \
-                      (__tsk)->comm, (__tsk)->pid, \
-                      (__tsk)->tss.ctx, ctx_now); \
-} while(0)
-#else
-#define SWITCH_CTX_CHECK(__tsk)        do { } while(0)
-#endif
-
        /* See what happens when you design the chip correctly?
         *
         * XXX What we are doing here assumes a lot about gcc reload
@@ -156,7+140,15 @@ do {       unsigned short ctx_now; \
         *           not reference %g6.
         */
 #define switch_to(prev, next)                                                  \
-do {   save_and_clear_fpu();                                                   \
+do {   if (current->tss.flags & SPARC_FLAG_PERFCTR) {                          \
+               unsigned long __tmp;                                            \
+               read_pcr(__tmp);                                                \
+               current->tss.pcr_reg = __tmp;                                   \
+               read_pic(__tmp);                                                \
+               current->tss.kernel_cntd0 += (unsigned int)(__tmp);             \
+               current->tss.kernel_cntd1 += ((__tmp) >> 32);                   \
+       }                                                                       \
+       save_and_clear_fpu();                                                   \
        __asm__ __volatile__(                                                   \
        "flushw\n\t"                                                            \
        "wrpr   %g0, 0x94, %pstate\n\t");                                       \
@@ -201,7+193,11 @@ do {       save_and_clear_fpu();                                                   \
          "l2", "l3", "l4", "l5", "l6", "l7",                                   \
          "i0", "i1", "i2", "i3", "i4", "i5",                                   \
          "o0", "o1", "o2", "o3", "o4", "o5", "o7");                            \
-       SWITCH_CTX_CHECK(current);                                              \
+       /* If you fuck with this, update ret_from_syscall code too. */          \
+       if (current->tss.flags & SPARC_FLAG_PERFCTR) {                          \
+               write_pcr(current->tss.pcr_reg);                                \
+               reset_pic();                                                    \
+       }                                                                       \
 } while(0)
 
 extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
index dfba3d8..93c14ae 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: uaccess.h,v 1.27 1998/09/23 02:04:57 davem Exp $ */
+/* $Id: uaccess.h,v 1.28 1998/10/11 06:58:34 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -45,10+45,8 @@ extern spinlock_t scheduler_lock;
 
 #define set_fs(val)                                                            \
 do {                                                                           \
-       unsigned long flags;                                                    \
        if (current->tss.current_ds.seg != val.seg) {                           \
                spin_lock(&scheduler_lock);                                     \
-               __save_and_cli(flags);                                          \
                current->tss.current_ds = (val);                                \
                if (segment_eq((val), KERNEL_DS)) {                             \
                        flushw_user ();                                         \
@@ -58,7+56,6 @@ do {                                                                          \
                }                                                               \
                spitfire_set_secondary_context(current->tss.ctx);               \
                __asm__ __volatile__("flush %g6");                              \
-               __restore_flags(flags);                                         \
                spin_unlock(&scheduler_lock);                                   \
        }                                                                       \
 } while(0)
index 8a8ae96..2db3c15 100644 (file)
@@ -1,4+1,4 @@
-/* $Id: unistd.h,v 1.22 1998/09/13 04:33:14 davem Exp $ */
+/* $Id: unistd.h,v 1.23 1998/10/07 01:28:02 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
 #define __NR_chmod               15 /* Common                                      */
 #define __NR_lchown              16 /* Common                                      */
 #define __NR_brk                 17 /* Common                                      */
-/* #define __NR_ni_syscall       18    ENOSYS under SunOS                          */
+#define __NR_perfctr             18 /* Performance counter operations              */
 #define __NR_lseek               19 /* Common                                      */
 #define __NR_getpid              20 /* Common                                      */
 #define __NR_capget             21 /* Linux Specific                              */
index a5fdf3a..34c364b 100644 (file)
 #define IFF_PORTSEL    0x2000          /* can set media type           */
 #define IFF_AUTOMEDIA  0x4000          /* auto media select active     */
 #define IFF_NODYNARP   0x8000          /* use static ARP only (HIPPI)  */
+
+#ifdef __KERNEL__
 /*
  * The ifaddr structure contains information about one address
  * of an interface.  They are maintained by the different address
@@ -66,6+68,8 @@ struct ifaddr
 #define        ifa_broadaddr   ifa_ifu.ifu_broadaddr   /* broadcast address    */
 #define        ifa_dstaddr     ifa_ifu.ifu_dstaddr     /* other end of link    */
 
+#endif /* __KERNEL__ */ 
+
 /*
  *     Device mapping structure. I'd just gone off and designed a 
  *     beautiful scheme using only loadable modules with arguments
@@ -115,7+119,7 @@ struct ifreq
                struct  ifmap ifru_map;
                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
                char    ifru_newname[IFNAMSIZ];
-               __kernel_caddr_t        ifru_data;
+               char *  ifru_data;
        } ifr_ifru;
 };
 
@@ -148,7+152,7 @@ struct ifconf
        int     ifc_len;                        /* size of buffer       */
        union 
        {
-               __kernel_caddr_t        ifcu_buf;
+               char *                  ifcu_buf;
                struct  ifreq           *ifcu_req;
        } ifc_ifcu;
 };
index 20fe4fa..2250420 100644 (file)
 #include <linux/linkage.h>
 
 /* Optimization barrier */
-#define barrier() __asm__("": : :"memory")
+/* The "volatile" is due to gcc bugs */
+#define barrier() __asm__ __volatile__("": : :"memory")
 
 #define INT_MAX                ((int)(~0U>>1))
 #define UINT_MAX       (~0U)
index 15656ff..9ea56b7 100644 (file)
 #define LP_NOPA  0x0010
 #define LP_ERR   0x0020
 #define LP_ABORT 0x0040
-#ifdef LP_NEED_CAREFUL
+#if 0
 #define LP_CAREFUL 0x0080
 #endif
 #define LP_ABORTOPEN 0x0100
@@ -131,6+131,7 @@ struct lp_struct {
        unsigned int last_error;
        volatile unsigned int irq_detected:1;
        volatile unsigned int irq_missed:1;
+       unsigned int polled:1;
 };
 
 /*
@@ -176,7+177,7 @@ struct lp_struct {
  */
 #define LP_DELAY       50
 
-#define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE)
+#define LP_POLLED(minor) (lp_table[(minor)].polled)
 #define LP_PREEMPTED(minor) (lp_table[(minor)].dev->port->waithead != NULL)
 
 /*
index 69a94b2..008a974 100644 (file)
@@ -163,8+163,7 @@ enum
        NET_IPV4_ROUTE = 18,
        NET_IPV4_FIB_HASH = 19,
 
-/*32*/ NET_IPV4_TCP_HOE_RETRANSMITS=32,
-       NET_IPV4_TCP_TIMESTAMPS,
+/*33*/ NET_IPV4_TCP_TIMESTAMPS=33,
        NET_IPV4_TCP_WINDOW_SCALING,
        NET_IPV4_TCP_SACK,
        NET_IPV4_TCP_RETRANS_COLLAPSE,
index 0c6a015..98c2dc9 100644 (file)
@@ -17,8+17,6 @@ struct scm_cookie
        struct ucred            creds;          /* Skb credentials      */
        struct scm_fp_list      *fp;            /* Passed files         */
        unsigned long           seq;            /* Connection seqno     */
-       struct file             *file;          /* file for socket      */
-       struct socket           *sock;          /* Passed socket        */
 };
 
 extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
@@ -39,7+37,6 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
        scm->creds.uid = current->uid;
        scm->creds.gid = current->gid;
        scm->creds.pid = current->pid;
-       scm->sock      = sock;
        if (msg->msg_controllen <= 0)
                return 0;
        return __scm_send(sock, msg, scm);
index be4f66a..dcefb24 100644 (file)
@@ -194,6+194,7 @@ extern void ibmmca_scsi_setup(char *str, int *ints);
 extern void in2000_setup(char *str, int *ints);
 extern void NCR53c406a_setup(char *str, int *ints);
 extern void wd7000_setup(char *str, int *ints);
+extern void dc390_setup(char* str, int *ints);
 extern void scsi_luns_setup(char *str, int *ints);
 extern void scsi_logging_setup(char *str, int *ints);
 extern void sound_setup(char *str, int *ints);
@@ -704,6+705,9 @@ static struct kernel_param cooked_params[] __initdata = {
 #ifdef CONFIG_SCSI_IBMMCA
         { "ibmmcascsi=", ibmmca_scsi_setup },
 #endif
+#if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP)
+        { "tmscsim=", dc390_setup },
+#endif
 #ifdef CONFIG_BLK_DEV_XD
        { "xd=", xd_setup },
        { "xd_geo=", xd_manual_geo_init },
index 1812e4b..5e37f2a 100644 (file)
@@ -550,7+550,7 @@ int kswapd(void *unused)
                        do_try_to_free_page(0);
                        if (free_memory_available() > 1)
                                break;
-               } while (jiffies != start_time);
+               } while (jiffies == start_time);
        }
        /* As if we could ever get here - maybe we want to make this killable */
        kswapd_task = NULL;
index e16c4a4..c28da7e 100644 (file)
@@ -103,7+103,6 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
 void __scm_destroy(struct scm_cookie *scm)
 {
        struct scm_fp_list *fpl = scm->fp;
-       struct file *file;
        int i;
 
        if (fpl) {
@@ -112,34+111,18 @@ void __scm_destroy(struct scm_cookie *scm)
                        fput(fpl->fp[i]);
                kfree(fpl);
        }
-
-       file = scm->file;
-       if (file) {
-               scm->sock = NULL;
-               scm->file = NULL;
-               fput(file);
-       }
 }
 
-
-
-extern __inline__ int not_one_bit(unsigned val)
-{
-       return (val-1) & val;
-}
-
-
 int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
 {
        struct cmsghdr *cmsg;
-       struct file *file;
-       int acc_fd, err;
-       unsigned int scm_flags=0;
+       int err;
 
        for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
        {
                err = -EINVAL;
 
+               /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */
                if ((unsigned long)(((char*)cmsg - (char*)msg->msg_control)
                                    + cmsg->cmsg_len) > msg->msg_controllen)
                        goto error;
@@ -162,30+145,6 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
                        if (err)
                                goto error;
                        break;
-               case SCM_CONNECT:
-                       if (scm_flags)
-                               goto error;
-                       if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
-                               goto error;
-                       memcpy(&acc_fd, CMSG_DATA(cmsg), sizeof(int));
-                       p->sock = NULL;
-                       if (acc_fd != -1) {
-                               err = -EBADF;
-                               file = fget(acc_fd);
-                               if (!file)
-                                       goto error;
-                               p->file = file;
-                               err = -ENOTSOCK;
-                               if (!file->f_dentry->d_inode ||
-                                   !file->f_dentry->d_inode->i_sock)
-                                       goto error;
-                               p->sock = &file->f_dentry->d_inode->u.socket_i;
-                               err = -EINVAL;
-                               if (p->sock->state != SS_UNCONNECTED) 
-                                       goto error;
-                       }
-                       scm_flags |= MSG_SYN;
-                       break;
                default:
                        goto error;
                }
@@ -196,16+155,13 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
                kfree(p->fp);
                p->fp = NULL;
        }
-       
-       err = -EINVAL;
-       msg->msg_flags |= scm_flags;
-       scm_flags = msg->msg_flags&MSG_CTLFLAGS;
-       if (not_one_bit(scm_flags))
-               goto error;
 
-       if (!(scm_flags && p->fp))
-               return 0;
+       err = -EINVAL; 
+       if (msg->msg_flags & MSG_CTLFLAGS)
+               goto error;
 
+       return 0;
+       
 error:
        scm_destroy(p);
        return err;
index f967166..1be5618 100644 (file)
@@ -7,7+7,7 @@
  *             handler for protocols to use and generic option handler.
  *
  *
- * Version:    $Id: sock.c,v 1.73 1998/10/03 16:08:10 freitag Exp $
+ * Version:    $Id: sock.c,v 1.74 1998/10/21 05:40:38 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -294,6+294,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                {
                        char devname[IFNAMSIZ]; 
 
+                       /* Sorry... */ 
+                       if (!capable(CAP_NET_RAW)) 
+                               return -EPERM; 
+
                        /* Bind this socket to a particular device like "eth0",
                         * as specified in the passed interface name. If the
                         * name is "" or the option length is zero the socket 
index bda85a2..7c3a736 100644 (file)
@@ -1,6+1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:    $Id: arp.c,v 1.70 1998/08/26 12:03:18 davem Exp $
+ * Version:    $Id: arp.c,v 1.73 1998/10/21 05:36:02 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -1027,7+1027,7 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy
                                "%-17s0x%-10x0x%-10x%s",
                                in_ntoa(*(u32*)n->key),
                                hatype,
-                               ATF_PUBL|ATF_PERM,       
+                               ATF_PUBL|ATF_PERM,
                                "00:00:00:00:00:00");
                        size += sprintf(buffer+len+size,
                                 "     %-17s %s\n",
index eae3cf1..af1bb4a 100644 (file)
@@ -3,7+3,7 @@
  *     
  *             Alan Cox, <alan@cymru.net>
  *
- *     Version: $Id: icmp.c,v 1.46 1998/10/03 09:37:15 davem Exp $
+ *     Version: $Id: icmp.c,v 1.47 1998/10/21 05:32:24 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -359,6+359,11 @@ struct socket *icmp_socket=&icmp_inode.u.socket_i;
  *     This function is generic and could be used for other purposes
  *     too. It uses a Token bucket filter as suggested by Alexey Kuznetsov.
  *
+ *     Note that the same dst_entry fields are modified by functions in 
+ *     route.c too, but these work for packet destinations while xrlim_allow
+ *     works for icmp destinations. This means the rate limiting information
+ *     for one "ip object" is shared.
+ *
  *     RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
  *                       SHOULD allow setting of rate limits 
  *
@@ -374,6+379,7 @@ int xrlim_allow(struct dst_entry *dst, int timeout)
        if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout)
                dst->rate_tokens = XRLIM_BURST_FACTOR*timeout;
        if (dst->rate_tokens >= timeout) {
+               dst->rate_last = now;
                dst->rate_tokens -= timeout;
                return 1;
        }
index 0ef3061..9b412ba 100644 (file)
@@ -2,7+2,7 @@
  *             IP_MASQ_FTP CUSeeMe masquerading module
  *
  *
- * Version:    @(#)$Id: ip_masq_cuseeme.c,v 1.3 1998/08/29 23:51:18 davem Exp $
+ * Version:    @(#)$Id: ip_masq_cuseeme.c,v 1.4 1998/10/06 04:48:57 davem Exp $
  *
  * Author:     Richard Lynch
  *             
index 9854fc4..ee3e276 100644 (file)
@@ -2,7+2,7 @@
  *             IP_MASQ_RAUDIO  - Real Audio masquerading module
  *
  *
- * Version:    @(#)$Id: ip_masq_raudio.c,v 1.10 1998/08/29 23:51:17 davem Exp $
+ * Version:    @(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $
  *
  * Author:     Nigel Metheringham
  *             Real Time Streaming code by Progressive Networks
index 6e681af..4724e3b 100644 (file)
@@ -2,7+2,7 @@
  *             IP_MASQ_VDOLIVE  - VDO Live masquerading module
  *
  *
- * Version:    @(#)$Id: ip_masq_vdolive.c,v 1.3 1998/08/29 23:51:18 davem Exp $
+ * Version:    @(#)$Id: ip_masq_vdolive.c,v 1.4 1998/10/06 04:49:07 davem Exp $
  *
  * Author:     Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
  *             PLAnet Online Ltd
index 1a08423..9f9966b 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Dumb Network Address Translation.
  *
- * Version:    $Id: ip_nat_dumb.c,v 1.6 1998/10/03 09:37:25 davem Exp $
+ * Version:    $Id: ip_nat_dumb.c,v 1.7 1998/10/06 04:49:09 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
index 76372b4..db1d7fc 100644 (file)
@@ -1,5+1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.15 1998/06/19 13:22:33 davem Exp $
+ *  $Id: ipconfig.c,v 1.16 1998/10/21 22:27:26 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -260,12+260,12 @@ __initfunc(int ic_defaults(void))
                root_server_addr = ic_servaddr;
 
        if (ic_netmask == INADDR_NONE) {
-               if (IN_CLASSA(ic_myaddr))
-                       ic_netmask = IN_CLASSA_NET;
-               else if (IN_CLASSB(ic_myaddr))
-                       ic_netmask = IN_CLASSB_NET;
-               else if (IN_CLASSC(ic_myaddr))
-                       ic_netmask = IN_CLASSC_NET;
+               if (IN_CLASSA(ntohl(ic_myaddr)))
+                       ic_netmask = htonl(IN_CLASSA_NET);
+               else if (IN_CLASSB(ntohl(ic_myaddr)))
+                       ic_netmask = htonl(IN_CLASSB_NET);
+               else if (IN_CLASSC(ntohl(ic_myaddr)))
+                       ic_netmask = htonl(IN_CLASSC_NET);
                else {
                        printk(KERN_ERR "IP-Config: Unable to guess netmask for address %08x\n", ic_myaddr);
                        return -1;
index b64dacc..f899090 100644 (file)
@@ -7,7+7,7 @@
  *             PROC file system.  It is mainly used for debugging and
  *             statistics.
  *
- * Version:    $Id: proc.c,v 1.32 1998/10/03 09:37:42 davem Exp $
+ * Version:    $Id: proc.c,v 1.33 1998/10/21 05:44:35 davem Exp $
  *
  * Authors:    Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -55,21+55,22 @@ static inline void get__openreq(struct sock *sk, struct open_request *req,
                                char *tmpbuf, 
                                int i)
 {
-       /* FIXME: I'm not sure if the timer fields are correct. */
        sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u",
                i,
                (long unsigned int)req->af.v4_req.loc_addr,
                ntohs(sk->sport),
                (long unsigned int)req->af.v4_req.rmt_addr,
-               req->rmt_port,
+               ntohs(req->rmt_port),
                TCP_SYN_RECV,
-               0,0, /* use sizeof(struct open_request) here? */
-               0, (unsigned long)(req->expires - jiffies), /* ??? */
+               0,0, /* could print option size, but that is af dependent. */
+               1,   /* timers active (only the expire timer) */  
+               (unsigned long)(req->expires - jiffies), 
                req->retrans,
                sk->socket ? sk->socket->inode->i_uid : 0,
-               0,      /* ??? */
-               sk->socket ? sk->socket->inode->i_ino:0);
+               0,  /* non standard timer */  
+               0 /* open_requests have no inode */
+               ); 
 }
 
 /* Format a single socket into tmpbuf. */
@@ -157,6+158,9 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
  * KNOWN BUGS
  *  As in get_unix_netinfo, the buffer might be too small. If this
  *  happens, get__netinfo returns only part of the available infos.
+ *
+ *  Assumes that buffer length is a multiply of 128 - if not it will
+ *  write past the end.   
  */
 static int
 get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
@@ -172,17+176,6 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                               "  sl  local_address rem_address   st tx_queue "
                               "rx_queue tr tm->when retrnsmt   uid  timeout inode");
        pos = 128;
-/*
- *     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 do a start_bh_atomic().
- *     Why not just use lock_sock()? As far as I can see all timer routines
- *     check for sock_readers before doing anything. -AK
- *      [Disabled for now again, because it hard-locked my machine, and there
- *      is an theoretical situation then, where an user could prevent
- *      sockets from being destroyed by constantly reading /proc/net/tcp.]
- */
        SOCKHASH_LOCK(); 
        sp = pro->sklist_next;
        while(sp != (struct sock *)pro) {
@@ -196,8+189,8 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                                        continue;
                                get__openreq(sp, req, tmpbuf, i); 
                                len += sprintf(buffer+len, "%-127s\n", tmpbuf);
-                               if(len >= length)
-                                       break; 
+                               if(len >= length) 
+                                       goto out;
                        }
                }
                
@@ -215,6+208,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                sp = next;
                i++;
        }
+out: 
        SOCKHASH_UNLOCK();
        
        begin = len - (pos - offset);
@@ -222,6+216,8 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
        len -= begin;
        if(len>length)
                len = length;
+       if (len<0)
+               len = 0; 
        return len;
 } 
 
@@ -265,6+261,8 @@ int afinet_get_info(char *buffer, char **start, off_t offset, int length, int du
        len -= offset;
        if (len > length)
                len = length;
+       if (len < 0)
+               len = 0;
        return len;
 }
 
@@ -343,6+341,8 @@ int snmp_get_info(char *buffer, char **start, off_t offset, int length, int dumm
        len -= offset;
        if (len > length)
                len = length;
+       if (len < 0)
+               len = 0; 
        return len;
 }
 
@@ -379,5+379,7 @@ int netstat_get_info(char *buffer, char **start, off_t offset, int length, int d
        len -= offset;
        if (len > length)
                len = length;
+       if (len < 0)
+               len = 0; 
        return len;
 }
index ba75608..c186a89 100644 (file)
@@ -1,7+1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.35 1998/10/03 09:37:54 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.36 1998/10/21 05:26:59 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -43,7+43,6 @@ extern int sysctl_ip_dynaddr;
 /* From ip_masq.c */
 extern int sysctl_ip_masq_debug;
 
-extern int sysctl_tcp_hoe_retransmits;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_sack;
@@ -92,9+91,6 @@ int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
 
 
 ctl_table ipv4_table[] = {
-        {NET_IPV4_TCP_HOE_RETRANSMITS, "tcp_hoe_retransmits",
-         &sysctl_tcp_hoe_retransmits, sizeof(int), 0644, NULL,
-         &proc_dointvec},
         {NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps",
          &sysctl_tcp_timestamps, sizeof(int), 0644, NULL,
          &proc_dointvec},
index 32a9f91..12b17b5 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.130 1998/10/04 07:06:47 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.133 1998/10/21 05:38:53 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Andi Kleen:             Add tcp_measure_rcv_mss to make 
  *                                     connections with MSS<min(MTU,ann. MSS)
  *                                     work without delayed acks. 
+ *             Andi Kleen:             Process packets with PSH set in the
+ *                                     fast path.
  */
 
 #include <linux/config.h>
@@ -75,7+77,6 @@ extern int sysctl_tcp_fin_timeout;
 int sysctl_tcp_timestamps = 1;
 int sysctl_tcp_window_scaling = 1;
 int sysctl_tcp_sack = 1;
-int sysctl_tcp_hoe_retransmits = 1;
 
 int sysctl_tcp_syncookies = SYNC_INIT; 
 int sysctl_tcp_stdurg;
@@ -1139,7+1140,7 @@ coalesce:
        /* Zap SWALK, by moving every further SACK up by one slot.
         * Decrease num_sacks.
         */
-       for(this_sack += 1; this_sack < num_sacks; this_sack++, swalk++) {
+       for(this_sack += 1; this_sack < num_sacks-1; this_sack++, swalk++) {
                struct tcp_sack_block *next = (swalk + 1);
                swalk->start_seq = next->start_seq;
                swalk->end_seq = next->end_seq;
@@ -1745,14+1746,15 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                }
        }
 
-       flg = *(((u32 *)th) + 3);
-               
+       flg = *(((u32 *)th) + 3) & ~htonl(0x8 << 16);
+
        /*      pred_flags is 0xS?10 << 16 + snd_wnd
         *      if header_predition is to be made
         *      'S' will always be tp->tcp_header_len >> 2
         *      '?' will be 0 else it will be !0
         *      (when there are holes in the receive 
         *       space for instance)
+        *      PSH flag is ignored.
          */
 
        if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
index 2e2362b..6ec830c 100644 (file)
@@ -22,6+22,10 @@ extern void inet6_proto_init(struct net_proto *pro);
 #endif
 #endif /* INET */
 
+#ifdef CONFIG_ECONET
+extern void econet_proto_init(struct net_proto *pro);
+#endif
+
 #ifdef CONFIG_NETLINK
 extern void netlink_proto_init(struct net_proto *pro);
 #endif
@@ -153,5+157,9 @@ struct net_proto protocols[] = {
   { "X.25",    x25_proto_init },                       /* CCITT X.25 Packet Layer */
 #endif
 
+#ifdef CONFIG_ECONET
+  { "Econet",  econet_proto_init },                    /* Acorn Econet */
+#endif
+
   { NULL,      NULL            }                       /* End marker                   */
 };
close