]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.75 2.1.75
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:16 +0000 (15:14 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:16 +0000 (15:14 -0500)
227 files changed:
Documentation/Configure.help
Documentation/cyrix.txt [deleted file]
Documentation/filesystems/coda.txt
Documentation/filesystems/vfat.txt
Documentation/networking/filter.txt [new file with mode: 0644]
Documentation/networking/ipddp.txt [new file with mode: 0644]
Makefile
arch/alpha/config.in
arch/alpha/mm/fault.c
arch/i386/boot/compressed/Makefile
arch/i386/boot/compressed/misc.c
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/Makefile
arch/i386/kernel/bios32.c
arch/i386/kernel/head.S
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/irq.c
arch/i386/kernel/process.c
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/i386/kernel/smp.c
arch/i386/kernel/time.c
arch/i386/kernel/traps.c
arch/i386/lib/delay.c
arch/i386/mm/fault.c
arch/i386/mm/init.c
drivers/block/floppy.c
drivers/block/ide-disk.c
drivers/block/ide-floppy.c
drivers/block/ide-probe.c
drivers/block/ide-proc.c
drivers/block/ide-tape.c
drivers/block/ide.c
drivers/block/ide.h
drivers/block/ll_rw_blk.c
drivers/block/swim3.c
drivers/char/Makefile
drivers/char/apm_bios.c
drivers/char/bttv.c
drivers/char/mem.c
drivers/char/pc_keyb.h
drivers/char/pms.c
drivers/char/random.c
drivers/char/sysrq.c
drivers/char/tga.c
drivers/char/wdt.c
drivers/net/Config.in
drivers/net/hamradio/baycom_par.c
drivers/net/hamradio/baycom_ser_fdx.c
drivers/net/hamradio/baycom_ser_hdx.c
drivers/net/hamradio/soundmodem/sm.c
drivers/net/ipddp.c
drivers/net/ipddp.h
drivers/pci/Makefile
drivers/pci/pci.c
drivers/pci/quirks.c [new file with mode: 0644]
drivers/scsi/53c7,8xx.h
drivers/scsi/AM53C974.c
drivers/scsi/AM53C974.h
drivers/scsi/BusLogic.h
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/NCR53c406a.h
drivers/scsi/a2091.h
drivers/scsi/a3000.h
drivers/scsi/advansys.c
drivers/scsi/advansys.h
drivers/scsi/aha152x.h
drivers/scsi/aha1542.c
drivers/scsi/aha1542.h
drivers/scsi/aha1740.h
drivers/scsi/aic7xxx.h
drivers/scsi/amiga7xx.h
drivers/scsi/atari_scsi.h
drivers/scsi/constants.c
drivers/scsi/dc390.h
drivers/scsi/dtc.h
drivers/scsi/eata.h
drivers/scsi/eata_dma.h
drivers/scsi/eata_dma_proc.c
drivers/scsi/eata_pio.h
drivers/scsi/eata_pio_proc.c
drivers/scsi/esp.c
drivers/scsi/esp.h
drivers/scsi/fdomain.h
drivers/scsi/g_NCR5380.c
drivers/scsi/g_NCR5380.h
drivers/scsi/gdth.h
drivers/scsi/gvp11.h
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/ibmmca.h
drivers/scsi/ide-scsi.h
drivers/scsi/in2000.h
drivers/scsi/mac53c94.h
drivers/scsi/mesh.h
drivers/scsi/ncr53c8xx.h
drivers/scsi/pas16.h
drivers/scsi/pci2000.h
drivers/scsi/pci2220i.h
drivers/scsi/ppa.h
drivers/scsi/psi240i.h
drivers/scsi/qlogicfas.h
drivers/scsi/qlogicisp.h
drivers/scsi/qlogicpti.h
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_debug.h
drivers/scsi/scsi_error.c [new file with mode: 0644]
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_obsolete.c [new file with mode: 0644]
drivers/scsi/scsi_obsolete.h [new file with mode: 0644]
drivers/scsi/scsi_proc.c
drivers/scsi/scsi_queue.c [new file with mode: 0644]
drivers/scsi/scsi_syms.c
drivers/scsi/scsicam.c
drivers/scsi/sd.c
drivers/scsi/sd_ioctl.c
drivers/scsi/seagate.h
drivers/scsi/sg.c
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/scsi/st.c
drivers/scsi/t128.h
drivers/scsi/u14-34f.h
drivers/scsi/ultrastor.h
drivers/scsi/wd7000.h
drivers/sound/.objects
drivers/sound/.objects.orig [new file with mode: 0644]
drivers/sound/Config.in
drivers/sound/Makefile
drivers/sound/README.C931 [new file with mode: 0644]
drivers/sound/ad1848.c
drivers/sound/audio.c
drivers/sound/configure.c
drivers/sound/dev_table.h
drivers/sound/dmabuf.c
drivers/sound/gus_card.c
drivers/sound/gus_wave.c
drivers/sound/mad16.c
drivers/sound/midibuf.c
drivers/sound/sb_audio.c
drivers/sound/softoss.h
drivers/sound/sound_calls.h
drivers/sound/sound_syms.c
drivers/sound/v_midi.c [new file with mode: 0644]
drivers/sound/v_midi.h [new file with mode: 0644]
fs/Config.in
fs/attr.c
fs/binfmt_elf.c
fs/buffer.c
fs/coda/Makefile
fs/coda/cnode.c
fs/coda/coda_linux.c
fs/coda/dir.c
fs/coda/file.c
fs/coda/namecache.c [deleted file]
fs/coda/pioctl.c
fs/coda/psdev.c
fs/coda/super.c
fs/coda/symlink.c
fs/coda/sysctl.c
fs/coda/upcall.c
fs/ext2/acl.c
fs/ext2/balloc.c
fs/ext2/inode.c
fs/fat/inode.c
fs/filesystems.c
fs/minix/namei.c
fs/namei.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfsroot.c
fs/nfs/write.c
fs/nls/nls_base.c
fs/super.c
fs/sysv/namei.c
fs/umsdos/namei.c
fs/vfat/namei.c
include/asm-alpha/socket.h
include/asm-i386/bugs.h
include/asm-i386/processor.h
include/asm-i386/smp.h
include/asm-i386/socket.h
include/asm-i386/uaccess.h
include/asm-mips/socket.h
include/linux/arcdevice.h
include/linux/blkdev.h
include/linux/coda.h
include/linux/coda_cnode.h
include/linux/coda_linux.h
include/linux/coda_namecache.h [deleted file]
include/linux/coda_opstats.h
include/linux/coda_psdev.h
include/linux/elfcore.h
include/linux/filter.h [new file with mode: 0644]
include/linux/interrupt.h
include/linux/kernel.h
include/linux/nfs.h
include/linux/nfs_fs.h
include/linux/ntfs_fs.h
include/linux/pci.h
include/linux/sched.h
include/linux/timer.h
include/linux/videodev.h
include/net/sock.h
init/main.c
ipc/sem.c
kernel/ksyms.c
kernel/printk.c
kernel/sysctl.c
mm/filemap.c
net/Config.in
net/core/Makefile
net/core/filter.c [new file with mode: 0644]
net/core/sock.c
net/ipv4/fib_semantics.c
net/ipv4/ip_forward.c
net/netlink/af_netlink.c
net/netsyms.c
net/sunrpc/sched.c
scripts/Menuconfig
scripts/tkcond.c

index 821339826e285def6afc3d0d2b2fdef6c7d1f4f8..e12f0286a1281b88c91e08ed3465b44c4e93e17f 100644 (file)
@@ -601,6 +601,14 @@ CONFIG_NET_ALIAS
   info.  If you need this feature (for any protocol, like IP) say Y;
   if unsure, say N.
 
+Socket filtering
+CONFIG_FILTER
+  The Linux Socket Filter is a deviation of the Berkely Packet Filter.
+  Through Socket Filtering you can have the kernel decide whether the
+  data is good and to continue processing it. Linux Socket Filtering 
+  works on all socket types except TCP for now. See the text file
+  linux/Documentation/networking/filter.txt for more information.
+
 Network firewalls
 CONFIG_FIREWALL
   A firewall is a computer which protects a local network from the
@@ -643,17 +651,6 @@ CONFIG_SYN_COOKIES
   /etc/rc.d/rc.local) in addition.
   If unsure, say Y.
 
-Socket Security API Support (EXPERIMENTAL)
-CONFIG_NET_SECURITY
-  Enable use of the socket security API. This option only really
-  supports security (via encryption of all traffic) over IPv4 links,
-  and then only if you add a security protocol which is also supported
-  at the other end of the link; Linux itself does not include any
-  security protocols, but you can use the enskip package at
-  ftp.tik.ee.ethz.ch/pub/packages/skip/. That package also contains
-  documentation of the API to be used for secure sockets. If unsure,
-  say N.
-
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
   This is support for floppy drives on Sun Sparc workstations. Say Y
@@ -1637,12 +1634,30 @@ CONFIG_ATALK
   hear that the GNU boycott of Apple is over, so even politically
   correct people are allowed to say Y here.
 
-IP-over-DDP support
+Appletalk-IP driver support
 CONFIG_IPDDP
+  Appletalk-IP is a method Macintosh users use IP services. This driver
+  allows you to either send your IP traffic over an Appletalk network to
+  an Appletalk-IP router, or you can have your machine act as an Appletalk-IP
+  router and route Appletalk-IP traffic for your Macintosh users. Both
+  modes require seperate user-space support software, please see each
+  individual options help to get the correct URL of the software.
+
+Appletalk-IP Encapsulation support
+CONFIG_IPDDP_ENCAP
   This allows IP networking for users who only have Appletalk
   networking available.  This feature is experimental. Please see
   http://www.maths.unm.edu/~bradford/ltpc.html for support software.
 
+Appletalk-IP Decapsulation support
+CONFIG_IPDDP_DECAP
+  This allows you to provide IP services to your Appletalk users.
+  It does not matter what interface the Macs are comming into your
+  Linux box on, be it Localtalk, Ethertalk, PPPtalk, etc. The only
+  dependent variable is if the Appletalk layer supports the protocol
+  you need. User space software is required to run this driver, you
+  can pick it up at http://spacs1.spacs.k12.wi.us/~jschlst/MacGate.html
+
 Apple/Farallon LocalTalk PC card support
 CONFIG_LTPC
   This allows you to use the AppleTalk PC card to connect to LocalTalk
@@ -1952,6 +1967,20 @@ CONFIG_SCSI_CONSTANTS
   understand if you say Y here; it will enlarge your kernel by about
   12KB. If in doubt, say Y.
 
+SCSI logging facility
+CONFIG_SCSI_LOGGING
+  This turns on a logging facility that can be used to debug a number
+  of problems.  Normally no logging output will appear, but you can
+  enable logging with a shell command like: 
+  'echo "scsi log token [level]" > /proc/scsi/scsi'
+  There are a number of things that can be used for 'token', and this
+  allows you to select the types of information you want, and the level
+  allows you to select the level of verbosity.  If you say 'N' here,
+  it may be harder to track down some types of scsi problems.  If
+  you say 'Y' here your kernel will be somewhat larger, but there
+  should be no noticable performance impact as long as you have logging
+  turned off.
+
 AdvanSys SCSI support
 CONFIG_SCSI_ADVANSYS
   This is a driver for all SCSI host adapters manufactured by
@@ -2586,6 +2615,15 @@ CONFIG_SCSI_PPA_HAVE_PEDANTIC
   your EPP chipset is from the SMC series, you are likely to have to
   set this value greater than 0.
 
+SCSI Debug host simulator.
+CONFIG_SCSI_DEBUG
+  This is a host adapter simulator that can be programmed to simulate a
+  large number of conditions that could occur on a real bus.  The advantage
+  is that many hard to reproduce problems can be tested in a controlled
+  environment where there is reduced risk of losing important data.
+  This is primarily of use to people trying to debug the middle and upper
+  layers of the scsi subsystem.
+
 Network device support?
 CONFIG_NETDEVICES
   You can say N here in case you don't intend to connect to any other
@@ -6231,123 +6269,6 @@ CONFIG_SUN_OPENPROMIO
   removed from the running kernel whenever you want), say M and read
   Documentation/modules.txt. If unsure, say Y.
 
-Support for Cyrix processors
-CONFIG_CYRIX
-  This enables recognition of Cyrix processors. Without it
-  /proc/cpuinfo will list your processor as an unknown model
-  of Cyrix. With it it will list the correct details. It should
-  be safe to say Y here regardless of what processor you are
-  actually using. If this option is not enabled none of the
-  Cyrix feature options are available.
-
-Enable suspend on halt power saving feature
-CONFIG_CYRIX_SUSP_HLT
-  Suspend on halt causes the processor to enter a low power state
-  when the "hlt" instruction is executed. This is disabled at
-  power up and many BIOSs leave it that way. You probably want it
-  enabled since it dramatically reduces the operating temperature
-  of the processor. In a few rare cases there may be problems
-  with some bus master DMA cards if this is enabled.
-
-No I/O recovery delays
-CONFIG_CYRIX_FAST_IO
-  Historically programmers used "jmp $+2" instructions to create
-  delays between I/O instructions. The branch prediction of 5x86
-  and higher processors renders this ineffective and so a selectable
-  delay is implemented for I/O instructions in the processor. Linux
-  uses dummy I/O instructions where necessary rather than jumps
-  and so the extra processor imposed delay should not be necessary.
-  Enabling this option removes this delay.
-
-5x86 performance features
-CONFIG_CYRIX_5X86
-  The Cyrix 5x86 has several performance feature which are enabled
-  using on-chip registers. This code attempts to ensure that the
-  useful features are set to suit Linux. Read Documentation/CPU/Cyrix
-  before enabling this.
-    WARNING: If this is enabled you may find that the only way to
-  reboot is to power cycle the machine. Even a hard reboot seems
-  to fail on some systems.
-
-6x86 performance features
-CONFIG_CYRIX_6X86
-  The Cyrix 6x86 has several performance feature which are enabled
-  using on-chip registers. Most are normally enabled by the BIOS
-  however this code ensures that all the useful ones are set to
-  suit Linux. Read Documentation/CPU/Cyrix before enabling this.
-
-Avoid unnecessary locked cycles
-CONFIG_CYRIX_6X86_NOLOCK
-  Enabling this option causes the 6x86 not to use locked bus cycles
-  except for page table access and interrupt acknowledge cycles.
-  This allows the data used by descriptor tables, xchg instructions
-  and instructions preceeded by the LOCK prefix to be cached leading
-  to improved performance. Enabling this option has no effect if
-  an SMP kernel is being built - SMP requires locked cycles to
-  guarantee processor synchronization.
-
-Allocate L1 cache lines on write misses
-CONFIG_CYRIX_6X86_WTALLOC
-  If this is enabled L1 cache write misses will cause a cache line
-  to be allocated. This may result in increased performance. On the
-  other hand it may cause excessive trashing of the L1 cache when
-  copying or zeroing pages. In general you _probably_ win...
-
-Branch Target Buffer features
-CONFIG_CYRIX_6X86_BTB
-  The Cyrix 6x86 has branch prediction logic which is normally
-  only set to handle short branches (as in small loops and ifs).
-  This code attempts on configure the branch prediction logic
-  appropriately. Read Documentation/CPU/Cyrix before enabling this.
-
-Variable sized paging mechanism (VSPM)
-CONFIG_CYRIX_6X86_VSPM
-  Variable sized paging mechanism (VSPM) is a feature of the Cyrix
-  6x86 family of processors that allows large regions of memory
-  to be mapped in one go, significantly reducing the amount of work
-  the MMU has to do compared with traditional paging. However VSPM
-  is known to be buggy in many 6x86 chip revisions. Please read
-  Documentation/CPU/Cyrix before enabling this.
-    WARNING: If this is enabled you may find that the only way to
-  reboot is to power cycle the machine. Even a hard reboot seems
-  to fail on some systems.
-
-Allocate L1 cache lines on write misses
-CONFIG_AMD_K5_WTALLOC
-  If this is enabled L1 cache write misses will cause a cache line
-  to be allocated. This may result in increased performance. On the
-  other hand it may cause excessive trashing of the L1 cache when
-  copying or zeroing pages. In general you _probably_ win...
-
-Allocate L1 cache lines on write misses
-CONFIG_AMD_K6_WTALLOC
-  If this is enabled L1 cache write misses will cause a cache line
-  to be allocated. This may result in increased performance. On the
-  other hand it may cause excessive trashing of the L1 cache when
-  copying or zeroing pages. In general you _probably_ win...
-
-Use write cacheability detection
-CONFIG_AMD_K6_WTALLOC_WCDE
-  Write cacheability detection requires the system logic to assert
-  the cache enable bus signal during a write cycle. Some chipsets
-  do this and some do not. Some, such as Triton, do but not at
-  the appropriate point during the write cycle. Cacheability
-  detection is not normally useful unless you have memory mapped
-  devices which exist outside the 640k-1M range but within your
-  actual memory. (There is another option that disables write
-  allocate for the 15M-16M range commonly used by older VLB
-  video cards). You probably do not want to enable this.
-
-No write allocate between 15MB-16MB
-CONFIG_AMD_K6_WTALLOC_WAE15M
-  There were a small number of cards, mainly VESA Local Bus
-  video cards, that were memory mapped to the 15M-16M address
-  range. If you have such a card you do not want write allocate
-  to delay or reorder writes to this space so you must enable
-  this option. Other memory mapped cards are either outside the
-  systems memory space or are in the 640k-1M range which is
-  not subject to write allocate so this option is not normally
-  required.
 
 # m68k-specific kernel options
 # Documented by Chris Lawrence <quango@themall.net> et al.
diff --git a/Documentation/cyrix.txt b/Documentation/cyrix.txt
deleted file mode 100644 (file)
index 203bc8b..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-                        Cyrix Processor Support
-                        -----------------------
-
-Processor Recognition
----------------------
-
-Cyrix processors prior to the 6x86MX power up in a default mode
-designed to avoid compatibility problems with software that
-makes assumptions about processor capabilities based solely on
-the apparent family of processor. Unless special handling is
-provided Cyrix chips will be identified as some unknown model
-of 486.
-
-  The Cyrix processor recognition kernel build option compiles
-in code that enables the CPUID instruction on Cyrix processors
-and that uses the Cyrix specific DEVID feature to identify the
-particular type of Cyrix chip present.
-
-  The 6x86MX and later processors have CPUID enabled by default
-however special handling is still required to read the specific
-processor type using DEVID since the CPUID information gives
-family 6, model 0 - i.e. an A step PPro.
-
-  The combination of CPUID and DEVID allows all current Cyrix
-processors to be recognised and listed correctly in /proc/cpuinfo.
-This includes Cx486, 5x86, 6x86, Gx86 (aka MediaGx) and 6x86MX.
-
-  Processor recognition is required for all other Cyrix specific
-options.
-
-
-Suspend on Halt Power Saving
-----------------------------
-
-The suspend on halt power saving feature allows the processor to
-enter a low power mode when the "hlt" instruction is executed. This
-results in dramatically reduced operating temperatures if you do
-not spend long periods of time running processor intensive tasks.
-Cyrix processors allow this feature to be enabled an disabled
-through their configuration registers. The default state on reset
-is disabled and many (most?) BIOSs leave it disabled hence a
-kernel configuration option is provided that adds code to explicitly
-enabled suspend on halt when Linux boots.
-
-  However there appear to be a few rare cases in which the
-combination of suspend on halt and some bus master DMA cards can
-cause the system to lock up. If this appears to happen you may
-need to leave suspend on halt in its default state. (Note that
-an option to _disable_ suspend on halt is not provided. If your
-BIOS enables it you have to live with it)
-
-
-5x86 Performance Features
--------------------------
-
-The 5x86 contains a performance control register that allows
-several performance enhancing features to be turned on. Unfortunately
-many of these features do not appear to work correctly. The 5x86
-performance features kernel build option will attempt to set
-the performance control register appropriately but it is
-impossible to guarantee that even these conservative settings
-will work on all chips.
-
-  WARNING: If this is enabled you may find that the only way to
-reboot is to power cycle the machine. Even a hard reboot seems
-to fail on some systems.
-
-
-6x86 Performance Features
--------------------------
-
-Like the 5x86 the 6x86 has several Cyrix specific performance
-features. Normally a 6x86 aware BIOS will set these to reasonable,
-if not fully optimal, settings. The 6x86 performance features
-kernel build option mostly just fine tunes them.
-
-
-6x86 Branch Prediction
-----------------------
-
-The 6x86 uses speculative execution coupled with several levels
-of branch prediction to maximise processing speed. While the
-default power up state is reasonable the branch prediction logic
-is configurable and there may be some benefit in fine tuning it.
-
-  Unfortunately Cyrix offer no documentation on how to configure
-branch prediction and IBM have only partial documentation available.
-Further detail and speculation is available from the 6x86opt package
-by Mikael Johansson <Mikael.Johansson@helsinki.fi>.
-
-  The initial power up state of the 6x86 configures the branch
-prediction logic to handle short branches. The 6x86 branch target
-buffer features kernel build option enables code that enables
-handling of long branches as well. It is not clear if this will
-benefit in your particular case or not.
-
-
-6x86 Variable Sized Paging Mechanism
-------------------------------------
-
-The variable sized paging mechanism (VSPM) is a feature of the Cyrix
-6x86 family of processors that allows large regions of memory
-to be mapped using a single MMU entry rather than many individual
-page sized entries. This significantly reduces the overhead in
-accessing such regions. It is also ideally suited to use for the
-linear mapping of physical memory to kernel memory used by Linux.
-
-  The Cyrix documenation offers only a brief paragraph of explanation.
-Unfortunately the observed behaviour of VSPM suggests that even
-this little information is not entirely correct. Worse still, no one
-at Cyrix is able to answer questions concerning VSPM. Given that
-every revision of 6x86 has *different* VSPM bugs this is not entirely
-surprising! Work arounds are in place for the known bugs in step 1,
-revisions 4, 5 and 6 chips. Revision 7 is also believed to work.
-
-  WARNING: There appears to be no way to disable a VSPM entry once
-it has been created short of a hard reset (which may mean a power
-cycle). Failure to clear the VSPM entries means that programs that
-use virtual memory layouts different from Linux will crash unexpectedly
-after Linux has been running. This includes Windows NT/95, programs
-that use DOS extenders etc.
-
-  By experiment:
-
-  * VSPM pages must be power of two sizes. A single 24MB page fails.
-    This is not entirely surprising but the documentation could give
-    the impression that VSPM supports arbitrary sizes.
-
-  * Documentation suggests there are 8 VSPM slots (3 bit index) but
-    tests show the upper four slots mirror the lower four.
-
-  * VSPM entries appear to override traditional page table entries
-    so we must not overlap the start of the vmalloc region.
-
-  The following only apply to 1 rev 6 and lower chips. 1 rev 7 and
-  above do not appear to have these problems.
-
-  * With a 16MB page followed by an 8MB page I always get a write
-    fault on the last 4k of the 8MB page. With 8MB plus 4MB I can't
-    even boot.
-      If we have such a memory size we map the first power of two
-    with a VSPM entry and use traditional paging for the rest.
-
-  * Do not try and create a mapping with dirty and accessed flags
-    clear - a step 1 rev 5 chip will crash.
-
-  * The valid bit in a VSPM entry is non-functional. There is no way
-    to invalidate a VSPM entry once it has been written.
-
-  * Attempting to replace a VSPM entry with one that maps a zero
-    sized region from 0 to 0 crashes the CPU.
-
-
-What more could be done
------------------------
-
-  Disabling write allocate while we do page copies/clears will
-avoid unnecessary cache trashing. However it will also reduce
-the apparent memory bandwidth for the operation so it runs
-slower (with write allocate the write to memory becomes delayed
-and happens asynchronously). Rumour has it that disabling
-write allocate for such operations is generally good on an
-Intel chip. Disabling and re-enabling write allocate on a
-Cyrix would take and extra 60-65 clock cycles each.
-
-  The 6x86 allows Address regions to be set up and en/disabling 
-certain features for these regions. In order to optimize, we could 
-analyse the setup done (or not done) by the BIOS and optimize it.
-However, it is worth noting that the BIOS probably has more
-hardware specific details coded in it than we could ever determine
-by any form of probing so if it sets something up in a particular
-way the motherboard designers may have had very good reasons for
-doing it. Trying to play fast and loose may not be such a good
-idea for the general case.
-
-  * Setting up regions fo the main memory: RCE, WWO, WL(?), WG
-
-  * Setting up VGA text (0x000a0000) and graphics memory (PCI:
-    e.g. 0xe0000000) to RCD, WG
-
-  * Setting up BIOS regions to RCD or RCE, WT
-
-  * Not touching SMM space (ARR3)
-
-  * Disabling WG for Memory Mapped IO
-
-(RCE/D = Region cache enable/disable, WWO = Weak Write Ordering,
-WL = Weak Locking, WG = Write Gathering, WT = Write Through.)
-
-
-Where to get information
-------------------------
-
-  There is a databook in PDF format (6X-DBOOK.PDF), which can be down-
-loaded from Cyrix' WWW server, which contains a description of the 
-Configuration Registers CCR0 - CCR5, the Device Identification Registers 
-DIR0 + DIR1 and the Address Region ARRx and Region Control
-RCRx registers and an incomplete description of the VSPM mechanism.
-More about CPU detection, VSPM and more undocumented features can be
-found on the Pentium Compiler Group homepage (http://www.goof.com/pcg)
-and by following the links found in the docs.
index 829fd2d206c488446131b60f7be193ba0edaeef4..7b242cc8447e43cd72d898752a3a11460e031ab3 100644 (file)
   (version 1.0) as well as improvements we envisage.
   ______________________________________________________________________
 
-  Table of Contents:
+  Table of Contents
 
-  1.      Introduction
 
-  2.      Servicing Coda filesystem calls
 
-  3.      The message layer
 
-  3.1.    Implementation details
 
-  4.      The interface at the call level
 
-  4.1.    Data structures shared by the kernel and Venus
 
-  4.2.    The pioctl interface
 
-  4.3.    root
 
-  4.4.    lookup
 
-  4.5.    getattr
 
-  4.6.    setattr
 
-  4.7.    access
 
-  4.8.    create
 
-  4.9.    mkdir
 
-  4.10.   link
 
-  4.11.   synlink
 
-  4.12.   remove
 
-  4.13.   rmdir
 
-  4.14.   readlink
 
-  4.15.   open
 
-  4.16.   close
 
-  4.17.   ioctl
 
-  4.18.   rename
 
-  4.19.   readdir
 
-  4.20.   vget
 
-  4.21.   fsync
 
-  4.22.   inactive
 
-  4.23.   rdwr
 
-  4.24.   odymount
 
-  4.25.   ody_lookup
 
-  4.26.   ody_expand
 
-  4.27.   prefetch
 
-  4.28.   signal
 
-  5.      The minicache and downcalls
 
-  5.1.    INVALIDATE
 
-  5.2.    FLUSH
 
-  5.3.    PURGEUSER
 
-  5.4.    ZAPFILE
 
-  5.5.    ZAPDIR
 
-  5.6.    ZAPVNODE
 
-  5.7.    PURGEFID
 
-  5.8.    REPLACE
 
-  6.      Initialization and cleanup
 
-  6.1.    Requirements
+
+
+
+
+
+
+
+
+
+
+
+  1. Introduction
+
+  2. Servicing Coda filesystem calls
+
+  3. The message layer
+
+     3.1 Implementation details
+
+  4. The interface at the call level
+
+     4.1 Data structures shared by the kernel and Venus
+     4.2 The pioctl interface
+     4.3 root
+     4.4 lookup
+     4.5 getattr
+     4.6 setattr
+     4.7 access
+     4.8 create
+     4.9 mkdir
+     4.10 link
+     4.11 symlink
+     4.12 remove
+     4.13 rmdir
+     4.14 readlink
+     4.15 open
+     4.16 close
+     4.17 ioctl
+     4.18 rename
+     4.19 readdir
+     4.20 vget
+     4.21 fsync
+     4.22 inactive
+     4.23 rdwr
+     4.24 odymount
+     4.25 ody_lookup
+     4.26 ody_expand
+     4.27 prefetch
+     4.28 signal
+
+  5. The minicache and downcalls
+
+     5.1 INVALIDATE
+     5.2 FLUSH
+     5.3 PURGEUSER
+     5.4 ZAPFILE
+     5.5 ZAPDIR
+     5.6 ZAPVNODE
+     5.7 PURGEFID
+     5.8 REPLACE
+
+  6. Initialization and cleanup
+
+     6.1 Requirements
+
+
   ______________________________________________________________________
   0wpage
 
   1\b1.\b.  I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
 
+
+
   A key component in the Coda Distributed File System is the cache
   manager, _\bV_\be_\bn_\bu_\bs.
 
+
   When processes on a Coda enabled system access files in the Coda
   filesystem, requests are directed at the filesystem layer in the
   operating system. The operating system will communicate with Venus to
   the Coda FS layer, so the Coda FS driver must expose the VFS interface
   as applicable in the operating system. These differ very significantly
   among operating systems, but share features such as facilities to
-  read/write and create and remove object.  The Coda FS layer services
+  read/write and create and remove objects.  The Coda FS layer services
   such VFS requests in by invoking on or more well defined services
   offered by the cache manager Venus.  When the replies from Venus have
   come back to the FS driver, servicing of the VFS call continues and
   returns to the process.
 
   As a result of this design a basic interface exposed by the FS driver
-  must allow Venus to handle manage message traffic.  In particular
-  Venus must be able to retrieve and place messages and to be notified
-  of the arrival of a new message. The notification must be through a
-  mechanism which does not block Venus since Venus must attend to other
-  tasks even when no messages are waiting or being processed.
+  must allow Venus to manage message traffic.  In particular Venus must
+  be able to retrieve and place messages and to be notified of the
+  arrival of a new message. The notification must be through a mechanism
+  which does not block Venus since Venus must attend to other tasks even
+  when no messages are waiting or being processed.
+
+
+
+
 
-                       Interfaces of Coda FS Driver
+
+                     Interfaces of the Coda FS Driver
 
   Furthermore the FS layer provides for a special path of communication
   between a user process and Venus, called the pioctl interface. The
 
   3\b3.\b.  T\bTh\bhe\be m\bme\bes\bss\bsa\bag\bge\be l\bla\bay\bye\ber\br
 
+
+
   At the lowest level the communication between Venus and the FS driver
-  proceeds through messages.  The synchronization of between processes
+  proceeds through messages.  The synchronization between processes
   requesting Coda file service and Venus relies on blocking and waking
   up processes.  The Coda FS driver processes VFS- and pioctl-requests
   on behalf of a process P, creates messages for Venus, awaits replies
   namely when Venus calls sendmsg_to_kernel.  At this moment the Coda FS
   driver looks at the contents of the message and decides if:
 
+
   +\bo  the message is a reply for a suspended thread P.  If so it removes
      the message from the processing queue and marks the message as
      WRITTEN.  Finally, the FS driver unblocks P (still in the kernel
 
   +\bo  The message is a _\bd_\bo_\bw_\bn_\bc_\ba_\bl_\bl.  A downcall is a request from Venus to
      the FS Driver. The FS driver processes the request immediately
-     (usually a cach eviction or replacement) and when finishes
+     (usually a cache eviction or replacement) and when finishes
      sendmsg_to_kernel returns.
 
   Now P awakes and continues processing upcall.  There are some
   deallocate message structure and return.  The FS routine can proceed
   with its processing.
 
+
+
+
+
+
+
                       Sleeping and IPC arrangements
 
   In case P is woken up by a signal and not by Venus, it will first look
   extra field "handle_signals" could be added in the message structure
   to indicate points of no return have been passed.--)
 
+
+
   3\b3.\b.1\b1.\b.  I\bIm\bmp\bpl\ble\bem\bme\ben\bnt\bta\bat\bti\bio\bon\bn d\bde\bet\bta\bai\bil\bls\bs
 
   The Unix implementation of this mechanism has been through the
 
   4\b4.\b.  T\bTh\bhe\be i\bin\bnt\bte\ber\brf\bfa\bac\bce\be a\bat\bt t\bth\bhe\be c\bca\bal\bll\bl l\ble\bev\bve\bel\bl
 
+
   This section describes the upcalls a Coda FS driver can make to Venus.
   Each of these upcalls make use of two structures: inputArgs and
   outputArgs.   In pseudo BNF form the structures take the following
   form:
 
+
   struct inputArgs {
       u_long opcode;
       u_long unique;     /* Keep multiple outstanding msgs distinct */
       <union "out" of call dependent parts of inputArgs>
   };
 
+
+
   Before going on let us elucidate the role of the various fields. The
   inputArgs start with the opcode which defines the type of service
   requested from Venus. There are approximately 30 upcalls at present
   Before delving into the specific calls we need to discuss a variety of
   data structures shared by the kernel and Venus.
 
+
+
+
   4\b4.\b.1\b1.\b.  D\bDa\bat\bta\ba s\bst\btr\bru\buc\bct\btu\bur\bre\bes\bs s\bsh\bha\bar\bre\bed\bd b\bby\by t\bth\bhe\be k\bke\ber\brn\bne\bel\bl a\ban\bnd\bd V\bVe\ben\bnu\bus\bs
 
+
   The CodaCred structure defines a variety of user and group id's as
   they are set for the calling process. The vuid_t and guid_t are 32 bit
   unsigned integers.  It also defines group member ship in an array.  On
       vgid_t cr_groups[NGROUPS];        /* Group membership for caller */
   };
 
+
+
   N\bNO\bOT\bTE\bE It is questionable if we need CodaCreds in Venus. Finally Venus
   doesn't know about groups, although it does create files with the
   default uid/gid.  Perhaps the list of group membership is superfluous.
 
+
   The next item is the fundamental identifier used to identify Coda
   files, the ViceFid.  A fid of a file uniquely defines a file or
   directory in the Coda filesystem within a _\bc_\be_\bl_\bl.   (-- A _\bc_\be_\bl_\bl is a
   control machine or SCM. See the Coda Administration manual for a
   detailed description of the role of the SCM.--)
 
+
   typedef struct ViceFid {
       VolumeId Volume;
       VnodeId Vnode;
       Unique_t Unique;
   } ViceFid;
 
+
+
   Each of the constituent fields: VolumeId, VnodeId and Unique_t are
   unsigned 32 bit integers.  We envisage that a further field will need
   to be prefixed to identify the Coda cell; this will probably take the
   exchange information.  It has room for future extensions such as
   support for device files (currently not present in Coda).
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
   struct coda_vattr {
           enum coda_vtype va_type;        /* vnode type (for create) */
           u_short         va_mode;        /* files access mode and type */
           long            va_spare;       /* remain quad aligned */
   };
 
+
+
+
   4\b4.\b.2\b2.\b.  T\bTh\bhe\be p\bpi\bio\boc\bct\btl\bl i\bin\bnt\bte\ber\brf\bfa\bac\bce\be
 
-  Coda specific requests can be made by application through a pioctl
+
+  Coda specific requests can be made by application through the pioctl
   interface. The pioctl is implemented as an ordinary ioctl on a
   ficticious file /coda/.CONTROL.  The piocl call opens this file, gets
   a file handle and makes the ioctl call. Finally it closes the file.
           int follow;
       } data;
 
+
+
   where
 
+
   struct ViceIoctl {
           caddr_t in, out;        /* Data to be transferred in, or out */
           short in_size;          /* Size of input buffer <= 2K */
           short out_size;         /* Maximum size of output buffer, <= 2K */
   };
 
+
+
   The path must be a Coda file, otherwise the ioctl upcall will not be
   made.
 
 
   4\b4.\b.3\b3.\b.  r\bro\boo\bot\bt
 
+
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
      i\bin\bn empty
                     ViceFid VFid;
                 } cfs_root;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn This call is made to Venus during the initialization of
   the Coda filesystem. If the result is zero, the cfs_root structure
   contains the ViceFid of the root of the Coda filesystem. If a non-zero
 
   4\b4.\b.4\b4.\b.  l\blo\boo\bok\bku\bup\bp
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Find the ViceFid and type of an object in a directory if it
   exists.
 
                     char        *name;          /* Place holder for data. */
                 } cfs_lookup;
 
+
+
      o\bou\but\bt
 
                 struct cfs_lookup_out {
                     int vtype;
                 } cfs_lookup;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn This call is made to determine the ViceFid and filetype of
   a directory entry.  The directory entry requested carries name name
   and Venus will search the directory identified by cfs_lookup_in.VFid.
 
   4\b4.\b.5\b5.\b.  g\bge\bet\bta\bat\btt\btr\br
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Get the attributes of a file.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     struct coda_vattr attr; /* XXXXX */
                 } cfs_getattr;
 
+
+
      o\bou\but\bt
 
                 struct cfs_getattr_out {
                     struct coda_vattr attr;
                 } cfs_getattr;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn This call returns the attributes of the file identified by
   fid.
 
 
   4\b4.\b.6\b6.\b.  s\bse\bet\bta\bat\btt\btr\br
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Set the attributes of a file.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     struct coda_vattr attr;
                 } cfs_setattr;
 
+
+
+
      o\bou\but\bt
         empty
 
 
   4\b4.\b.7\b7.\b.  a\bac\bcc\bce\bes\bss\bs
 
+
   S\bSu\bum\bmm\bma\bar\bry\by
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     int flags;
                 } cfs_access;
 
+
+
      o\bou\but\bt
         empty
 
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Verify if access to the object identified by VFid for
-  operetions described by flags is permitted.  The result indicates if
+  operations described by flags is permitted.  The result indicates if
   access will be granted.  It is important to remember that Coda uses
   ACL's to enforce protection and that ultimately the servers, not the
   clients enforce the security of the system.  The result of this call
 
   4\b4.\b.8\b8.\b.  c\bcr\bre\bea\bat\bte\be
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Invoked to create a file
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     char        *name;          /* Place holder for data. */
                 } cfs_create;
 
+
+
+
      o\bou\but\bt
 
                 struct cfs_create_out {
                     struct coda_vattr attr;
                 } cfs_create;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn  This upcall is invoked to request creation of a file.
   The file will be created in the directory identified by VFid, its name
   will be name, and the mode will be mode.  If excl is set an error will
   instantiate a vnode, inode or filehandle at kernel level for the new
   object.
 
+
   E\bEr\brr\bro\bor\brs\bs A variety of errors can occur. Permissions may be insufficient.
   If the object exists and is not a file the error EISDIR is returned
   under Unix.
 
   4\b4.\b.9\b9.\b.  m\bmk\bkd\bdi\bir\br
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Create a new directory.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     char        *name;          /* Place holder for data. */
                 } cfs_mkdir;
 
+
+
      o\bou\but\bt
 
                 struct cfs_mkdir_out {
                     struct coda_vattr attr;
                 } cfs_mkdir;
 
+
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn This call is similar to create but creates a directory.
   Only the mode field in the input parameters is used for creation.
   Upon successful creation, the attr returned contains the attributes of
 
   4\b4.\b.1\b10\b0.\b.  l\bli\bin\bnk\bk
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Create a link to an existing file.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     char        *tname;         /* Place holder for data. */
                 } cfs_link;
 
+
+
      o\bou\but\bt
         empty
 
 
   E\bEr\brr\bro\bor\brs\bs The usual errors can occur.0wpage
 
-  4\b4.\b.1\b11\b1.\b.  s\bsy\byn\bnl\bli\bin\bnk\bk
+  4\b4.\b.1\b11\b1.\b.  s\bsy\bym\bml\bli\bin\bnk\bk
+
 
   S\bSu\bum\bmm\bma\bar\bry\by create a symbolic link
 
                     char        *tname;
                 } cfs_symlink;
 
+
+
      o\bou\but\bt
         none
 
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Create a symbolic link. The link is to be placed in the
   directory identified by VFid and named tname.  It should point to the
-  pathname srcname.  The attributes of the newly creaeted object are to
+  pathname srcname.  The attributes of the newly created object are to
   be set to attr.
 
   E\bEr\brr\bro\bor\brs\bs
 
   4\b4.\b.1\b12\b2.\b.  r\bre\bem\bmo\bov\bve\be
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Remove a file
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     char        *name;          /* Place holder for data. */
                 } cfs_remove;
 
+
+
      o\bou\but\bt
         none
 
 
   4\b4.\b.1\b13\b3.\b.  r\brm\bmd\bdi\bir\br
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Remove a directory
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     char        *name;          /* Place holder for data. */
                 } cfs_rmdir;
 
+
+
      o\bou\but\bt
         none
 
 
   4\b4.\b.1\b14\b4.\b.  r\bre\bea\bad\bdl\bli\bin\bnk\bk
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Read the value of a symbolic link.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     ViceFid VFid;
                 } cfs_readlink;
 
+
+
      o\bou\but\bt
 
                 struct cfs_readlink_out {
                     caddr_t     data;           /* Place holder for data. */
                 } cfs_readlink;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn This routine reads the contents of symbolic link
   identified by VFid into the buffer data.  The buffer data must be able
   to hold any name up to CFS_MAXNAMLEN (PATH or NAM??).
 
   4\b4.\b.1\b15\b5.\b.  o\bop\bpe\ben\bn
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Open a file.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     int flags;
                 } cfs_open;
 
+
+
      o\bou\but\bt
 
                 struct cfs_open_out {
                     ino_t       inode;
                 } cfs_open;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn  This request asks Venus to place the file identified by
   VFid in its cache and to note that the calling process wishes to open
   it with flags as in open(2).  The return value to the kernel differs
   informed of the device and inode number of the container file in the
   fields dev and inode.  For Windows the path of the container file is
   returned to the kernel.
-
   E\bEr\brr\bro\bor\brs\bs
 
   N\bNO\bOT\bTE\bE Currently the cfs_open_out structure is not properly adapted to
 
   4\b4.\b.1\b16\b6.\b.  c\bcl\blo\bos\bse\be
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Close a file, update it on the servers.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     int flags;
                 } cfs_close;
 
+
+
      o\bou\but\bt
         none
 
 
   4\b4.\b.1\b17\b7.\b.  i\bio\boc\bct\btl\bl
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Do an ioctl on a file. This includes the piocl interface.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     char *data;                 /* Place holder for data. */
                 } cfs_ioctl;
 
+
+
      o\bou\but\bt
 
+
                 struct cfs_ioctl_out {
                     int len;
                     caddr_t     data;           /* Place holder for data. */
                 } cfs_ioctl;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Do an ioctl operation on a file.  The command, len and
   data arguments are filled as usual.  flags is not used by Venus.
 
   N\bNO\bOT\bTE\bE Another bogus parameter.  flags is not used.  What is the
   business about PREFETCHING in the Venus' code?
 
+
   0wpage
 
   4\b4.\b.1\b18\b8.\b.  r\bre\ben\bna\bam\bme\be
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Rename a fid.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     char        *destname;
                 } cfs_rename;
 
+
+
      o\bou\but\bt
         none
 
 
   4\b4.\b.1\b19\b9.\b.  r\bre\bea\bad\bdd\bdi\bir\br
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Read directory entries.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     int offset;
                 } cfs_readdir;
 
+
+
+
      o\bou\but\bt
 
                 struct cfs_readdir_out {
                     caddr_t     data;           /* Place holder for data. */
                 } cfs_readdir;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Read directory entries from VFid starting at offset and
   read at most count bytes.  Returns the data into data and indicates
   the size returned size.
 
   4\b4.\b.2\b20\b0.\b.  v\bvg\bge\bet\bt
 
+
   S\bSu\bum\bmm\bma\bar\bry\by instructs Venus to do an FSDB->Get.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
      i\bin\bn
 
-                struct cfs_fsync_in {
+                struct cfs_vget_in {
                     ViceFid VFid;
-                } cfs_fsync;
+                } cfs_vget;
+
+
 
      o\bou\but\bt
 
                     int vtype;
                 } cfs_vget;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn This upcall asks Venus to do a get operation on an fsobj
   labelled by VFid.
 
 
   4\b4.\b.2\b21\b1.\b.  f\bfs\bsy\byn\bnc\bc
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Tell Venus to update the RVM attributes of a file.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     ViceFid VFid;
                 } cfs_fsync;
 
+
+
      o\bou\but\bt
         none
 
 
   4\b4.\b.2\b22\b2.\b.  i\bin\bna\bac\bct\bti\biv\bve\be
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Tell Venus a vnode is no longer in use.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     ViceFid VFid;
                 } cfs_inactive;
 
+
+
      o\bou\but\bt
         none
 
 
   4\b4.\b.2\b23\b3.\b.  r\brd\bdw\bwr\br
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Read or write from a file
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
                     caddr_t     data;           /* Place holder for data. */
                 } cfs_rdwr;
 
+
+
+
      o\bou\but\bt
 
                 struct cfs_rdwr_out {
                     caddr_t     data;   /* Place holder for data. */
                 } cfs_rdwr;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn This upcall asks Venus to read or write from a file.
 
   E\bEr\brr\bro\bor\brs\bs
   read/write operations never reach Venus.  I have been told the
   operation does not work.  It is not currently used.
 
+
   0wpage
 
   4\b4.\b.2\b24\b4.\b.  o\bod\bdy\bym\bmo\bou\bun\bnt\bt
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Allows mounting multiple Coda "filesystems" on one Unix mount
   point.
 
                     char        *name;          /* Place holder for data. */
                 } ody_mount;
 
+
+
      o\bou\but\bt
 
                 struct ody_mount_out {
                     ViceFid VFid;
                 } ody_mount;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn  Asks Venus to return the rootfid of a Coda system named
   name.  The fid is returned in VFid.
 
 
   4\b4.\b.2\b25\b5.\b.  o\bod\bdy\by_\b_l\blo\boo\bok\bku\bup\bp
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Looks up something.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
      i\bin\bn irrelevant
 
+
      o\bou\but\bt
         irrelevant
 
 
   4\b4.\b.2\b26\b6.\b.  o\bod\bdy\by_\b_e\bex\bxp\bpa\ban\bnd\bd
 
+
   S\bSu\bum\bmm\bma\bar\bry\by expands something in a dynamic set.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
   4\b4.\b.2\b27\b7.\b.  p\bpr\bre\bef\bfe\bet\btc\bch\bh
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Prefetch a dynamic set.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
   N\bNO\bOT\bTE\bE Gut it. It isn't working and isn't used by Coda.
 
+
   0wpage
 
   4\b4.\b.2\b28\b8.\b.  s\bsi\big\bgn\bna\bal\bl
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Send Venus a signal about an upcall.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
   5\b5.\b.  T\bTh\bhe\be m\bmi\bin\bni\bic\bca\bac\bch\bhe\be a\ban\bnd\bd d\bdo\bow\bwn\bnc\bca\bal\bll\bls\bs
 
+
   The Coda FS Driver can cache results of lookup and access upcalls, to
   limit the frequency of upcalls.  Upcalls carry a price since a process
   context switch needs to take place.  The counterpart of caching the
 
   The kernel code generally has to maintain a structure which links the
   internal file handles (called vnodes in BSD, inodes in Linux and
-  FileHandles in Windows) with the ViceFid's which Venus maintains.
-  Ther reason is that frequent translations back and forth are needed in
+  FileHandles in Windows) with the ViceFid's which Venus maintains.  The
+  reason is that frequent translations back and forth are needed in
   order to make upcalls and use the results of upcalls.  Such linking
   objects are called c\bcn\bno\bod\bde\bes\bs.
 
   The lookup call in the Coda FS Driver may request the cnode of the
   desired object from the cache, by passing it's name, directory and the
   CodaCred's of the caller.  The cache will return the cnode or indicate
-  and it cannot be found.  The Coda FS Driver must be careful to
+  that it cannot be found.  The Coda FS Driver must be careful to
   invalidate cache entries when it modifies or removes objects.
 
   When Venus obtains information that indicates that cache entries are
   the kind described below.  The Coda FS Driver does not return an error
   unless the downcall data could not be read into kernel memory.
 
+
   5\b5.\b.1\b1.\b.  I\bIN\bNV\bVA\bAL\bLI\bID\bDA\bAT\bTE\bE
 
+
   No information is available on this call.
 
+
   5\b5.\b.2\b2.\b.  F\bFL\bLU\bUS\bSH\bH
 
+
+
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs None
 
   S\bSu\bum\bmm\bma\bar\bry\by Flush the name cache entirely.
   systems allow the kernel name cache to be switched off dynamically.
   When this is done, this downcall is made.
 
+
   5\b5.\b.3\b3.\b.  P\bPU\bUR\bRG\bGE\bEU\bUS\bSE\bER\bR
 
+
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
           struct cfs_purgeuser_out {/* CFS_PURGEUSER is a venus->kernel call */
               struct CodaCred cred;
           } cfs_purgeuser;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Remove all entries in the cache carrying the Cred.  This
   call is issued when tokes for a user expire or are flushed.
 
+
   5\b5.\b.4\b4.\b.  Z\bZA\bAP\bPF\bFI\bIL\bLE\bE
 
+
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
           struct cfs_zapfile_out {  /* CFS_ZAPFILE is a venus->kernel call */
               ViceFid CodaFid;
           } cfs_zapfile;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Remove all entries which have the (dir vnode, name) pair.
   This is issued as a result of an invalidation of cached attributes of
   a vnode.
   zapfile routine takes different arguments. Linux does not implement
   the invalidation of attributes correctly.
 
+
+
   5\b5.\b.5\b5.\b.  Z\bZA\bAP\bPD\bDI\bIR\bR
 
+
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
           struct cfs_zapdir_out {   /* CFS_ZAPDIR is a venus->kernel call */
               ViceFid CodaFid;
           } cfs_zapdir;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Remove all entries in the cache lying in a directory
   CodaFid, and all children of this directory. This call is issed when
-  Venus receives a callback on the this directory.
+  Venus receives a callback on the directory.
+
 
   5\b5.\b.6\b6.\b.  Z\bZA\bAP\bPV\bVN\bNO\bOD\bDE\bE
 
+
+
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
 
           struct cfs_zapvnode_out { /* CFS_ZAPVNODE is a venus->kernel call */
               ViceFid VFid;
           } cfs_zapvnode;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Remove all entries in the cache carrying the cred and VFid
   as in the arguments. This downcall is probably never issued.
 
+
   5\b5.\b.7\b7.\b.  P\bPU\bUR\bRG\bGE\bEF\bFI\bID\bD
 
+
   S\bSu\bum\bmm\bma\bar\bry\by
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
               ViceFid CodaFid;
           } cfs_purgefid;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Flush the attribute for the file. If it is a dir (odd
   vnode), purge its children from the namecache remove the file from the
   namecache.
 
+
+
   5\b5.\b.8\b8.\b.  R\bRE\bEP\bPL\bLA\bAC\bCE\bE
 
+
   S\bSu\bum\bmm\bma\bar\bry\by Replace the Fid's for a collection of names.
 
   A\bAr\brg\bgu\bum\bme\ben\bnt\bts\bs
               ViceFid OldFid;
           } cfs_replace;
 
+
+
   D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn This routine replaces a ViceFid in the name cache with
   another.  It is added to allow Venus during reintegration to replace
   locally allocated temp fids while disconnected with global fids even
 
   6\b6.\b.  I\bIn\bni\bit\bti\bia\bal\bli\biz\bza\bat\bti\bio\bon\bn a\ban\bnd\bd c\bcl\ble\bea\ban\bnu\bup\bp
 
+
   This section gives brief hints as to desirable features for the Coda
   FS Driver at startup and upon shutdown or Venus failures.  Before
   entering the discussion it is useful to repeat that the Coda FS Driver
   maintains the following data:
 
+
   1. message queues
 
   2. cnodes
      Currently the _\bp_\bi_\bo_\bc_\bt_\bl passes through the VFS for Coda so we can
      treat these similarly.
 
+
   6\b6.\b.1\b1.\b.  R\bRe\beq\bqu\bui\bir\bre\bem\bme\ben\bnt\bts\bs
 
+
   The following requirements should be accomodated:
 
   1. The message queueus should have open and close routines.  On Unix
 
   +\bo  Close will free all memory allocated by the message queues.
 
+
   2. At open the namecache shall be initialized to empty state.
 
   3. Before the message queues are open, all VFS operations will fail.
   above requirements fully.  For smooth operation this needs to be
   corrected.
 
+
+
index 050a4306a6734dda4b400a0e226fb0ca56c98ea1..61f44a87c74cab723e39fba6e33642e61b403ced 100644 (file)
@@ -43,6 +43,10 @@ nonumtail=<bool> -- When creating 8.3 aliases, normally the alias will
                  be the short alias instead of 'longfi~1.txt'. 
                   
 quiet         -- Stops printing certain warning messages.
+check=s|r|n   -- Case sensitivity checking setting.
+                 s: strict, case sensitive
+                 r: relaxed, case insensitive
+                 n: normal, default setting, currently case insensitive
 
 <bool>: 0,1,yes,no,true,false
 
diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt
new file mode 100644 (file)
index 0000000..9e2d731
--- /dev/null
@@ -0,0 +1,42 @@
+filter.txt: Linux Socket Filtering
+Written by: Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
+
+Introduction
+============
+
+       Linux Socket Filtering is a deviation of the Berkely
+Packet Filter. There are some distinct differences between
+the BSD and Linux Kernel Filtering.
+
+Linux Socket Filtering (LSF) allows a user-space program to
+attach a filter onto any socket and allow or disallow certain
+types of data to come through the socket. LSF follows exactly
+the same filter code structure as the BSD Berkely Packet Filter
+(BPF), so refering to the BSD bpf.4 manpage is very helpful in
+creating filters.
+
+LSF is much simpler that BPF. One does not have to worry about
+devices or anything like that. You simply create your filter
+code, send it to the kernel via the SO_ATTACH_FILTER ioctl and
+if you filter code passes the kernel check on it, you then
+immediately begin filtering data on that socket.
+
+You can also detach filters from your socket via the
+SO_DETACH_FILTER ioctl. This will probably not be used much
+since when you close a socket that has a filter on it the
+filter is automagicly removed. The other less common case
+may be adding a differnt filter on the same socket you had another
+filter that is still running, the kernel takes care of removing
+the old one and placing your new one in its place, assumming your
+filter has passed the checks, otherwise if it fails the old filter
+will remain on that socket.
+
+Examples
+========
+
+Ioctls-
+setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter));
+setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &value, sizeof(value));
+
+See the BSD bpf.4 manpage and the BSD Packet Filter paper written by
+Steven McCanne and Van Jacobson of Lawrence Berkely Laboratory.
diff --git a/Documentation/networking/ipddp.txt b/Documentation/networking/ipddp.txt
new file mode 100644 (file)
index 0000000..6ed2d93
--- /dev/null
@@ -0,0 +1,78 @@
+Text file for ipddp.c:
+       Appletalk-IP Decapsulation and Appletalk-IP Encapsulation
+
+This text file writen by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
+
+Introduction
+------------
+
+Appletalk-IP (IPDDP) is the method computers connected to Appletalk
+networks can communicate via IP. Appletalk-IP is simply IP datagrams
+inside Appletalk packets.
+
+Through this driver you can either allow your Linux box to communicate
+IP over an Appletalk network or you can provide IP gatewaying functions
+for you Appletalk users.
+
+You can currently Encapsulate or Decapsulate Appletalk-IP on LocalTalk,
+EtherTalk and PPPTalk. The only limit on the protocol is that of what
+the kernel Appletalk layer and drivers are available.
+
+Each mode requires its own user space software.
+
+Compiling Appletalk-IP Decapsulation/Encapsulation
+=================================================
+
+Appletalk-IP Decapsulation needs to be compiled into your kernel. You
+will need to turn on Appletalk-IP driver support. Then you will need to
+select ONE of the two options; IP to Appletalk-IP Encapsulation support or
+Appletalk-IP to IP Decapsulation support. If you compile the driver
+staticly you will only be able to use the driver for the function you have
+enabled in the kernel. If you compile the driver as a module you can
+select what mode you want it to run in via a module loading param.
+ipddp_mode=1 for Appletalk-IP Encapsulation and ipddp_mode=2 for
+Appletalk-IP to IP Decapsulation.
+
+Basic instructions for user space tools
+=======================================
+
+To enable Appletalk-IP Decapsulation/Encapsulation you will need the 
+proper tools. You can get the tools for Decapsulation from
+http://spacs1.spacs.k12.wi.us/~jschlst/MacGate and for Encapsulation
+from http://www.maths.unm.edu/~bradford/ltpc.html
+
+I will briefly describe the operation of the tools, but you will
+need to consult the supporting documentation for each set of tools.
+
+Decapsulation - You will need to download a software package called
+MacGate. In this distribution there will be a tool called MacRoute
+which enabled you to add routes to the kernel for your Macs by hand.
+Also the tool MacRegGateWay is included to register the
+proper IP Gateway and IP addresses for your machine. Included in this
+distribution is a patch to netatalk-1.4b2+asun2.0a17.2 (available from
+ftp.u.washington.edu/pub/user-supported/asun/) this patch is optional
+but it allows automatic adding and deleting of routes for Macs. (Handy
+for locations with large Mac installations)
+
+Encapsulation - You will need to download a software daemon called ipddpd.
+This software expects there to be and Appletalk-IP gateway on the network.
+You will also need to add the proper routes to route your Linux box's IP
+traffic out the ipddp interface.
+
+Common Uses of ipddp.c
+----------------------
+Of course Appletalk-IP Decapsulation and Encapsulation, but specificly
+Decapsulation is being used most for connecting LocalTalk networks to
+IP networks. Although it has been used on EtherTalk networks to allow
+Macs that are only able to tunnel IP over EtherTalk.
+
+Encapsulation has been used to allow a Linux box stuck on a LocalTalk
+network to use IP. It should work equally well if you are stuck on an
+EtherTalk only network.
+
+Further Assisatance
+-------------------
+You can contact me (Jay Schulist <Jay.Schulist@spacs.k12.wi.us>) with any
+questions reguarding Decapsulation or Encapsulation. Bradford W. Johnson
+<johns393@maroon.tc.umn.edu> originally wrote the ipddp.c driver for IP
+encapsulation in Appletalk.
index ccc253fa1161356dd673fbfccfa7105fd5dd8c88..605d9a7f69b6ddc280f47f063e1e062d5a9d2bfd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 74
+SUBLEVEL = 75
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
index 84402f1e043f8dae15cc53a3c5e208d14f041a5e..fd4525f33a652bfb7a045393964c31529f436722 100644 (file)
@@ -193,3 +193,7 @@ if [ "$CONFIG_PROFILE" = "y" ]; then
 fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
+
+if [ "$CONFIG_TGA_CONSOLE" = "n" ]; then
+  define_bool CONFIG_VGA_CONSOLE y
+fi
index 72d4224f7ec1df789323af4224bc36c12bf3bea8..e44639fb2e641269ca19abe323d5528413e2f9d0 100644 (file)
@@ -70,6 +70,20 @@ asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr,
        struct mm_struct *mm = current->mm;
        unsigned fixup;
 
+       /* As of EV6, a load into $31/$f31 is a prefetch, and never faults
+          (or is suppressed by the PALcode).  Support that for older cpu's
+          by ignoring such an instruction.  */
+       if (cause == 0) {
+               /* No need for get_user.. we know the insn is there.  */
+               unsigned int insn = *(unsigned int *)regs->pc;
+               if ((insn >> 21 & 0x1f) == 0x1f &&
+                   /* ldq ldl ldt lds ldg ldf ldwu ldbu */
+                   (1ul << (insn >> 26) & 0x30f00001400ul)) {
+                       regs->pc += 4;
+                       return;
+               }
+       }
+
        down(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if (!vma)
index 653c12eba60d8980c1c0e1f9bd561552389fce23..770c563ece8c1806bfcdd2b635954be090e27854 100644 (file)
@@ -57,4 +57,4 @@ piggy.o:      $(SYSTEM)
        rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
 
 clean:
-       rm -f vmlinux bvmlinux
+       rm -f vmlinux bvmlinux _tmp_*
index e4a6ede9a1bc00924e9a8ccc9b19555627aec82c..4d2ece791e27459482aabcf9f9b7caa4cca0031b 100644 (file)
@@ -349,9 +349,9 @@ int decompress_kernel(struct moveparams *mv)
        else setup_output_buffer_if_we_run_high(mv);
 
        makecrc();
-       puts("Uncompressing Linux...");
+       puts("Uncompressing Linux... ");
        gunzip();
-       puts("done.\nNow booting the kernel\n");
+       puts("Ok, booting the kernel.\n");
        if (high_loaded) close_output_buffer_if_we_run_high(mv);
        return high_loaded;
 }
index 7595ab5fef4dd075ddba2ad462fea39d06be382c..48010abb5acc4f3bd63cfab5aad13da5fd4d3a1d 100644 (file)
@@ -9,6 +9,16 @@ comment 'Code maturity level options'
 bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
 endmenu
 
+mainmenu_option next_comment
+comment 'Processor type and features'
+choice 'Processor family' \
+       "386                    CONFIG_M386     \
+        486/Cx486              CONFIG_M486     \
+        Pentium/K5/5x86/6x86   CONFIG_M586     \
+        PPro/K6/6x86MX         CONFIG_M686" Pentium
+bool 'Math emulation' CONFIG_MATH_EMULATION
+endmenu
+
 mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
@@ -21,7 +31,6 @@ endmenu
 mainmenu_option next_comment
 comment 'General setup'
 
-bool 'Kernel math emulation' CONFIG_MATH_EMULATION
 bool 'Networking support' CONFIG_NET
 bool 'PCI support' CONFIG_PCI
 if [ "$CONFIG_PCI" = "y" ]; then
@@ -41,16 +50,11 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 fi
 
-choice 'Processor type' \
-       "386            CONFIG_M386     \
-        486            CONFIG_M486     \
-        Pentium        CONFIG_M586     \
-        PPro           CONFIG_M686" Pentium
 bool 'Video mode selection support' CONFIG_VIDEO_SELECT
 
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
 fi
 
 endmenu
@@ -140,3 +144,5 @@ if [ "$CONFIG_PROFILE" = "y" ]; then
 fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
+
+define_bool CONFIG_VGA_CONSOLE y
index f8793e75f9cff11c406385abee3bf5d7f5f06e25..f5de6e1a44937abcab6ba1f7944834f8ca2914fd 100644 (file)
@@ -7,6 +7,15 @@
 #
 # CONFIG_EXPERIMENTAL is not set
 
+#
+# Processor type and features
+#
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+CONFIG_M586=y
+# CONFIG_M686 is not set
+# CONFIG_MATH_EMULATION is not set
+
 #
 # Loadable module support
 #
@@ -17,21 +26,16 @@ CONFIG_MODULES=y
 #
 # General setup
 #
-# CONFIG_MATH_EMULATION is not set
 CONFIG_NET=y
 CONFIG_PCI=y
 CONFIG_PCI_BIOS=y
-# CONFIG_PCI_DIRECT is not set
+CONFIG_PCI_DIRECT=y
 # CONFIG_MCA is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
-# CONFIG_M386 is not set
-# CONFIG_M486 is not set
-# CONFIG_M586 is not set
-CONFIG_M686=y
 # CONFIG_VIDEO_SELECT is not set
 # CONFIG_PARPORT is not set
 
@@ -79,6 +83,7 @@ CONFIG_PACKET=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 is not set
@@ -123,6 +128,7 @@ CONFIG_BLK_DEV_SD=y
 #
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
 
 #
 # SCSI low-level drivers
@@ -185,8 +191,7 @@ CONFIG_EEXPRESS_PRO100=y
 # CONFIG_DLCI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_STRIP is not set
-# CONFIG_WAVELAN is not set
+# CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
@@ -228,6 +233,7 @@ CONFIG_LOCKD=y
 # CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -283,3 +289,4 @@ CONFIG_82C710_MOUSE=y
 #
 # CONFIG_PROFILE is not set
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_VGA_CONSOLE=y
index 9491ef562f8c9f900383233d926f3c2a81b3a409..17042cd7fb64b7efaf1a0ddd670654b5862a16e0 100644 (file)
@@ -18,10 +18,14 @@ endif
 all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
-O_OBJS   := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
+O_OBJS   := process.o signal.o entry.o traps.o irq.o vm86.o \
             ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o
 OX_OBJS  := i386_ksyms.o
 
+ifdef CONFIG_PCI
+O_OBJS += bios32.o
+endif
+
 ifdef CONFIG_MCA
 O_OBJS += mca.o
 endif
index 27d5a9d8018a5f9c921940ce6e487bac05a57813..0167c667dcfc9727ace625015283a6629c2205f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * bios32.c - BIOS32, PCI BIOS functions.
  *
- * $Id: bios32.c,v 1.14 1997/08/02 22:20:57 mj Exp $
+ * $Id: bios32.c,v 1.17 1997/11/16 11:03:41 mj Exp $
  *
  * Sponsored by
  *     iX Multiuser Multitasking Magazine
@@ -456,7 +456,7 @@ __initfunc(static struct pci_access *pci_check_direct(void))
     outb (0x00, 0xCFB);
     outb (0x00, 0xCF8);
     outb (0x00, 0xCFA);
-    if (inb (0xCF8) == 0x00 && inb (0xCFB) == 0x00) {
+    if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00) {
        restore_flags(flags);
        printk("PCI: Using configuration type 2\n");
        return &pci_direct_conf2;
@@ -897,6 +897,8 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
 #else
 #ifdef CONFIG_PCI_DIRECT
        a = pci_check_direct();
+#else
+#error "You need to set CONFIG_PCI_BIOS or CONFIG_PCI_DIRECT if you want PCI support."
 #endif
 #endif
        if (a)
index a21ac679103b22f71dd64b23b020f22f20796c20..210f384575bef716ee8e6504271c9b08fda782bf 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  linux/arch/i386/head.S
+ *  linux/arch/i386/head.S -- the 32-bit startup code.
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- *  head.S contains the 32-bit startup code.
+ *
+ *  Enhanced CPU detection and feature setting code by Mike Jagdis
+ *  and Martin Mares, November 1997.
  */
 
 .text
 #define CL_BASE_ADDR   0x90000
 #define CL_OFFSET      0x90022
 
+/*
+ * References to members of the boot_cpu_data structure.
+ */
+
+#define CPU_PARAMS     SYMBOL_NAME(boot_cpu_data)
+#define X86            CPU_PARAMS+0
+#define X86_VENDOR     CPU_PARAMS+1
+#define X86_MODEL      CPU_PARAMS+2
+#define X86_MASK       CPU_PARAMS+3
+#define X86_HARD_MATH  CPU_PARAMS+6
+#define X86_CPUID      CPU_PARAMS+8
+#define X86_CAPABILITY CPU_PARAMS+12
+#define X86_VENDOR_ID  CPU_PARAMS+16
+
 /*
  * swapper_pg_dir is the main page directory, address 0x00101000
  */
@@ -45,15 +58,9 @@ startup_32:
  *     not yet offset 0xC0000000..
  */
 #define cr4_bits mmu_cr4_features-0xC0000000
-#ifdef GAS_KNOWS_CR4
        movl %cr4,%eax          # Turn on 4Mb pages
        orl cr4_bits,%eax
        movl %eax,%cr4
-#else
-       .byte 0x0f,0x20,0xe0
-       orl cr4_bits,%eax
-       .byte 0x0f,0x22,0xe0
-#endif
 #endif
 /*
  * Setup paging (the tables are already set up, just switch them on)
@@ -135,13 +142,69 @@ startup_32:
 checkCPUtype:
 #endif
 
+       movl $-1,X86_CPUID              #  -1 for no CPUID initially
+
 /* check if it is 486 or 386. */
 /*
  * XXX - this does a lot of unnecessary setup.  Alignment checks don't
  * apply at our cpl of 0 and the stack ought to be aligned already, and
  * we don't need to preserve eflags.
  */
-       movl $3, SYMBOL_NAME(x86)
+       /*
+        * A Cyrix preserves flags in cases where other CPUs change
+        * them in undefined ways. We need to know this since we may
+        * need to enable the CPUID instruction at least. (Cyrix chips
+        * prior to M2 have CPUID disabled by default, the Cx486s
+        * didn't have it at all.)
+        */
+       xor %ax,%ax
+       sahf
+       movb $5,%al
+       movb $2,%bl
+       div %bl
+       lahf
+       cmpb $2,%ah
+       jne ncyrix
+
+       /*
+        * It behaves like a Cyrix so put "Cyrix" in the vendor id
+        * field. It may be overwritten later with the real thing
+        * if CPUID works.
+        */
+       movl $0x69727943,X86_VENDOR_ID                  # low 4 chars
+       movl $0x00000078,X86_VENDOR_ID                  # next 4 chars
+
+       /*
+        * N.B. The pattern of accesses to 0x22 and 0x23 is *important*
+        *      so do not try and "optimise" it! For the same reason we
+        *      do all this with interrupts off just to be sure.
+        */
+#define setCx86(reg, val) \
+       movb reg,%al;   \
+       outb %al,$0x22; \
+       movb val,%al;   \
+       outb %al,$0x23
+
+#define getCx86(reg) \
+       movb reg,%al;   \
+       outb %al,$0x22; \
+       inb $0x23,%al
+
+       getCx86($0xc3)          # get CCR3
+       movb %al,%cl            # Save old value
+       movb %al,%bl
+       andb $0x0f,%bl          # Enable all config registers (for CCR4 access)
+       orb $0x10,%bl
+       setCx86($0xc3,%bl)
+
+       getCx86($0xe8)          # CCR4 |= CPUID
+       orb $0x80,%al
+       movb %al,%bl
+       setCx86($0xe8,%bl)
+
+       setCx86($0xc3,%cl)      # Restore old CCR3
+
+ncyrix:        movl $3,X86             # at least 386
        pushfl                  # push EFLAGS
        popl %eax               # get EFLAGS
        movl %eax,%ecx          # save original EFLAGS
@@ -153,7 +216,8 @@ checkCPUtype:
        xorl %ecx,%eax          # change in flags
        andl $0x40000,%eax      # check if AC bit changed
        je is386
-       movl $4,SYMBOL_NAME(x86)
+
+       movl $4,X86             # at least 486
        movl %ecx,%eax
        xorl $0x200000,%eax     # check ID flag
        pushl %eax
@@ -161,42 +225,74 @@ checkCPUtype:
        pushfl                  # 487SX we can't change it
        popl %eax
        xorl %ecx,%eax
-       andl $0x200000,%eax
-       je is486
-isnew: pushl %ecx              # restore original EFLAGS
+       pushl %ecx              # restore original EFLAGS
        popfl
-       incl SYMBOL_NAME(have_cpuid)    # we have CPUID
-       /* get processor type */
-                               # LINUS WE HAVE A BUG HERE - MUST CHECK WITH
-                               # CPUID#0 THAT CPUID#1 IS SUPPORTED...
-       movl $1, %eax           # Use the CPUID instruction to 
-       .byte 0x0f, 0xa2        # check the processor type
-       movb %al, %cl           # save reg for future use
-       andb $0x0f,%ah          # mask processor family
-       movb %ah,SYMBOL_NAME(x86)
-       andb $0xf0, %eax        # mask model
-       shrb $4, %al
-       movb %al,SYMBOL_NAME(x86_model)
-       andb $0x0f, %cl         # mask mask revision
-       movb %cl,SYMBOL_NAME(x86_mask)
-       movl %edx,SYMBOL_NAME(x86_capability)
+       andl $0x200000,%eax
+       je nocpuid
+
        /* get vendor info */
-       xorl %eax, %eax                 # call CPUID with 0 -> return vendor ID
-       .byte 0x0f, 0xa2                # CPUID
-       movl %ebx,SYMBOL_NAME(x86_vendor_id)    # lo 4 chars
-       movl %edx,SYMBOL_NAME(x86_vendor_id)+4  # next 4 chars
-       movl %ecx,SYMBOL_NAME(x86_vendor_id)+8  # last 4 chars
+       xorl %eax,%eax                  # call CPUID with 0 -> return vendor ID
+       cpuid
+       movl %eax,X86_CPUID             # save CPUID level
+       movl %ebx,X86_VENDOR_ID         # lo 4 chars
+       movl %edx,X86_VENDOR_ID+4       # next 4 chars
+       movl %ecx,X86_VENDOR_ID+8       # last 4 chars
 
-       movl %cr0,%eax          # 486+
-       andl $0x80000011,%eax   # Save PG,PE,ET
-       orl $0x50022,%eax       # set AM, WP, NE and MP
-       jmp 2f
-is486: pushl %ecx              # restore original EFLAGS
-       popfl
-       movl %cr0,%eax          # 486
+       orl %eax,%eax                   # do we have processor info as well?
+       je nocpuid
+
+       movl $1,%eax            # Use the CPUID instruction to get CPU type
+       cpuid
+       movb %al,%cl            # save reg for future use
+       andb $0x0f,%ah          # mask processor family
+       movb %ah,X86
+       andb $0xf0,%al          # mask model
+       shrb $4,%al
+       movb %al,X86_MODEL
+       andb $0x0f,%cl          # mask mask revision
+       movb %cl,X86_MASK
+       movl %edx,X86_CAPABILITY
+
+nocpuid:
+       /*
+        * Even if we had CPUID Cyrix tries to look compatible with
+        * Intel so we have to go elsewhere for the nitty gritty.
+        */
+       cmpl $0x69727943,X86_VENDOR_ID          # "Cyri[x.*]"?
+       jne is486                               # maybe ...
+
+       movb $0xfe,X86_MODEL                    # Generic Cx486?
+       movb $0,X86_MASK
+
+       getCx86($0xc3)          # Test for DEVID by writing CCR3
+       movb %al,%cl
+       movb %al,%bl
+       orb $0x80,%bl
+       setCx86($0xc3,%bl)
+       getCx86($0xc0)          # dummy to change bus
+       getCx86($0xc3)
+       cmpb %al,%cl
+       je is486                # not writable == no DEVID
+
+       setCx86($0xc3,%cl)      # restore CCR3
+
+       getCx86($0xff)          # get DEVID in preference to any CPUID
+       movb %al,X86_MASK
+       getCx86($0xfe)
+       movb %al,X86_MODEL
+       andb $0xf0,%al          # Check for 6x86(L)
+       cmp $0x30,%al
+       jnz is486
+       getCx86($0xe9)          # CCR5: reset SLOP bit, so that the udelay loop
+       andb $0xfd,%al          # works well on 6x86(L) CPU's.
+       movb %al,%bl
+       setCx86($0xe9,%bl)
+
+is486: movl %cr0,%eax          # 486 or better
        andl $0x80000011,%eax   # Save PG,PE,ET
        orl $0x50022,%eax       # set AM, WP, NE and MP
        jmp 2f
+
 is386: pushl %ecx              # restore original EFLAGS
        popfl
        movl %cr0,%eax          # 386
@@ -208,17 +304,11 @@ is386:    pushl %ecx              # restore original EFLAGS
        movb ready,%al          # First CPU if 0
        orb %al,%al
        jz 4f                   # First CPU skip this stuff
-#ifdef GAS_KNOWS_CR4
        movl %cr4,%eax          # Turn on 4Mb pages
        orl $16,%eax
        movl %eax,%cr4
-#else
-       .byte 0x0f,0x20,0xe0
-       orl $16,%eax
-       .byte 0x0f,0x22,0xe0
-#endif
-       movl %cr3, %eax         # Intel specification clarification says
-       movl %eax, %cr3         # to do this. Maybe it makes a difference.
+       movl %cr3,%eax          # Intel specification clarification says
+       movl %eax,%cr3          # to do this. Maybe it makes a difference.
                                # Who knows ?
 #endif
 4:
@@ -228,7 +318,7 @@ is386:      pushl %ecx              # restore original EFLAGS
        lgdt gdt_descr
        lidt idt_descr
        ljmp $(__KERNEL_CS),$1f
-1:     movl $(__KERNEL_DS),%eax# reload all the segment registers
+1:     movl $(__KERNEL_DS),%eax        # reload all the segment registers
        mov %ax,%ds             # after changing gdt.
        mov %ax,%es
        mov %ax,%fs
@@ -258,7 +348,7 @@ ready:      .byte 0
  * We depend on ET to be correct. This checks for 287/387.
  */
 check_x87:
-       movb $0,SYMBOL_NAME(hard_math)
+       movb $0,X86_HARD_MATH
        clts
        fninit
        fstsw %ax
@@ -269,7 +359,7 @@ check_x87:
        movl %eax,%cr0
        ret
        ALIGN
-1:     movb $1,SYMBOL_NAME(hard_math)
+1:     movb $1,X86_HARD_MATH
        .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
        ret
 
@@ -366,7 +456,7 @@ ENTRY(swapper_pg_dir)
        .long 0x00102007
        .fill 767,4,0
        .long 0x00102007
-       .fill 127,4,0
+       .fill 255,4,0
 
 /*
  * The page tables are initialized to only 4MB here - the final page
index e71177c3c247b5dd71e3939b0144bf5e40c16cd4..3433bc5dc5c91bd019cc4017a11e11372fb2fbd0 100644 (file)
@@ -27,10 +27,9 @@ EXPORT_SYMBOL(drive_info);
 #endif
 
 /* platform dependent support */
-EXPORT_SYMBOL(x86);
+EXPORT_SYMBOL(boot_cpu_data);
 EXPORT_SYMBOL(EISA_bus);
 EXPORT_SYMBOL(MCA_bus);
-EXPORT_SYMBOL(wp_works_ok);
 EXPORT_SYMBOL(__verify_write);
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
index 62d07450845679e3711c84394a9df97080f308ba..8552adcd6ba63832665b3f3358b3a92c759d73c2 100644 (file)
@@ -15,6 +15,7 @@
  * Naturally it's not a 1:1 relation, but there are similarities.
  */
 
+#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
@@ -202,7 +203,7 @@ static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
 static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
 {
        outb(0,0xF0);
-       if (ignore_irq13 || !hard_math)
+       if (ignore_irq13 || !boot_cpu_data.hard_math)
                return;
        math_error();
 }
index 352c5552a759a6ec5bfbb7cb55436c9d14f24e91..629e7ef12f2b2ae13be1a51b08707d488b3d44ad 100644 (file)
@@ -75,7 +75,7 @@ void enable_hlt(void)
 static void hard_idle(void)
 {
        while (!need_resched) {
-               if (hlt_works_ok && !hlt_counter) {
+               if (boot_cpu_data.hlt_works_ok && !hlt_counter) {
 #ifdef CONFIG_APM
                                /* If the APM BIOS is not enabled, or there
                                 is an error calling the idle routine, we
@@ -114,8 +114,7 @@ asmlinkage int sys_idle(void)
        /* endless idle loop with no priority at all */
        current->priority = -100;
        current->counter = -100;
-       for (;;) 
-       {
+       for (;;) {
                /*
                 *      We are locked at this point. So we can safely call
                 *      the APM bios knowing only one CPU at a time will do
@@ -124,12 +123,9 @@ asmlinkage int sys_idle(void)
                if (!start_idle) 
                        start_idle = jiffies;
                if (jiffies - start_idle > HARD_IDLE_TIMEOUT) 
-               {
                        hard_idle();
-               } 
-               else 
-               {
-                       if (hlt_works_ok && !hlt_counter && !need_resched)
+               else  {
+                       if (boot_cpu_data.hlt_works_ok && !hlt_counter && !need_resched)
                                __asm__("hlt");
                }
                run_task_queue(&tq_scheduler);
@@ -154,7 +150,7 @@ int cpu_idle(void *unused)
        current->priority = -100;
        while(1)
        {
-               if(cpu_data[smp_processor_id()].hlt_works_ok &&
+               if(current_cpu_data.hlt_works_ok &&
                                !hlt_counter && !need_resched)
                        __asm("hlt");
                /*
@@ -185,6 +181,7 @@ asmlinkage int sys_idle(void)
  * controller to pulse the reset-line low. We try that for a while,
  * and if it doesn't work, we do some other stupid things.
  */
+
 static long no_idt[2] = {0, 0};
 static int reboot_mode = 0;
 static int reboot_thru_bios = 0;
@@ -226,7 +223,7 @@ real_mode_gdt_entries [3] =
 {
        0x0000000000000000ULL,  /* Null descriptor */
        0x00009a000000ffffULL,  /* 16-bit real-mode 64k code at 0x00000000 */
-       0x000092000100ffffULL           /* 16-bit real-mode 64k data at 0x00000100 */
+       0x000092000100ffffULL   /* 16-bit real-mode 64k data at 0x00000100 */
 };
 
 static struct
@@ -260,16 +257,16 @@ static unsigned char real_mode_switch [] =
 {
        0x66, 0x0f, 0x20, 0xc0,                 /*    movl  %cr0,%eax        */
        0x66, 0x83, 0xe0, 0x11,                 /*    andl  $0x00000011,%eax */
-       0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,             /*    orl   $0x60000000,%eax */
+       0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,     /*    orl   $0x60000000,%eax */
        0x66, 0x0f, 0x22, 0xc0,                 /*    movl  %eax,%cr0        */
        0x66, 0x0f, 0x22, 0xd8,                 /*    movl  %eax,%cr3        */
        0x66, 0x0f, 0x20, 0xc3,                 /*    movl  %cr0,%ebx        */
        0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,       /*    andl  $0x60000000,%ebx */
-       0x74, 0x02,                                     /*    jz    f                */
-       0x0f, 0x08,                                     /*    invd                   */
-       0x24, 0x10,                                     /* f: andb  $0x10,al         */
+       0x74, 0x02,                             /*    jz    f                */
+       0x0f, 0x08,                             /*    invd                   */
+       0x24, 0x10,                             /* f: andb  $0x10,al         */
        0x66, 0x0f, 0x22, 0xc0,                 /*    movl  %eax,%cr0        */
-       0xea, 0x00, 0x00, 0xff, 0xff                    /*    ljmp  $0xffff,$0x0000  */
+       0xea, 0x00, 0x00, 0xff, 0xff            /*    ljmp  $0xffff,$0x0000  */
 };
 
 static inline void kb_wait(void)
@@ -301,7 +298,7 @@ void machine_restart(char * __unused)
                }
        }
 
-       cli ();
+       cli();
 
        /* Write zero to CMOS register number 0x0f, which the BIOS POST
           routine will recognize as telling it to do a proper reboot.  (Well
@@ -325,7 +322,7 @@ void machine_restart(char * __unused)
        /* Make sure the first page is mapped to the start of physical memory.
           It is normally not mapped, to trap kernel NULL pointer dereferences. */
 
-       pg0 [0] = 7;
+       pg0[0] = 7;
 
        /*
         * Use `swapper_pg_dir' as our page directory.  We bother with
@@ -530,7 +527,7 @@ int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu)
        int fpvalid;
 
        if ((fpvalid = current->used_math) != 0) {
-               if (hard_math) {
+               if (boot_cpu_data.hard_math) {
                  if (last_task_used_math == current) {
                          __asm__("clts ; fsave %0; fwait": :"m" (*fpu));
                  }
index 9868811a6a0ee72c2500d420efc5afee6b7e4742..6469e61e942696d538e899cfac53f7c19238bed1 100644 (file)
@@ -2,6 +2,9 @@
  *  linux/arch/i386/kernel/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
+ *  and Martin Mares, November 1997.
  */
 
 /*
 #include <asm/smp.h>
 
 /*
- * Tell us the machine setup..
+ * Machine setup..
  */
-char hard_math = 0;            /* set by kernel/head.S */
-char x86 = 0;                  /* set by kernel/head.S to 3..6 */
-char x86_model = 0;            /* set by kernel/head.S */
-char x86_mask = 0;             /* set by kernel/head.S */
-int x86_capability = 0;                /* set by kernel/head.S */
-int fdiv_bug = 0;              /* set if Pentium(TM) with FP bug */
-int pentium_f00f_bug = 0;      /* set if Pentium(TM) with F00F bug */
-int have_cpuid = 0;             /* set if CPUID instruction works */
-
-char x86_vendor_id[13] = "unknown";
 
 char ignore_irq13 = 0;         /* set if exception 16 works */
-char wp_works_ok = -1;         /* set if paging hardware honours WP */ 
-char hlt_works_ok = 1;         /* set if the "hlt" instruction works */
+struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
 
 /*
  * Bus types ..
@@ -93,9 +85,7 @@ extern char empty_zero_page[PAGE_SIZE];
  */
 #define PARAM  empty_zero_page
 #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#ifndef STANDARD_MEMORY_BIOS_CALL
 #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
-#endif
 #ifdef CONFIG_APM
 #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
 #endif
@@ -124,15 +114,12 @@ __initfunc(void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
        unsigned long memory_start, memory_end;
-       unsigned long memory_alt_end;
        char c = ' ', *to = command_line, *from = COMMAND_LINE;
        int len = 0;
        static unsigned char smptrap=0;
 
-       if(smptrap==1)
-       {
+       if (smptrap)
                return;
-       }
        smptrap=1;
 
        ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
@@ -150,13 +137,12 @@ __initfunc(void setup_arch(char **cmdline_p,
        aux_device_present = AUX_DEVICE_INFO;
        memory_end = (1<<20) + (EXT_MEM_K<<10);
 #ifndef STANDARD_MEMORY_BIOS_CALL
-       memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
-       if (memory_alt_end > memory_end) {
-           printk("Memory: sized by int13 0e801h\n");
-           memory_end = memory_alt_end;
+       {
+               unsigned long memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
+               /* printk(KERN_DEBUG "Memory sizing: %08x %08x\n", memory_end, memory_alt_end); */
+               if (memory_alt_end > memory_end)
+                       memory_end = memory_alt_end;
        }
-       else
-           printk("Memory: sized by int13 088h\n");
 #endif
        memory_end &= PAGE_MASK;
 #ifdef CONFIG_BLK_DEV_RAM
@@ -186,7 +172,7 @@ __initfunc(void setup_arch(char **cmdline_p,
                        if (to != command_line) to--;
                        if (!memcmp(from+4, "nopentium", 9)) {
                                from += 9+4;
-                               x86_capability &= ~8;
+                               boot_cpu_data.x86_capability &= ~8;
                        } else {
                                memory_end = simple_strtoul(from+4, &from, 0);
                                if ( *from == 'K' || *from == 'k' ) {
@@ -232,79 +218,220 @@ __initfunc(void setup_arch(char **cmdline_p,
        request_region(0xf0,0x10,"fpu");
 }
 
-static const char * i486model(unsigned int nr)
+/*
+ *     Detection of CPU model.
+ */
+
+extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
 {
-       static const char *model[] = {
-               "0","DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB",
-               "10","11","12","13","Am5x86-WT","Am5x86-WB"
-       };
-       if (nr < sizeof(model)/sizeof(char *))
-               return model[nr];
-       return NULL;
+       __asm__("cpuid"
+               : "=a" (*eax),
+                 "=b" (*ebx),
+                 "=c" (*ecx),
+                 "=d" (*edx)
+               : "a" (op)
+               : "cc");
 }
 
-static const char * i586model(unsigned int nr)
+__initfunc(static int cyrix_model(struct cpuinfo_x86 *c))
 {
-       static const char *model[] = {
-               "0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83",
-               "Pentium MMX"
-       };
-       if (nr < sizeof(model)/sizeof(char *))
-               return model[nr];
-       return NULL;
+       int nr = c->x86_model;
+       char *buf = c->x86_model_id;
+
+       /* Note that some of the possibilities this decoding allows
+        * have never actually been manufactured - but those that
+        * do actually exist are correctly decoded.
+        */
+       if (nr < 0x20) {
+               strcpy(buf, "Cx486");
+               if (!(nr & 0x10)) {
+                       sprintf(buf+5, "%c%s%c",
+                               (nr & 0x01) ? 'D' : 'S',
+                               (nr & 0x04) ? "Rx" : "LC",
+                               (nr & 0x02) ? '2' : '\000');
+               } else if (!(nr & 0x08)) {
+                       sprintf(buf+5, "S%s%c",
+                               (nr & 0x01) ? "2" : "",
+                               (nr & 0x02) ? 'e' : '\000');
+               } else {
+                       sprintf(buf+5, "DX%c",
+                               nr == 0x1b ? '2'
+                                       : (nr == 0x1f ? '4' : '\000'));
+               }
+       } else if (nr >= 0x20 && nr <= 0x4f) {  /* 5x86, 6x86 or Gx86 */
+               char *s = "";
+               if (nr >= 0x30 && nr < 0x40) {  /* 6x86 */
+                       if (c->x86 == 5 && (c->x86_capability & (1 << 8)))
+                               s = "L";        /* 6x86L */
+                       else if (c->x86 == 6)
+                               s = "MX";       /* 6x86MX */
+                       }
+               sprintf(buf, "%cx86%s %cx Core/Bus Clock",
+                       "??56G"[nr>>4],
+                       s,
+                       "12??43"[nr & 0x05]);
+       } else if (nr >= 0x50 && nr <= 0x5f) {  /* Cyrix 6x86MX */
+               sprintf(buf, "6x86MX %c%sx Core/Bus Clock",
+                       "12233445"[nr & 0x07],
+                       (nr && !(nr&1)) ? ".5" : "");
+       } else if (nr >= 0xfd && c->cpuid_level < 0) {
+               /* Probably 0xfd (Cx486[SD]LC with no ID register)
+                * or 0xfe (Cx486 A step with no ID register).
+                */
+               strcpy(buf, "Cx486");
+       } else
+               return 0;       /* Use CPUID if applicable */
+       return 1;
 }
 
-static const char * k5model(unsigned int nr)
+__initfunc(static int amd_model(struct cpuinfo_x86 *c))
 {
-       static const char *model[] = {
-               "SSA5 (PR-75, PR-90, PR-100)", "5k86 (PR-120, PR-133)",
-               "5k86 (PR-166)", "5k86 (PR-200)", "", "", 
-               "K6(PR-133..PR-166)","K6(PR-133..PR-200)"
-       };
-       if (nr < sizeof(model)/sizeof(char *))
-               return model[nr];
-       return NULL;
+       unsigned int n, dummy, *v;
+
+       /* Actually we must have cpuid or we could never have
+        * figured out that this was AMD from the vendor info :-).
+        */
+
+       cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
+       if (n < 4)
+               return 0;
+       v = (unsigned int *) c->x86_model_id;
+       cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+       cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+       cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+       c->x86_model_id[48] = 0;
+       return 1;
 }
 
-static const char * i686model(unsigned int nr)
+__initfunc(void get_cpu_vendor(struct cpuinfo_x86 *c))
 {
-       static const char *model[] = {
-               "PPro A-step", "Pentium Pro", "2", "Pentium II"
-       };
-       if (nr < sizeof(model)/sizeof(char *))
-               return model[nr];
-       return NULL;
+       char *v = c->x86_vendor_id;
+
+       if (!strcmp(v, "GenuineIntel"))
+               c->x86_vendor = X86_VENDOR_INTEL;
+       else if (!strcmp(v, "AuthenticAMD"))
+               c->x86_vendor = X86_VENDOR_AMD;
+       else if (!strncmp(v, "Cyrix", 5))
+               c->x86_vendor = X86_VENDOR_CYRIX;
+       else if (!strcmp(v, "UMC UMC UMC "))
+               c->x86_vendor = X86_VENDOR_UMC;
+       else if (!strcmp(v, "CentaurHauls"))
+               c->x86_vendor = X86_VENDOR_CENTAUR;
+       else if (!strcmp(v, "NexGenDriven"))
+               c->x86_vendor = X86_VENDOR_NEXGEN;
+       else
+               c->x86_vendor = X86_VENDOR_UNKNOWN;
 }
 
-static const char * getmodel(int x86, int model)
+struct cpu_model_info {
+       int vendor;
+       int x86;
+       char *model_names[16];
+};
+
+static struct cpu_model_info cpu_models[] __initdata = {
+       { X86_VENDOR_INTEL,     4,
+               { "486 DX-25/33", "486 DX-50", "486 SX", "487 DX", "486 DX/2", "486 SL", "486 SX/2",
+                 NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_INTEL,     5,
+         { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75+",
+           "OverDrive PODP5V83", "Pentium MMX", NULL, NULL,
+           "Mobile Pentium 75+", "Mobile Pentium MMX", NULL, NULL, NULL,
+           NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_INTEL,     6,
+         { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II", NULL,
+           NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_CYRIX,     4,
+         { NULL, NULL, NULL, NULL, "MediaGX", NULL, NULL, NULL, NULL, "5x86",
+           NULL, NULL, NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_CYRIX,     5,
+         { NULL, NULL, "6x86", NULL, "GXm", NULL, NULL, NULL, NULL,
+           NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_CYRIX,     6,
+         { "6x86MX", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+           NULL, NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_AMD,       4,
+         { NULL, NULL, NULL, "DX/2", NULL, NULL, NULL, "DX/2-WB", "DX/4",
+           "DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }},
+       { X86_VENDOR_AMD,       5,
+         { "K5/SSA5 (PR-75, PR-90, PR-100)", "K5 (PR-120, PR-133)",
+           "K5 (PR-166)", "K5 (PR-200)", NULL, NULL,
+           "K6 (166 - 266)", "K6 (166 - 300)", "K6 (model 8)",
+           "K6 (model 9)", NULL, NULL, NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_UMC,       4,
+         { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+           NULL, NULL, NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_CENTAUR,   5,
+         { NULL, NULL, NULL, NULL, "C6", NULL, NULL, NULL, NULL, NULL, NULL,
+           NULL, NULL, NULL, NULL, NULL }},
+       { X86_VENDOR_NEXGEN,    5,
+         { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+           NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
+};
+
+__initfunc(void identify_cpu(struct cpuinfo_x86 *c))
 {
-        const char *p = NULL;
-        static char nbuf[12];
-       switch (x86) {
-               case 4:
-                       p = i486model(model);
-                       break;
-               case 5:
-                       if(strcmp(x86_vendor_id, "AuthenticAMD") == 0){
-                               p = k5model(model);
-                       } else {
-                               p = i586model(model);
+       int i;
+       char *p = NULL;
+
+       c->loops_per_sec = loops_per_sec;
+
+       get_cpu_vendor(c);
+
+       if (c->x86_vendor == X86_VENDOR_UNKNOWN &&
+           c->cpuid_level < 0)
+               return;
+
+       if ((c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) ||
+           (c->x86_vendor == X86_VENDOR_CYRIX && cyrix_model(c)))
+               return;
+
+       if (c->x86_model < 16)
+               for (i=0; i<sizeof(cpu_models)/sizeof(struct cpu_model_info); i++)
+                       if (cpu_models[i].vendor == c->x86_vendor &&
+                           cpu_models[i].x86 == c->x86) {
+                               p = cpu_models[i].model_names[c->x86_model];
+                               break;
                        }
-                       break;
-               case 6:
-                       p = i686model(model);
-                       break;
-       }
-        if (p)
-                return p;
+       if (p)
+               strcpy(c->x86_model_id, p);
+       else
+               sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model);
+}
+
+static char *cpu_vendor_names[] __initdata = {
+       "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" };
+
+__initfunc(void print_cpu_info(struct cpuinfo_x86 *c))
+{
+       char *vendor = NULL;
+
+       if (c->x86_vendor < sizeof(cpu_vendor_names)/sizeof(char *))
+               vendor = cpu_vendor_names[c->x86_vendor];
+       else if (c->cpuid_level >= 0)
+               vendor = c->x86_vendor_id;
 
-        sprintf(nbuf, "%d", model);
-        return nbuf;
+       if (vendor)
+               printk("%s ", vendor);
+
+       if (!c->x86_model_id[0])
+               printk("%d86", c->x86);
+       else
+               printk("%s", c->x86_model_id);
+
+       if (c->x86_mask)
+               printk(" stepping %02x", c->x86_mask);
+
+       printk("\n");
 }
 
+/*
+ *     Get CPU information for use by the procfs.
+ */
+
 int get_cpuinfo(char * buffer)
 {
-        int i, len = 0;
+       char *p = buffer;
        int sep_bug;
         static const char *x86_cap_flags[] = {
                 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
@@ -312,83 +439,63 @@ int get_cpuinfo(char * buffer)
                 "16", "17", "18", "19", "20", "21", "22", "mmx",
                 "24", "25", "26", "27", "28", "29", "30", "31"
         };
-        
-#ifdef __SMP__
-        int n;
+       struct cpuinfo_x86 *c = cpu_data;
+       int i, n;
 
-#define CD(X)          (cpu_data[n].X)
-/* SMP has the wrong name for loops_per_sec */
-#define loops_per_sec  udelay_val
-#define CPUN n
-
-        for ( n = 0 ; n < 32 ; n++ ) {
-                if ( cpu_present_map & (1<<n) ) {
-                        if (len) buffer[len++] = '\n'; 
-
-#else
-#define CD(X) (X)
-#define CPUN 0
-#endif
-
-                        len += sprintf(buffer+len,"processor\t: %d\n"
-                                       "cpu\t\t: %c86\n"
-                                       "model\t\t: %s\n"
-                                       "vendor_id\t: %s\n",
-                                       CPUN,
-                                       CD(x86)+'0',
-                                       CD(have_cpuid) ? 
-                                         getmodel(CD(x86), CD(x86_model)) :
-                                         "unknown",
-                                       CD(x86_vendor_id));
-        
-                        if (CD(x86_mask))
-                                len += sprintf(buffer+len,
-                                               "stepping\t: %d\n",
-                                               CD(x86_mask));
-                        else
-                                len += sprintf(buffer+len, 
-                                               "stepping\t: unknown\n");
-
-                       sep_bug = CD(have_cpuid) &&
-                                 (CD(x86_capability) & 0x800) &&
-                                 !memcmp(x86_vendor_id, "GenuineIntel", 12) &&
-                                 CD(x86) == 6 &&
-                                 CD(x86_model) < 3 &&
-                                 CD(x86_mask) < 3;
-        
-                        len += sprintf(buffer+len,
-                                       "fdiv_bug\t: %s\n"
-                                       "hlt_bug\t\t: %s\n"
-                                      "sep_bug\t\t: %s\n"
-                                      "f00f_bug\t: %s\n"
-                                       "fpu\t\t: %s\n"
-                                       "fpu_exception\t: %s\n"
-                                       "cpuid\t\t: %s\n"
-                                       "wp\t\t: %s\n"
-                                       "flags\t\t:",
-                                       CD(fdiv_bug) ? "yes" : "no",
-                                       CD(hlt_works_ok) ? "no" : "yes",
-                                      sep_bug ? "yes" : "no",
-                                      pentium_f00f_bug ? "yes" : "no",
-                                       CD(hard_math) ? "yes" : "no",
-                                       (CD(hard_math) && ignore_irq13)
-                                         ? "yes" : "no",
-                                       CD(have_cpuid) ? "yes" : "no",
-                                       CD(wp_works_ok) ? "yes" : "no");
-        
-                        for ( i = 0 ; i < 32 ; i++ ) {
-                                if ( CD(x86_capability) & (1 << i) ) {
-                                        len += sprintf(buffer+len, " %s",
-                                                       x86_cap_flags[i]);
-                                }
-                        }
-                        len += sprintf(buffer+len,
-                                       "\nbogomips\t: %lu.%02lu\n",
-                                       CD(loops_per_sec+2500)/500000,
-                                       (CD(loops_per_sec+2500)/5000) % 100);
+       for(n=0; n<NR_CPUS; n++, c++) {
 #ifdef __SMP__
-                }
-        }
+               if (!(cpu_present_map & (1<<n)))
+                       continue;
 #endif
-        return len;
+               p += sprintf(p, "processor\t: %d\n"
+                              "cpu family\t: %c\n"
+                              "model\t\t: %s\n"
+                              "vendor_id\t: %s\n",
+                              n,
+                              c->x86 + '0',
+                              c->x86_model_id[0] ? c->x86_model_id : "unknown",
+                              c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown");
+               if (c->x86_mask) {
+                       if (c->x86_vendor == X86_VENDOR_CYRIX)
+                               p += sprintf(p, "stepping\t: %d rev %d\n",
+                                            c->x86_mask >> 4,
+                                            c->x86_mask & 0x0f);
+                       else
+                               p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
+               } else
+                       p += sprintf(p, "stepping\t: unknown\n");
+
+               sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
+                         c->x86 == 0x06 &&
+                         c->cpuid_level >= 0 &&
+                         (c->x86_capability & 0x800) &&
+                         c->x86_model < 3 &&
+                         c->x86_mask < 3;
+        
+               p += sprintf(p, "fdiv_bug\t: %s\n"
+                               "hlt_bug\t\t: %s\n"
+                               "sep_bug\t\t: %s\n"
+                               "f00f_bug\t: %s\n"
+                               "fpu\t\t: %s\n"
+                               "fpu_exception\t: %s\n"
+                               "cpuid level\t: %d\n"
+                               "wp\t\t: %s\n"
+                               "flags\t\t:",
+                            c->fdiv_bug ? "yes" : "no",
+                            c->hlt_works_ok ? "no" : "yes",
+                            sep_bug ? "yes" : "no",
+                            c->f00f_bug ? "yes" : "no",
+                            c->hard_math ? "yes" : "no",
+                            (c->hard_math && ignore_irq13) ? "yes" : "no",
+                            c->cpuid_level,
+                            c->wp_works_ok ? "yes" : "no");
+
+               for ( i = 0 ; i < 32 ; i++ )
+                       if ( c->x86_capability & (1 << i) )
+                               p += sprintf(p, " %s", x86_cap_flags[i]);
+               p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n",
+                            (c->loops_per_sec+2500)/500000,
+                            ((c->loops_per_sec+2500)/5000) % 100);
+       }
+        return p - buffer;
 }
index 853b821004231f2996d7f6f98a9b829b8f5f3452..3c321a83e10b5ef92fe75c7504f06aac423d6cc4 100644 (file)
@@ -165,7 +165,7 @@ static inline void restore_i387(struct _fpstate *buf)
 #ifndef CONFIG_MATH_EMULATION
        restore_i387_hard(buf);
 #else
-       if (hard_math)
+       if (boot_cpu_data.hard_math)
                restore_i387_hard(buf);
        else
                restore_i387_soft(&current->tss.i387.soft, buf);
@@ -325,7 +325,7 @@ static struct _fpstate * save_i387(struct _fpstate *buf)
 #ifndef CONFIG_MATH_EMULATION
        return save_i387_hard(buf);
 #else
-       return hard_math ? save_i387_hard(buf)
+       return boot_cpu_data.hard_math ? save_i387_hard(buf)
          : save_i387_soft(&current->tss.i387.soft, buf);
 #endif
 }
index eef0303750eccf25f37e0a2380883c51a6d6cf04..b4c5062d59ed57183fc0a66381e91a169d55c631 100644 (file)
@@ -460,7 +460,7 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
                                        cpu_present_map=3;
                                        num_processors=2;
                                        printk("I/O APIC at 0xFEC00000.\n");
-                                       printk("Bus#0 is ");
+                                       printk("Bus #0 is ");
                                }
                                switch(mpf->mpf_feature1)
                                {
@@ -558,7 +558,7 @@ __initfunc(static unsigned long setup_trampoline(void))
 __initfunc(unsigned long smp_alloc_memory(unsigned long mem_base))
 {
        if (virt_to_phys((void *)mem_base) >= 0x9F000)
-               panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.\n", mem_base);
+               panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.", mem_base);
        trampoline_base = (void *)mem_base;
        return mem_base + PAGE_SIZE;
 }
@@ -571,22 +571,17 @@ __initfunc(unsigned long smp_alloc_memory(unsigned long mem_base))
 __initfunc(void smp_store_cpu_info(int id))
 {
        struct cpuinfo_x86 *c=&cpu_data[id];
-       c->hard_math=hard_math;                 /* Always assumed same currently */
-       c->x86=x86;
-       c->x86_model=x86_model;
-       c->x86_mask=x86_mask;
+
+       *c = boot_cpu_data;
+       identify_cpu(c);
        /*
         *      Mask B, Pentium, but not Pentium MMX
         */
-       if(x86_mask>=1 && x86_mask<=4 && x86==5 && (x86_model>=0&&x86_model<=3))
+       if (c->x86_vendor == X86_VENDOR_INTEL &&
+           c->x86 == 5 &&
+           c->x86_mask >= 1 && c->x86_mask <= 4 &&
+           c->x86_model <= 3)
                smp_b_stepping=1;               /* Remember we have B step Pentia with bugs */
-       c->x86_capability=x86_capability;
-       c->fdiv_bug=fdiv_bug;
-       c->wp_works_ok=wp_works_ok;             /* Always assumed the same currently */
-       c->hlt_works_ok=hlt_works_ok;
-       c->have_cpuid=have_cpuid;
-       c->udelay_val=loops_per_sec;
-       strcpy(c->x86_vendor_id, x86_vendor_id);
 }
 
 /*
@@ -706,7 +701,7 @@ __initfunc(static void do_boot_cpu(int i))
 
        idle = task[cpucount];
        if (!idle)
-               panic("No idle process for CPU %d\n", i);
+               panic("No idle process for CPU %d", i);
 
        idle->processor = i;
        cpu_logical_map[cpucount] = i;
@@ -855,6 +850,9 @@ __initfunc(static void do_boot_cpu(int i))
                        cpu_number_map[i] = cpucount;
                        cpu_logical_map[cpucount] = i;
 #endif
+                       printk("OK.\n");
+                       printk("CPU%d: ", i);
+                       print_cpu_info(&cpu_data[i]);
                }
                else
                {
@@ -901,28 +899,33 @@ __initfunc(void smp_boot_cpus(void))
         */
 
        smp_store_cpu_info(boot_cpu_id);                        /* Final full version of the data */
+       printk("CPU%d: ", boot_cpu_id);
+       print_cpu_info(&cpu_data[boot_cpu_id]);
 
        cpu_present_map |= (1 << hard_smp_processor_id());
        cpu_number_map[boot_cpu_id] = 0;
        active_kernel_processor=boot_cpu_id;
 
        /*
-        *      If SMP should be disabled, then really disable it!
+        *      If we don't conform to the Intel MPS standard, get out
+        *      of here now!
         */
 
-       if (!max_cpus && smp_found_config)
+       if (!smp_found_config)
        {
-               smp_found_config = 0;
-               printk("SMP mode deactivated, forcing use of dummy APIC emulation.\n");
+               printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n");
+               return;
        }
 
        /*
-        *      If we don't conform to the Intel MPS standard, get out
-        *      of here now!
+        *      If SMP should be disabled, then really disable it!
         */
 
-       if (!smp_found_config)
-               return;
+       if (!max_cpus)
+       {
+               smp_found_config = 0;
+               printk("SMP mode deactivated, forcing use of dummy APIC emulation.\n");
+       }
 
        /*
         *      Map the local APIC into kernel space
@@ -931,7 +934,7 @@ __initfunc(void smp_boot_cpus(void))
        apic_reg = ioremap(apic_addr,4096);
 
        if(apic_reg == NULL)
-               panic("Unable to map local apic.\n");
+               panic("Unable to map local apic.");
 
 #ifdef SMP_DEBUG
        {
@@ -1049,7 +1052,7 @@ __initfunc(void smp_boot_cpus(void))
        SMP_PRINTK(("Before bogomips.\n"));
        if(cpucount==0)
        {
-               printk("Error: only one processor found.\n");
+               printk(KERN_ERR "Error: only one processor found.\n");
                cpu_present_map=(1<<hard_smp_processor_id());
        }
        else
@@ -1058,7 +1061,7 @@ __initfunc(void smp_boot_cpus(void))
                for(i=0;i<32;i++)
                {
                        if(cpu_present_map&(1<<i))
-                               bogosum+=cpu_data[i].udelay_val;
+                               bogosum+=cpu_data[i].loops_per_sec;
                }
                printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
                        cpucount+1,
@@ -1069,7 +1072,7 @@ __initfunc(void smp_boot_cpus(void))
                smp_num_cpus=cpucount+1;
        }
        if(smp_b_stepping)
-               printk("WARNING: SMP operation may be unreliable with B stepping processors.\n");
+               printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
        SMP_PRINTK(("Boot done.\n"));
 }
 
@@ -1417,7 +1420,7 @@ asmlinkage void smp_reschedule_interrupt(void)
         * for the global interrupt lock.
         */
        irq_enter(cpu, 0);
-       need_resched=1;
+       need_resched = 1;
        irq_exit(cpu, 0);
 }
 
@@ -1451,7 +1454,7 @@ asmlinkage void smp_stop_cpu_interrupt(void)
  * closely follows bus clocks.
  */
 
-#define RTDSC(x)       __asm__ __volatile__ (  ".byte 0x0f,0x31" \
+#define RDTSC(x)       __asm__ __volatile__ (  "rdtsc" \
                                :"=a" (((unsigned long*)&x)[0]),  \
                                 "=d" (((unsigned long*)&x)[1]))
 
@@ -1576,7 +1579,7 @@ __initfunc(int calibrate_APIC_clock (void))
        /*
         * We wrapped around just now, lets start:
         */
-       RTDSC(t1);
+       RDTSC(t1);
        tt1=apic_read(APIC_TMCCT);
 
 #define LOOPS (HZ/10)
@@ -1587,7 +1590,7 @@ __initfunc(int calibrate_APIC_clock (void))
                wait_8254_wraparound ();
 
        tt2=apic_read(APIC_TMCCT);
-       RTDSC(t2);
+       RDTSC(t2);
 
        /*
         * The APIC bus clock counter is 32 bits only, it
@@ -1696,6 +1699,3 @@ int setup_profiling_timer (unsigned int multiplier)
 }
 
 #undef APIC_DIVISOR
-#undef RTDSC
-
-
index a08c9c49cdccab5a3c4b1cd2c088d46d1b223891..5d7d3a6fe62cf6af8418b51fcebf7aadbe6a5a20 100644 (file)
@@ -109,8 +109,7 @@ static unsigned long do_fast_gettimeoffset(void)
        }
 
        /* Read the time counter */
-       __asm__(".byte 0x0f,0x31"
-               :"=a" (eax), "=d" (edx));
+       __asm__("rdtsc" : "=a" (eax), "=d" (edx));
 
        /* .. relative to previous jiffy (32 bits is enough) */
        edx = 0;
@@ -437,7 +436,7 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        /* read Pentium cycle counter */
-       __asm__(".byte 0x0f,0x31"
+       __asm__("rdtsc"
                :"=a" (last_timer_cc.low),
                 "=d" (last_timer_cc.high));
        timer_interrupt(irq, NULL, regs);
@@ -528,26 +527,24 @@ __initfunc(void time_init(void))
                                /* Don't use them if a suspend/resume could
                                    corrupt the timer value.  This problem
                                    needs more debugging. */
-       if (x86_capability & 16) {
+       if (boot_cpu_data.x86_capability & 16) {
                do_gettimeoffset = do_fast_gettimeoffset;
                do_get_fast_time = do_x86_get_fast_time;
 
-               if( strcmp( x86_vendor_id, "AuthenticAMD" ) == 0 ) {
-                       if( x86 == 5 ) {
-                               if( x86_model == 0 ) {
-                                       /* turn on cycle counters during power down */
-                                       __asm__ __volatile__ (" movl $0x83, %%ecx \n \
-                                                               .byte 0x0f,0x32 \n \
-                                                               orl $1,%%eax \n \
-                                                               .byte 0x0f,0x30 \n " 
-                                                                : : : "ax", "cx", "dx" );
-                                       udelay(500);
-                               }
-                       }
+               if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+                   boot_cpu_data.x86 == 5 &&
+                   boot_cpu_data.x86_model == 0) {
+                       /* turn on cycle counters during power down */
+                       __asm__ __volatile__ (" movl $0x83, %%ecx \n \
+                               rdmsr \n \
+                               orl $1,%%eax \n \
+                               wrmsr \n " 
+                                      : : : "ax", "cx", "dx" );
+                               udelay(500);
                }
 
                /* read Pentium cycle counter */
-               __asm__(".byte 0x0f,0x31"
+               __asm__("rdtsc"
                        :"=a" (init_timer_cc.low),
                         "=d" (init_timer_cc.high));
                irq0.handler = pentium_timer_interrupt;
index bd125a0414fe447735a455e9977b02c0f69a6066..d289aa35b611194d2a80797b14edbc42a48cad7d 100644 (file)
@@ -6,9 +6,7 @@
 
 /*
  * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
- * to mainly kill the offending process (probably by giving it a signal,
- * but possibly by killing it outright if necessary).
+ * state in 'asm.s'.
  */
 #include <linux/config.h>
 #include <linux/head.h>
index 4afc206e58525b3416510af0c0cf60e2596e5a93..12b6b468370f744dd41852ecf079638ca164ff9e 100644 (file)
 #include <asm/smp.h>
 #endif
 
-#ifdef __SMP__
-#define __udelay_val cpu_data[smp_processor_id()].udelay_val
-#else
-#define __udelay_val loops_per_sec
-#endif
-
 void __delay(unsigned long loops)
 {
        __asm__ __volatile__(
@@ -34,7 +28,7 @@ inline void __const_udelay(unsigned long xloops)
 {
        __asm__("mull %0"
                :"=d" (xloops)
-               :"a" (xloops),"0" (__udelay_val)
+               :"a" (xloops),"0" (current_cpu_data.loops_per_sec)
                :"ax");
         __delay(xloops);
 }
index beb9f91a467a1070e08a7bb7a35cda42e552ed67..75ada6ba033c42eec3f5ad3c212f585197d73ccd 100644 (file)
@@ -76,8 +76,6 @@ bad_area:
 
 asmlinkage void do_invalid_op (struct pt_regs *, unsigned long);
 
-extern int pentium_f00f_bug;
-
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -180,7 +178,7 @@ bad_area:
        /*
         * Pentium F0 0F C7 C8 bug workaround.
         */
-       if (pentium_f00f_bug) {
+       if (boot_cpu_data.f00f_bug) {
                unsigned long nr;
                
                nr = (address - (unsigned long) idt) >> 3;
@@ -209,10 +207,16 @@ bad_area:
  *
  * First we check if it was the bootup rw-test, though..
  */
-       if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) {
-               wp_works_ok = 1;
-               pg0[0] = pte_val(mk_pte(TASK_SIZE, PAGE_SHARED));
-               flush_tlb();
+       if (boot_cpu_data.wp_works_ok < 0 &&
+           address == PAGE_OFFSET && (error_code & 1)) {
+               boot_cpu_data.wp_works_ok = 1;
+               pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_KERNEL));
+               local_flush_tlb();
+               /*
+                * Beware: Black magic here. The printk is needed here to flush
+                * CPU state on certain buggy processors.
+                */
+               printk("Ok");
                goto out;
        }
 
index 6ed47e2ef85f44e4dce0748db36ac7f6ed7dac77..b8f4742e937c2c27bb5cf27e52c0c944654783f4 100644 (file)
@@ -131,14 +131,6 @@ extern char __init_begin, __init_end;
 #define X86_FEATURE_MCA                0x4000          /* Machine Check Architecture */
 #define X86_FEATURE_CMOV       0x8000          /* Cmov/fcomi */
 
-#ifdef GAS_KNOWS_CR4
-#define read_cr4       "movl %%cr4,%%eax"
-#define write_cr4      "movl %%eax,%%cr4"
-#else
-#define read_cr4       ".byte 0x0f,0x20,0xe0"
-#define write_cr4      ".byte 0x0f,0x22,0xe0"
-#endif
-
 /*
  * Save the cr4 feature set we're using (ie
  * Pentium 4MB enable and PPro Global page
@@ -150,9 +142,9 @@ unsigned long mmu_cr4_features __initdata = 0;
 static inline void set_in_cr4(unsigned long mask)
 {
        mmu_cr4_features |= mask;
-       __asm__(read_cr4 "\n\t"
+       __asm__("movl %%cr4,%%eax\n\t"
                "orl %0,%%eax\n\t"
-               write_cr4
+               "movl %%eax,%%cr4\n"
                : : "irg" (mask)
                :"ax");
 }
@@ -178,9 +170,6 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
  * kernel.
  * It may also hold the MP configuration table when we are booting SMP.
  */
-#if 0
-       memset((void *) 0, 0, PAGE_SIZE);
-#endif
 #ifdef __SMP__
        if (!smp_scan_config(0x0,0x400))        /* Scan the bottom 1K for a signature */
        {
@@ -198,9 +187,6 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
         *      here.
         */
 /*     smp_alloc_memory(8192); */
-#endif
-#ifdef TEST_VERIFY_AREA
-       wp_works_ok = 0;
 #endif
        start_mem = PAGE_ALIGN(start_mem);
        address = PAGE_OFFSET;
@@ -219,14 +205,14 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
                 * virtual memory boundary, but that's OK as we won't
                 * use that memory anyway.
                 */
-               if (x86_capability & X86_FEATURE_PSE) {
+               if (boot_cpu_data.x86_capability & X86_FEATURE_PSE) {
                        unsigned long __pe;
 
                        set_in_cr4(X86_CR4_PSE);
-                       wp_works_ok = 1;
+                       boot_cpu_data.wp_works_ok = 1;
                        __pe = _KERNPG_TABLE + _PAGE_4M + __pa(address);
                        /* Make it "global" too if supported */
-                       if (x86_capability & X86_FEATURE_PGE) {
+                       if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) {
                                set_in_cr4(X86_CR4_PGE);
                                __pe += _PAGE_GLOBAL;
                        }
@@ -235,6 +221,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
                        address += 4*1024*1024;
                        continue;
                }
+
                /*
                 * We're on a [34]86, use normal page tables.
                 * pg_table is physical at this point
@@ -247,6 +234,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
 
                pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pg_table;
                pg_dir++;
+
                /* now change pg_table to kernel virtual addresses */
                pg_table = (pte_t *) __va(pg_table);
                for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
@@ -288,14 +276,14 @@ __initfunc(void test_wp_bit(void))
        pg0[0] = old;
        local_flush_tlb();
        current->mm->mmap->vm_start -= PAGE_SIZE;
-       if (wp_works_ok < 0) {
-               wp_works_ok = 0;
+       if (boot_cpu_data.wp_works_ok < 0) {
+               boot_cpu_data.wp_works_ok = 0;
                printk("No.\n");
 #ifndef CONFIG_M386
                panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
 #endif
        } else
-               printk("Ok.\n");
+               printk(".\n");
 }
 
 __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
@@ -377,7 +365,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
                datapages << (PAGE_SHIFT-10),
                initpages << (PAGE_SHIFT-10));
 
-       if (wp_works_ok < 0)
+       if (boot_cpu_data.wp_works_ok < 0)
                test_wp_bit();
 }
 
index 9f69bb517944eae1c03de53e7b2bc2b88ab8b724..dfa5d9cdf86a87ba8f7e0d1e90ba9dc9ed6ac8da 100644 (file)
@@ -3295,8 +3295,8 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                return -EINVAL;
 
        /* permission checks */
-       if (((cmd & 0x80) && !suser()) ||
-            ((cmd & 0x40) && !IOCTL_ALLOWED))
+       if (((cmd & 0x40) && !IOCTL_ALLOWED) ||
+           ((cmd & 0x80) && !suser()))
                return -EPERM;
 
        /* copyin */
index 5e178b6cd1faf364ed50224b2b3155beb70633fe..67221e10d8181b827ea514b4f0b38ec9cbf51c27 100644 (file)
@@ -467,7 +467,22 @@ static void idedisk_pre_reset (ide_drive_t *drive)
                drive->special.b.set_multmode = 1;
 }
 
+static int proc_idedisk_read_cache
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       char            *out = page;
+       int             len;
+
+       if (drive->id)
+               len = sprintf(out,"%i\n", drive->id->buf_size / 2);
+       else
+               len = sprintf(out,"(none)\n");
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
 static ide_proc_entry_t idedisk_proc[] = {
+       { "cache", proc_idedisk_read_cache, NULL },
        { "geometry", proc_ide_read_geometry, NULL },
        { NULL, NULL, NULL }
 };
index 5572a07ba6f98196e421450ee1413f5bdb9b47fb..8e6d47d72e393fd7f62d086cafb24f678ad3dd4d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-floppy.c    Version 0.8             Feb  21, 1997
+ * linux/drivers/block/ide-floppy.c    Version 0.8             Dec   7, 1997
  *
  * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
  */
@@ -1364,6 +1364,11 @@ static int idefloppy_cleanup (ide_drive_t *drive)
        return 0;
 }
 
+static ide_proc_entry_t idefloppy_proc[] = {
+       { "geometry", proc_ide_read_geometry, NULL },
+       { NULL, NULL, NULL }
+};
+
 int idefloppy_init (void);
 static ide_module_t idefloppy_module = {
        IDE_DRIVER_MODULE,
@@ -1391,7 +1396,7 @@ static ide_driver_t idefloppy_driver = {
        NULL,                   /* pre_reset */
        idefloppy_capacity,     /* capacity */
        NULL,                   /* special */
-       NULL                    /* proc */
+       idefloppy_proc          /* proc */
 };
 
 /*
index 8e9336037bbfd1d212e7352d0a44227454041ced..d8280959edc2990ebe6d6ba01f1d322bb6802458 100644 (file)
@@ -582,7 +582,7 @@ static void init_gendisk (ide_hwif_t *hwif)
 {
        struct gendisk *gd, **gdp;
        unsigned int unit, units, minors;
-       int *bs, *max_sect;
+       int *bs, *max_sect, *max_ra;
 
        /* figure out maximum drive number on the interface */
        for (units = MAX_DRIVES; units > 0; --units) {
@@ -595,15 +595,18 @@ static void init_gendisk (ide_hwif_t *hwif)
        gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
        bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
        max_sect  = kmalloc (minors*sizeof(int), GFP_KERNEL);
+       max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
 
        memset(gd->part, 0, minors * sizeof(struct hd_struct));
 
        /* cdroms and msdos f/s are examples of non-1024 blocksizes */
        blksize_size[hwif->major] = bs;
        max_sectors[hwif->major] = max_sect;
+       max_readahead[hwif->major] = max_ra;
        for (unit = 0; unit < minors; ++unit) {
                *bs++ = BLOCK_SIZE;
-               *max_sect++ = 244;
+               *max_sect++ = MAX_SECTORS;
+               *max_ra++ = MAX_READAHEAD;
        }
 
        for (unit = 0; unit < units; ++unit)
@@ -674,6 +677,10 @@ static int hwif_init (ide_hwif_t *hwif)
        return hwif->present;
 }
 
+
+int ideprobe_init(void);
+
+
 static ide_module_t ideprobe_module = {
        IDE_PROBE_MODULE,
        ideprobe_init,
index 55ad225215c10ac53d20ca330cb9aae4ed47e135..859581bf389293076a6f77a0e7b6e7a97c4d3623 100644 (file)
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-/*
- * Standard exit stuff:
- */
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
-{                                      \
-       len -= off;                     \
-       if (len < count) {              \
-               *eof = 1;               \
-               if (len <= 0)           \
-                       return 0;       \
-       } else                          \
-               len = count;            \
-       *start = page + off;            \
-       return len;                     \
-}
-
-
 #ifdef CONFIG_PCI
 
 static int ide_getxdigit(char c)
@@ -129,8 +112,9 @@ static int proc_ide_write_pci
                        cli();  /* ensure all PCI writes are done together */
                        while (((ide_hwgroup_t *)(hwif->hwgroup))->active || (hwif->mate && ((ide_hwgroup_t *)(hwif->mate->hwgroup))->active)) {
                                sti();
-                               if (0 < (signed long)(timeout - jiffies)) {
+                               if (0 < (signed long)(jiffies - timeout)) {
                                        printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name);
+                                       restore_flags(flags);
                                        return -EBUSY;
                                }
                                cli();
@@ -311,6 +295,8 @@ static int proc_ide_read_settings
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
        ide_drive_t     *drive = (ide_drive_t *) data;
+       int             major = HWIF(drive)->major;
+       int             minor = drive->select.b.unit << PARTN_BITS;
        char            *out = page;
        int             len;
 
@@ -321,6 +307,9 @@ static int proc_ide_read_settings
        out += sprintf(out,"nowerr       %i\n", drive->bad_wstat == BAD_R_STAT);
        out += sprintf(out,"keepsettings %i\n", drive->keep_settings);
        out += sprintf(out,"nice         %i/%i/%i\n", drive->nice0, drive->nice1, drive->nice2);
+       out += sprintf(out,"dsc_overlap  %i\n", drive->dsc_overlap);
+       out += sprintf(out,"max_sectors  %i\n", max_sectors[major][minor]);
+       out += sprintf(out,"readahead    %i\n", max_readahead[major][minor] / 1024);
        len = out - page;
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
@@ -329,9 +318,13 @@ int proc_ide_read_capacity
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
        ide_drive_t     *drive = (ide_drive_t *) data;
+       ide_driver_t    *driver = (ide_driver_t *) drive->driver;
        int             len;
 
-       len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+       if (!driver)
+           len = sprintf(page, "(none)\n");
+        else
+           len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -399,7 +392,6 @@ static int proc_ide_read_media
 
 
 static ide_proc_entry_t generic_drive_entries[] = {
-       { "capacity", proc_ide_read_capacity, NULL },
        { "driver", proc_ide_read_driver, NULL },
        { "identify", proc_ide_read_identify, NULL },
        { "media", proc_ide_read_media, NULL },
index a30fc9a58d960d15bd5f35682ca77a7b8c1d408b..3083debfda8d1f6084436411d2f116066837f0dd 100644 (file)
@@ -3321,6 +3321,9 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
        unsigned short mask,i;
 #endif /* IDETAPE_DEBUG_LOG */
 
+       if (!id)
+               return 0;
+
        *((unsigned short *) &gcw) = id->config;
 
 #if IDETAPE_DEBUG_LOG
@@ -3421,10 +3424,7 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
                printk (KERN_ERR "ide-tape: Device type is not set to tape\n");
        else if (!gcw.removable)
                printk (KERN_ERR "ide-tape: The removable flag is not set\n");
-       else if (gcw.drq_type != 2) {
-               printk (KERN_ERR "ide-tape: Sorry, DRQ types other than Accelerated DRQ\n");
-               printk (KERN_ERR "ide-tape: are still not supported by the driver\n");
-       } else if (gcw.packet_size != 0) {
+       else if (gcw.packet_size != 0) {
                printk (KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
                if (gcw.packet_size == 1)
                        printk (KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
@@ -3605,6 +3605,88 @@ static int idetape_cleanup (ide_drive_t *drive)
        return 0;
 }
 
+static int proc_idetape_read_buffer
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       idetape_tape_t  *tape = drive->driver_data;
+       char            *out = page;
+       int             len;
+
+       len = sprintf(out,"%d\n", tape->capabilities.buffer_size / 2);
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idetape_read_name
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       idetape_tape_t  *tape = drive->driver_data;
+       char            *out = page;
+       int             len;
+
+       len = sprintf(out,"%s\n", tape->name);
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idetape_read_pipeline
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       idetape_tape_t  *tape = drive->driver_data;
+       char            *out = page;
+       int             len;
+
+       len = sprintf(out,"%d\n", tape->max_stages * tape->stage_size / 1024);
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idetape_read_speed
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       idetape_tape_t  *tape = drive->driver_data;
+       char            *out = page;
+       int             len;
+
+       len = sprintf(out,"%d\n", tape->capabilities.speed);
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idetape_read_stage
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       idetape_tape_t  *tape = drive->driver_data;
+       char            *out = page;
+       int             len;
+
+       len = sprintf(out,"%d\n", tape->stage_size / 1024);
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idetape_read_tdsc
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       idetape_tape_t  *tape = drive->driver_data;
+       char            *out = page;
+       int             len;
+
+       len = sprintf(out,"%lu\n", tape->best_dsc_rw_frequency * 1000 / HZ);
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static ide_proc_entry_t idetape_proc[] = {
+       { "buffer", proc_idetape_read_buffer, NULL },
+       { "name", proc_idetape_read_name, NULL },
+       { "pipeline", proc_idetape_read_pipeline, NULL },
+       { "speed", proc_idetape_read_speed, NULL },
+       { "stage", proc_idetape_read_stage, NULL },
+       { "tdsc", proc_idetape_read_tdsc, NULL },
+       { NULL, NULL, NULL }
+};
+
 int idetape_init (void);
 
 static ide_module_t idetape_module = {
@@ -3633,7 +3715,7 @@ static ide_driver_t idetape_driver = {
        idetape_pre_reset,      /* pre_reset */
        NULL,                   /* capacity */
        NULL,                   /* special */
-       NULL                    /* proc */
+       idetape_proc            /* proc */
 };
 
 /*
index 3b9a172837a103a30cb09af8b9ab8dc7580e57cf..9a5bbc3a31d8707c54ef5d3198d90f8b7a216029 100644 (file)
@@ -1640,6 +1640,7 @@ void ide_unregister (unsigned int index)
        unregister_blkdev(hwif->major, hwif->name);
        kfree(blksize_size[hwif->major]);
        kfree(max_sectors[hwif->major]);
+       kfree(max_readahead[hwif->major]);
        blk_dev[hwif->major].request_fn = NULL;
        blk_dev[hwif->major].data = NULL;
        blk_dev[hwif->major].queue = NULL;
@@ -2598,6 +2599,11 @@ search:
        return NULL;
 }
 
+static ide_proc_entry_t generic_subdriver_entries[] = {
+       { "capacity", proc_ide_read_capacity, NULL },
+       { NULL, NULL, NULL }
+};
+
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
 {
        unsigned long flags;
@@ -2619,6 +2625,7 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
                drive->nice1 = 1;
        }
        drive->revalidate = 1;
+       ide_add_proc_entries(drive, generic_subdriver_entries);
        ide_add_proc_entries(drive, driver->proc);
        return 0;
 }
@@ -2634,6 +2641,7 @@ int ide_unregister_subdriver (ide_drive_t *drive)
                return 1;
        }
        ide_remove_proc_entries(drive, DRIVER(drive)->proc);
+       ide_remove_proc_entries(drive, generic_subdriver_entries);
        drive->driver = NULL;
        restore_flags(flags);
        return 0;
index 5bdae8e214be5069ec8f10148857c130cbacfa7b..5ea5dd2ac66fc0b18a8069321b3a1fdb47908f13 100644 (file)
@@ -373,8 +373,25 @@ typedef struct {
 void proc_ide_init(void);
 void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
 void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
+read_proc_t proc_ide_read_capacity;
 read_proc_t proc_ide_read_geometry;
 
+/*
+ * Standard exit stuff:
+ */
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
+{                                      \
+       len -= off;                     \
+       if (len < count) {              \
+               *eof = 1;               \
+               if (len <= 0)           \
+                       return 0;       \
+       } else                          \
+               len = count;            \
+       *start = page + off;            \
+       return len;                     \
+}
+
 /*
  * Subdrivers support.
  */
index f9d7907bd96f91a8760c9a93aa1b2e7d9af6ec4a..c852db6ff096fa99329cc6570a2fd079389a68f9 100644 (file)
@@ -95,7 +95,7 @@ int * max_sectors[MAX_BLKDEV] = { NULL, NULL, };
 static inline int get_max_sectors(kdev_t dev)
 {
        if (!max_sectors[MAJOR(dev)])
-               return 244;     /* 254? */
+               return MAX_SECTORS;
        return max_sectors[MAJOR(dev)][MINOR(dev)];
 }
 
@@ -684,6 +684,7 @@ __initfunc(int blk_dev_init(void))
                dev->plug.rq_status  = RQ_INACTIVE;
                dev->plug.cmd        = -1;
                dev->plug.next       = NULL;
+               dev->plug_tq.sync    = 0;
                dev->plug_tq.routine = &unplug_device;
                dev->plug_tq.data    = dev;
        }
index 6ce5c037d19e2fd1c3f8b00c96cd31537b45acaa..58ced412fc7d8ed42164f9caedaab11b1adb3a9a 100644 (file)
@@ -741,8 +741,8 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
        struct floppy_state *fs;
        int err;
 
-       if (((cmd & 0x80) && !suser())
-           || ((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))))
+       if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) ||
+           ((cmd & 0x80) && !suser()))
                return -EPERM;
 
        fs = &floppy_states[0];
index c51e02bb3606b91192c2bfe466a8668ff0609893..9654dff869163e05ee5df34fb5c712c705590ac3 100644 (file)
@@ -373,10 +373,9 @@ endif
 ifdef CONFIG_VT
   ifdef CONFIG_TGA_CONSOLE
   L_OBJS += tga.o
-  else
-   ifndef CONFIG_SUN_CONSOLE
-   L_OBJS += vga.o vesa_blank.o
-   endif
+  endif
+  ifdef CONFIG_VGA_CONSOLE
+  L_OBJS += vga.o vesa_blank.o
   endif
 endif
 
index c19db03401e434bfe196fec7affa72d79edad887..6a06654aedf4ff78dc738cadc9ccb10738c33bbc 100644 (file)
@@ -964,6 +964,13 @@ static int do_open(struct inode * inode, struct file * filp)
        as->event_tail = as->event_head = 0;
        as->suspends_pending = as->standbys_pending = 0;
        as->suspends_read = as->standbys_read = 0;
+       /*
+        * XXX - this is a tiny bit broken, when we consider BSD
+         * process accounting. If the device is opened by root, we
+        * instantly flag that we used superuser privs. Who knows,
+        * we might close the device immediately without doing a
+        * privileged operation -- cevans
+        */
        as->suser = suser();
        as->next = user_list;
        user_list = as;
index 4c1fa303c5a055dc078afaf406cb2bac4ddb499f..8128829ea27ae8afc0b55d57edc19665404b56f3 100644 (file)
@@ -378,7 +378,7 @@ static void bt848_set_size(struct bttv *btv)
                 */
                case 1: 
                        btwrite(BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT);
-                       btand(~0x10, BT848_CAP_CTL); // Dithering looks much better in this mode
+                       btand(~0x10, BT848_CAP_CTL);  /* Dithering looks much better in this mode */
                        break;
                case 2: 
                        btwrite(BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT);
@@ -721,7 +721,9 @@ static inline void bt848_sat_v(struct bttv *btv, ulong data)
  *     Cliprect -> risc table.
  *
  *     FIXME: This is generating wrong code when we have some kinds of
- *     rectangle lists. I don't currently understand why.
+ *     rectangle lists. If you generate overlapped rectangles then it
+ *     gets a bit confused. Since we add the frame buffer clip rectangles
+ *     we need to fix this. Better yet to rewrite this function.
  */
  
 static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count)
@@ -818,6 +820,11 @@ static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count)
                        while ((cur=cur->next));
                }
 
+               /*
+                *      Fixme - we have to handle overlapped rectangles
+                *      here, but the overlap might be partial
+                */
+                
                /* add rect to second (x-sorted) list if rect.y == y  */
                if ((cur=first.next)) 
                {
@@ -1068,7 +1075,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        /* Only channel 0 has a tuner */
                        if(v.tuner!=0 || lastchan)
                                return -EINVAL;
-                       if(v.mode!=VIDEO_MODE_PAL||v.mode!=VIDEO_MODE_NTSC)
+                       if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC)
                                return -EOPNOTSUPP;
                        btv->win.norm = v.mode;
                        bt848_set_size(btv);
@@ -1262,6 +1269,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        vp=btv->audio_dev;
                        vp.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE);
                        vp.flags|=VIDEO_AUDIO_MUTABLE;
+                       strcpy(vp.name,"TV");
+                       if(copy_to_user(&v,arg,sizeof(v)))
+                               return -EFAULT;
                        return 0;
                }
                case VIDIOCSAUDIO:
index 08d11b90146c0c64e31d3b2356bd70e5e85e17a7..dcd92525cb9280d2f04916f2c9edc94741af35f8 100644 (file)
@@ -129,7 +129,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
         * The surround logic should disable caching for the high device
         * addresses anyway, but right now this seems still needed.
         */
-       if (x86 > 3 && offset >= __pa(high_memory))
+       if (boot_cpu_data.x86 > 3 && offset >= __pa(high_memory))
                pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 #endif
 #ifdef __powerpc__
index a70763bf0c02d4408b58fb6090c16c57279d7a07..19429557608e16b44f11f19cadb01b2a74cdef69 100644 (file)
@@ -10,7 +10,7 @@
  *     Configuration Switches
  */
 
-#define KBD_REPORT_ERR                 /* Report keyboard errors */
+#undef KBD_REPORT_ERR                  /* Report keyboard errors */
 #define KBD_REPORT_UNKN                        /* Report unknown scan codes */
 #define KBD_REPORT_TIMEOUTS            /* Report keyboard timeouts */
 #undef KBD_IS_FOCUS_9000               /* We have the brain-damaged FOCUS-9000 keyboard */
@@ -87,7 +87,7 @@ extern unsigned char aux_device_present;
  *     Controller Mode Register Bits
  */
 
-#define KBD_MODE_KBD_INT       0x01    /* Keyboard data generage IRQ1 */
+#define KBD_MODE_KBD_INT       0x01    /* Keyboard data generate IRQ1 */
 #define KBD_MODE_MOUSE_INT     0x02    /* Mouse data generate IRQ12 */
 #define KBD_MODE_SYS           0x04    /* The system flag (?) */
 #define KBD_MODE_NO_KEYLOCK    0x08    /* The keylock doesn't affect the keyboard if set */
index 78682a35355dea9401db4f0af9a3047a3573935f..b0383154239a8a261c813ee474126fe5b7909fc0 100644 (file)
@@ -1045,9 +1045,15 @@ static void shutdown_mediavision(void)
  
 #ifdef MODULE
 
+MODULE_PARM(io_port,"i");
+MODULE_PARM(mem_base,"i");
+
 int init_module(void)
 {
        printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.01\n");
+       
+       data_port = io_port +1;
+       
        if(init_mediavision())
        {
                printk(KERN_INFO "Board not found.\n");
index 6b8a2f12b09a60998ac6a2f065acbef21ac42608..55d4b6c451cd8118e2f166885242c811a5d74668 100644 (file)
@@ -585,7 +585,7 @@ static void add_timer_randomness(struct random_bucket *r,
        begin_benchmark(&timer_benchmark);
 #endif
 #if defined (__i386__)
-       if (x86_capability & 16) {
+       if (boot_cpu_data.x86_capability & 16) {
                unsigned long low, high;
                __asm__(".byte 0x0f,0x31"
                        :"=a" (low), "=d" (high));
index 25396c3c1bd992831fe65974768d378a1bcc6cc9..83b10d4a264384146984106b2b855f0e40a22d8f 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  *
- *     $Id: sysrq.c,v 1.4 1997/07/17 11:54:15 mj Exp $
+ *     $Id: sysrq.c,v 1.7 1997/11/06 15:57:09 mj Exp $
  *
  *     Linux Magic System Request Key Hacks
  *
@@ -31,10 +31,6 @@ extern void reset_vc(unsigned int);
 extern int console_loglevel;
 extern struct vfsmount *vfsmntlist;
 
-#ifdef __sparc__
-extern void halt_now(void);
-#endif
-
 /* Send a signal to all user processes */
 
 static void send_sig_all(int sig, int even_init)
@@ -60,6 +56,9 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
 {
        int orig_log_level = console_loglevel;
 
+       if (!key)
+               return;
+
        console_loglevel = 7;
        printk(KERN_INFO "SysRq: ");
        switch (key) {
@@ -69,7 +68,7 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
                        printk("Keyboard mode set to XLATE\n");
                }
                break;
-       case 'a':                                           /* A -- SAK */
+       case 'k':                                           /* K -- SAK */
                printk("SAK\n");
                if (tty)
                        do_SAK(tty);
@@ -79,12 +78,6 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
                printk("Resetting\n");
                machine_restart(NULL);
                break;
-#ifdef __sparc__
-       case 'h':                                           /* H -- halt immediately */
-               printk("Halting\n");
-               halt_now();
-               break;
-#endif
 #ifdef CONFIG_APM
        case 'o':                                           /* O -- power off */
                printk("Power off\n");
@@ -123,7 +116,7 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
                send_sig_all(SIGTERM, 0);
                orig_log_level = 8;                         /* We probably have killed syslogd */
                break;
-       case 'k':                                           /* K -- kill all user processes */
+       case 'i':                                           /* I -- kill all user processes */
                printk("Kill All Tasks\n");
                send_sig_all(SIGKILL, 0);
                orig_log_level = 8;
@@ -134,14 +127,16 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
                orig_log_level = 8;
                break;
        default:                                            /* Unknown: help */
-               printk("unRaw sAk Boot "
-#ifdef __sparc__
-                      "Halt "
-#endif
+               if (kbd)
+                       printk("unRaw ");
+               if (tty)
+                       printk("saK ");
+               printk("Boot "
 #ifdef CONFIG_APM
                       "Off "
 #endif
-                      "Sync Unmount showPc showTasks showMem loglevel0-8 tErm Kill killalL\n");
+                      "Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n");
+               /* Don't use 'A' as it's handled specially on the Sparc */
        }
 
        console_loglevel = orig_log_level;
index d824294ec53c243d3e10295daadb7e0b85d50eb3..4fe1676f379a7244d859f6d067336e6197ab2147 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/console.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -446,14 +447,21 @@ void set_vesa_blanking(const unsigned long arg)
 
 /*
  *     See if we have a TGA card.
+ *     Just a placeholder at the moment, because of the strange
+ *     way the TGA card is initialized. This has to be enabled when
+ *     the kernel initializes PCI devices before the console.
  */
-__initfunc(int con_is_present())
+__initfunc(int con_is_present(void))
 {
+#if 0
+       unsigned char pci_bus, pci_devfn;
        int status;
 
        status = pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
                                      0, &pci_bus, &pci_devfn);
        return (status == PCIBIOS_DEVICE_NOT_FOUND) ? 0 : 1;
+#endif
+       return 1;
 }
 
 /*
index 36af5fdcc2da41365131e6850711f8e0899ca3fa..576cd2ae30dc908609b7f29dc5b29136d4641da4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     Industrial Computer Source WDT500/501 driver for Linux 2.1.x
  *
- *     (c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
+ *     (c) Copyright 1996-1997 Alan Cox <alan@cymru.net>, All Rights Reserved.
  *                             http://www.cymru.net
  *
  *     This program is free software; you can redistribute it and/or
@@ -15,7 +15,7 @@
  *
  *     (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
- *     Release 0.06.
+ *     Release 0.07.
  *
  *     Fixes
  *             Dave Gregorich  :       Modularisation and minor bugs
@@ -368,7 +368,7 @@ void cleanup_module(void)
 #ifdef CONFIG_WDT_501  
        misc_deregister(&temp_miscdev);
 #endif 
-       notifier_chain_unregister(&boot_notifier_list, &wdt_notifier);
+       notifier_chain_unregister(&reboot_notifier_list, &wdt_notifier);
        release_region(io,8);
        free_irq(irq, NULL);
 }
@@ -377,7 +377,7 @@ void cleanup_module(void)
 
 __initfunc(int wdt_init(void))
 {
-       printk("WDT500/501-P driver at %X(Interrupt %d)\n", io,irq);
+       printk("WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq);
        if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL))
        {
                printk("IRQ %d is not free.\n", irq);
@@ -387,8 +387,8 @@ __initfunc(int wdt_init(void))
 #ifdef CONFIG_WDT_501  
        misc_register(&temp_miscdev);
 #endif 
-       request_region(io, 8, "wdt501");
-       notifier_chain_register(&boot_notifier_list, &wdt_notifier);
+       request_region(io, 8, "wdt501p");
+       notifier_chain_register(&reboot_notifier_list, &wdt_notifier);
        return 0;
 }
 
index 9fe98ee2db287ccd78e1735cd859839ef92ec644..3abbdddebcd113f84d17ced09eca623e5d186e1c 100644 (file)
@@ -136,7 +136,11 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
        bool 'Dayna firmware support' CONFIG_COPS_DAYNA
        bool 'Tangent firmware support' CONFIG_COPS_TANGENT
     fi
-    dep_tristate 'IP-over-DDP driver support' CONFIG_IPDDP $CONFIG_ATALK
+    tristate 'Appletalk-IP driver support' CONFIG_IPDDP
+    if [ "$CONFIG_IPDDP" != "n" ]; then
+       bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
+       bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
+    fi
   fi
 fi
 
@@ -156,8 +160,11 @@ if [ "$CONFIG_SLIP" != "n" ]; then
   bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
 fi
 
-tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
-tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
+if [ "$CONFIG_NET_RADIO" = "y" ]; then
+  tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
+  tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+fi
 
 bool 'Token Ring driver support' CONFIG_TR
 if [ "$CONFIG_TR" = "y" ]; then
index 0b470e2f3b03c543092e276bde079af60085ed83..1704b325d0b62a6fd478c7b054de838c9c907ad0 100644 (file)
@@ -502,7 +502,7 @@ static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
                return 0;
 
        case HDLCDRVCTL_SETMODE:
-               if (!suser() || dev->start)
+               if (dev->start || !suser())
                        return -EACCES;
                hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
                return baycom_setmode(bc, hi->data.modename);
index 9005356d3c99cb40a747f87815ded1641c17f582..b70e4efde90603e26a319348d50f28e0f5024aa4 100644 (file)
@@ -587,7 +587,7 @@ static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
                return 0;
 
        case HDLCDRVCTL_SETMODE:
-               if (!suser() || dev->start)
+               if (dev->start || !suser())
                        return -EACCES;
                hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
                return baycom_setmode(bc, hi->data.modename);
index e3d7ac998242ed51856ca91fcf3d2824235ac52c..f1024658d2aee5f6c7d7c180a117fa2ebd1e228e 100644 (file)
@@ -626,7 +626,7 @@ static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
                return 0;
 
        case HDLCDRVCTL_SETMODE:
-               if (!suser() || dev->start)
+               if (dev->start || !suser())
                        return -EACCES;
                hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
                return baycom_setmode(bc, hi->data.modename);
index 171aecfc77096927cc45e893440d19f40dd76fce..3423807aca54fead33e5d2eb59eb4b4430b030a3 100644 (file)
@@ -592,7 +592,7 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr,
                return 0;
 
        case HDLCDRVCTL_SETMODE:
-               if (!suser() || dev->start)
+               if (dev->start || !suser())
                        return -EACCES;
                hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
                return sethw(dev, sm, hi->data.modename);
index fa3072a6c838d6fa4aab8f48ceee7d8be9f00a8d..927ecea2eef9dd0dac81fca48e00439c743b8417 100644 (file)
@@ -1,9 +1,10 @@
 /*
- *     ipddp.c: IP-over-DDP driver for Linux
+ *     ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
+ *              Appletalk-IP to IP Decapsulation driver for Linux
  *
  *     Authors:
- *      - Original code by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- *     - Moved to driver by: Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
+ *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ *     - DDP-IP Decap by: Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
  *
  *     Derived from:
  *     - Almost all code already existed in net/appletalk/ddp.c I just
@@ -12,6 +13,8 @@
  *      - skeleton.c: A network driver outline for linux.
  *        Written 1993-94 by Donald Becker.
  *     - dummy.c: A dummy net driver. By Nick Holloway.
+ *     - MacGate: A user space Daemon for Appletalk-IP Decap for
+ *       Linux by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
  *
  *      Copyright 1993 United States Government as represented by the
  *      Director, National Security Agency.
@@ -21,7 +24,7 @@
  */
 
 static const char *version = 
-"ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
+       "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
 
 #include <linux/config.h>
 #ifdef MODULE
@@ -53,16 +56,24 @@ static const char *version =
 #include <linux/atalk.h>
 #include <linux/ip.h>
 #include <net/route.h>
+#include <linux/inet.h>
 
 #include "ipddp.h"             /* Our stuff */
 
+static struct ipddp_route *ipddp_route_list = NULL;
+
 /*
  *      The name of the card. Is used for messages and in the requests for
  *      io regions, irqs and dma channels
  */
-
 static const char *cardname = "ipddp";
 
+#ifdef CONFIG_IPDDP_ENCAP
+static int ipddp_mode = IPDDP_ENCAP;
+#else
+static int ipddp_mode = IPDDP_DECAP;
+#endif
+
 /* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
 #ifndef IPDDP_DEBUG
 #define IPDDP_DEBUG 1
@@ -73,8 +84,11 @@ static unsigned int ipddp_debug = IPDDP_DEBUG;
 static int ipddp_xmit(struct sk_buff *skb, struct device *dev);
 static struct net_device_stats *ipddp_get_stats(struct device *dev);
 static int ipddp_rebuild_header(struct sk_buff *skb);
-static int ipddp_header(struct sk_buff *skb, struct device *dev,
+static int ipddp_hard_header(struct sk_buff *skb, struct device *dev,
                 unsigned short type, void *daddr, void *saddr, unsigned len);
+static int ipddp_create(struct ipddp_route *new_rt);
+static int ipddp_delete(struct ipddp_route *rt);
+static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
 static int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 
 
@@ -103,6 +117,17 @@ int ipddp_init(struct device *dev)
        if (ipddp_debug && version_printed++ == 0)
                 printk("%s", version);
 
+       /* Let the user now what mode we are in */
+       if(ipddp_mode == IPDDP_ENCAP)
+               printk("%s: Appletalk-IP Encapsulation mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
+                       dev->name);
+       if(ipddp_mode == IPDDP_DECAP)
+               printk("%s: Appletalk-IP Decapsulation mode by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n", 
+                       dev->name);
+
+       /* Fill in the device structure with ethernet-generic values. */
+        ether_setup(dev);
+
        /* Initalize the device structure. */
         dev->hard_start_xmit = ipddp_xmit;
 
@@ -115,7 +140,7 @@ int ipddp_init(struct device *dev)
         dev->stop          = ipddp_close;
         dev->get_stats      = ipddp_get_stats;
         dev->do_ioctl       = ipddp_ioctl;
-       dev->hard_header    = ipddp_header;        /* see ip_output.c */
+       dev->hard_header    = ipddp_hard_header;        /* see ip_output.c */
        dev->rebuild_header = ipddp_rebuild_header;
 
         dev->type = ARPHRD_IPDDP;              /* IP over DDP tunnel */
@@ -129,9 +154,6 @@ int ipddp_init(struct device *dev)
          */
         dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
 
-       /* Fill in the device structure with ethernet-generic values. */
-       ether_setup(dev);
-
         return 0;
 }
 
@@ -141,16 +163,13 @@ int ipddp_init(struct device *dev)
 static int ipddp_xmit(struct sk_buff *skb, struct device *dev)
 {
         /* Retrieve the saved address hint */
-        struct at_addr *a=(struct at_addr *)skb->data;
+        struct at_addr *at = (struct at_addr *)skb->data;
         skb_pull(skb,4);
 
         ((struct net_device_stats *) dev->priv)->tx_packets++;
         ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
 
-       if(ipddp_debug>1)
-               printk("ipddp_xmit: Headroom %d\n",skb_headroom(skb));
-
-        if(aarp_send_ddp(skb->dev,skb,a,NULL) < 0)
+        if(aarp_send_ddp(skb->dev, skb, at, NULL) < 0)
                 dev_kfree_skb(skb,FREE_WRITE);
 
         return 0;
@@ -165,7 +184,8 @@ static struct net_device_stats *ipddp_get_stats(struct device *dev)
 }
 
 /*
- * Now the packet really wants to go out.
+ * Now the packet really wants to go out. On entry skb->data points to the
+ * ddpehdr we reserved earlier. skb->h.raw will be the higher level header.
  */
 static int ipddp_rebuild_header(struct sk_buff *skb)
 {
@@ -175,106 +195,171 @@ static int ipddp_rebuild_header(struct sk_buff *skb)
         struct ipddp_route *rt;
         struct at_addr *our_addr;
 
-        /*
-         * On entry skb->data points to the ddpehdr we reserved earlier.
-         * skb->h.raw will be the higher level header.
-         */
-
-        /*
-         * We created this earlier.
+       /*
+         * Find appropriate route to use, based only on IP number.
          */
-
-        ddp = (struct ddpehdr *) (skb->data+4);
-
-        /* find appropriate route */
-
-        for(rt=ipddp_route_head;rt;rt=rt->next)
+        for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
         {
                 if(rt->ip == paddr)
                         break;
         }
 
-        if(!rt) {
-                printk("ipddp unreachable dst %08lx\n",ntohl(paddr));
+        if(rt == NULL)
+        {
+                printk("%s: unreachable dst %s\n", cardname, in_ntoa(paddr));
                 return -ENETUNREACH;
         }
 
         our_addr = atalk_find_dev_addr(rt->dev);
 
-        /* fill in ddpehdr */
+       if(ipddp_mode == IPDDP_DECAP)
+               /* 
+                * Pull off the excess room that should not be there.
+                * This is the case for Localtalk, this may not hold
+                * true for Ethertalk, etc. 
+                */
+               skb_pull(skb, 31-(sizeof(struct ddpehdr)+1));
+
+       /* Create the Extended DDP header */
+       ddp = (struct ddpehdr *) (skb->data+4);
         ddp->deh_len = skb->len;
         ddp->deh_hops = 1;
         ddp->deh_pad = 0;
         ddp->deh_sum = 0;
-        ddp->deh_dnet = rt->at.s_net;   /* FIXME more hops?? */
-        ddp->deh_snet = our_addr->s_net;
+
+       /*
+         * For Localtalk we need aarp_send_ddp to strip the
+         * Ext DDP header and place a Shrt DDP header on it.
+         */
+        if(rt->dev->type == ARPHRD_LOCALTLK)
+        {
+                ddp->deh_dnet  = 0;   /* FIXME more hops?? */
+                ddp->deh_snet  = 0;
+        }
+        else
+        {
+                ddp->deh_dnet  = rt->at.s_net;   /* FIXME more hops?? */
+                ddp->deh_snet  = our_addr->s_net;
+        }
         ddp->deh_dnode = rt->at.s_node;
         ddp->deh_snode = our_addr->s_node;
         ddp->deh_dport = 72;
         ddp->deh_sport = 72;
 
-        *((__u8 *)(ddp+1)) = 22;        /* ddp type = IP */
+        *((__u8 *)(ddp+1)) = 22;                       /* ddp type = IP */
+        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));                /* fix up length field */
 
-        /* fix up length field */
-        *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));
-
-        /* set skb->dev to appropriate device */
-        skb->dev = rt->dev;
-
-        /* skb->raddr = (unsigned long) at */
+       /* Hide it at the start of the buffer, we pull it out in ipddp_xmit */
         at = rt->at;
-        /* Hide it at the start of the buffer */
         memcpy(skb->data,(void *)&at,sizeof(at));
-        skb->arp = 1;   /* so the actual device doesn't try to arp it... */
+
+       skb->dev = rt->dev;     /* set skb->dev to appropriate device */
+        skb->arp = 1;          /* so the actual device doesn't try to arp it... */
         skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
 
         return 0;
 }
 
-static int ipddp_header(struct sk_buff *skb, struct device *dev, 
+static int ipddp_hard_header(struct sk_buff *skb, struct device *dev, 
                unsigned short type, void *daddr, void *saddr, unsigned len)
 {
-       if(ipddp_debug>=2)
-               printk("%s: ipddp_header\n", cardname);
-
         /* Push down the header space and the type byte */
         skb_push(skb, sizeof(struct ddpehdr)+1+4);
 
         return 0;
 }
 
+/*
+ * Create a routing entry. We first verify that the
+ * record does not already exist. If it does we return -EEXIST
+ */
+static int ipddp_create(struct ipddp_route *new_rt)
+{
+        struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
+       struct ipddp_route *test;
+
+        if(rt == NULL)
+                return -ENOMEM;
+
+        rt->ip = new_rt->ip;
+        rt->at = new_rt->at;
+        rt->next = NULL;
+        rt->dev = atrtr_get_dev(&rt->at);
+        if(rt->dev == NULL)
+                return (-ENETUNREACH);
+
+       test = ipddp_find_route(rt);
+       if(test != NULL)
+               return (-EEXIST);
+       
+        rt->next = ipddp_route_list;
+        ipddp_route_list = rt;
+
+        return 0;
+}
+
+/*
+ * Delete a route, we only delete a FULL match.
+ * If route does not exist we return -ENOENT.
+ */
+static int ipddp_delete(struct ipddp_route *rt)
+{
+        struct ipddp_route **r = &ipddp_route_list;
+        struct ipddp_route *tmp;
+
+        while((tmp = *r) != NULL)
+        {
+                if(tmp->ip == rt->ip
+                        && tmp->at.s_net == rt->at.s_net
+                        && tmp->at.s_node == rt->at.s_node)
+                {
+                        *r = tmp->next;
+                        kfree_s(tmp, sizeof(struct ipddp_route));
+                        return 0;
+                }
+                r = &tmp->next;
+        }
+
+        return (-ENOENT);
+}
+
+/*
+ * Find a routing entry, we only return a FULL match
+ */
+static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
+{
+        struct ipddp_route *f;
+
+        for(f = ipddp_route_list; f != NULL; f = f->next)
+        {
+                if(f->ip == rt->ip
+                        && f->at.s_net == rt->at.s_net
+                        && f->at.s_node == rt->at.s_node)
+                        return (f);
+        }
+
+        return (NULL);
+}
+
 static int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
-        struct ipddp_route *urt = (struct ipddp_route *)ifr->ifr_data;
+        struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
 
         if(!suser())
                 return -EPERM;
 
-        /* for now we only have one route at a time */
-
         switch(cmd)
         {
-                case SIOCADDIPDDPRT:
-                        if(copy_from_user(&ipddp_route_test,urt,sizeof(struct ipddp_route)))
-                                return -EFAULT;
-                        ipddp_route_test.dev = atrtr_get_dev(&ipddp_route_test.at);
-                        if (dev==NULL)
-                                return -ENETUNREACH;
-                        ipddp_route_test.next = NULL;
-                        printk("%s: Added route through %s\n",
-                               ipddp_route_test.dev->name, cardname);
-                        ipddp_route_head = &ipddp_route_test;
-                        return 0;
+               case SIOCADDIPDDPRT:
+                        return (ipddp_create(rt));
 
                 case SIOCFINDIPDDPRT:
-                        if(copy_to_user(urt,&ipddp_route_test,sizeof(struct ipddp_route)))
+                        if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
                                 return -EFAULT;
                         return 0;
 
                 case SIOCDELIPDDPRT:
-                        ipddp_route_test.dev = NULL;
-                        ipddp_route_head = NULL;
-                        return 0;
+                        return (ipddp_delete(rt));
 
                 default:
                         return -EINVAL;
@@ -291,9 +376,17 @@ static struct device dev_ipddp=
                 0, 0, 0, NULL, ipddp_init
 };
 
+MODULE_PARM(ipddp_mode, "i");
+
 int init_module(void)
 {
-       if (register_netdev(&dev_ipddp) != 0)
+       int err;
+
+       err=dev_alloc_name(&dev_ipddp, "ipddp%d");
+        if(err < 0)
+                return err;
+
+       if(register_netdev(&dev_ipddp) != 0)
                 return -EIO;
 
        return 0;
index 6093adfec10180a9a9c0b9dbe3b5b51f43c93747..31178934bfe91365f3e6f1066390b769b289030c 100644 (file)
@@ -7,9 +7,10 @@
 
 #ifdef __KERNEL__
 
-#define SIOCADDIPDDPRT SIOCDEVPRIVATE
-#define SIOCDELIPDDPRT SIOCDEVPRIVATE+1
-#define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2
+#define SIOCADDIPDDPRT   (SIOCDEVPRIVATE)
+#define SIOCDELIPDDPRT   (SIOCDEVPRIVATE+1)
+#define SIOCFINDIPDDPRT  (SIOCDEVPRIVATE+2)
+#define SIOCPRINTIPDDPRT (SIOCDEVPRIVATE+3)
 
 struct ipddp_route
 {
@@ -20,8 +21,8 @@ struct ipddp_route
         struct ipddp_route *next;
 };
 
-static struct ipddp_route *ipddp_route_head;
-static struct ipddp_route ipddp_route_test;
+#define IPDDP_ENCAP    1
+#define IPDDP_DECAP    2
 
 #endif /* __KERNEL__ */
 #endif /* __LINUX_IPDDP_H */
index aafcdb12f6be38b08136f0931b42c35c3635dcce..2ab6b19ac98ca505ecbfa3cd4ef473b99913d748 100644 (file)
@@ -12,4 +12,8 @@
 L_OBJS   := pci.o
 L_TARGET := pci.a
 
+ifeq ($(CONFIG_PCI_OPTIMIZE),y)
+L_OBJS   += quirks.o
+endif
+
 include $(TOPDIR)/Rules.make
index 84dca452fa4f12bbeb42eacc7c342686a509b898..2848a4a82062e98d58573566bb930e64ce1cf7b6 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * $Id: pci.c,v 1.44 1997/09/03 05:08:22 richard Exp $
+ * $Id: pci.c,v 1.51 1997/12/03 06:18:11 davem Exp $
  *
  * PCI services that are built on top of the BIOS32 service.
  *
- * Copyright 1993, 1994, 1995 Drew Eckhardt, Frederic Potter,
- *     David Mosberger-Tang
+ * Copyright 1993, 1994, 1995, 1997 Drew Eckhardt, Frederic Potter,
+ *     David Mosberger-Tang, Martin Mares
  */
 #include <linux/config.h>
 #include <linux/ptrace.h>
 struct pci_bus pci_root;
 struct pci_dev *pci_devices = 0;
 
-/*
- * The bridge_id field is an offset of an item into the array
- * BRIDGE_MAPPING_TYPE. 0xff indicates that the device is not a PCI
- * bridge, or that we don't know for the moment how to configure it.
- * I'm trying to do my best so that the kernel stays small.  Different
- * chipset can have same optimization structure. i486 and pentium
- * chipsets from the same manufacturer usually have the same
- * structure.
- */
-#define DEVICE(vid,did,name) \
-  {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name), 0xff}
+#undef DEBUG
 
-#define BRIDGE(vid,did,name,bridge) \
-  {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name), (bridge)}
+#define DEVICE(vid,did,name) \
+  {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name)}
 
 /*
  * Sorted in ascending order by vendor and device.
@@ -87,7 +77,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( TSENG,          TSENG_ET6000,   "ET6000"),
        DEVICE( WEITEK,         WEITEK_P9000,   "P9000"),
        DEVICE( WEITEK,         WEITEK_P9100,   "P9100"),
-       BRIDGE( DEC,            DEC_BRD,        "DC21050",              0x00),
+       DEVICE( DEC,            DEC_BRD,        "DC21050"),
        DEVICE( DEC,            DEC_TULIP,      "DC21040"),
        DEVICE( DEC,            DEC_TGA,        "TGA"),
        DEVICE( DEC,            DEC_TULIP_FAST, "DC21140"),
@@ -180,10 +170,10 @@ struct pci_dev_info dev_info[] = {
        DEVICE( N9,             N9_I128,        "Imagine 128"),
        DEVICE( N9,             N9_I128_2,      "Imagine 128v2"),
        DEVICE( UMC,            UMC_UM8673F,    "UM8673F"),
-       BRIDGE( UMC,            UMC_UM8891A,    "UM8891A",              0x01),
+       DEVICE( UMC,            UMC_UM8891A,    "UM8891A"),
        DEVICE( UMC,            UMC_UM8886BF,   "UM8886BF"),
        DEVICE( UMC,            UMC_UM8886A,    "UM8886A"),
-       BRIDGE( UMC,            UMC_UM8881F,    "UM8881F",              0x02),
+       DEVICE( UMC,            UMC_UM8881F,    "UM8881F"),
        DEVICE( UMC,            UMC_UM8886F,    "UM8886F"),
        DEVICE( UMC,            UMC_UM9017F,    "UM9017F"),
        DEVICE( UMC,            UMC_UM8886N,    "UM8886N"),
@@ -206,7 +196,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( OLICOM,         OLICOM_OC6151,  "OC-6151/6152"),
        DEVICE( SUN,            SUN_EBUS,       "EBUS"),
        DEVICE( SUN,            SUN_HAPPYMEAL,  "Happy Meal"),
-       BRIDGE( SUN,            SUN_PBM,        "PCI Bus Module",       0x02),
+       DEVICE( SUN,            SUN_PBM,        "PCI Bus Module"),
        DEVICE( CMD,            CMD_640,        "640 (buggy)"),
        DEVICE( CMD,            CMD_643,        "643"),
        DEVICE( CMD,            CMD_646,        "646"),
@@ -382,10 +372,10 @@ struct pci_dev_info dev_info[] = {
        DEVICE( S3,             S3_ViRGE_DXGX,  "ViRGE/DX or /GX"),
        DEVICE( S3,             S3_ViRGE_GX2,   "ViRGE/GX2"),
        DEVICE( INTEL,          INTEL_82375,    "82375EB"),
-       BRIDGE( INTEL,          INTEL_82424,    "82424ZX Saturn",       0x00),
+       DEVICE( INTEL,          INTEL_82424,    "82424ZX Saturn"),
        DEVICE( INTEL,          INTEL_82378,    "82378IB"),
        DEVICE( INTEL,          INTEL_82430,    "82430ZX Aries"),
-       BRIDGE( INTEL,          INTEL_82434,    "82434LX Mercury/Neptune", 0x00),
+       DEVICE( INTEL,          INTEL_82434,    "82434LX Mercury/Neptune"),
        DEVICE( INTEL,          INTEL_82092AA_0,"82092AA PCMCIA bridge"),
        DEVICE( INTEL,          INTEL_82092AA_1,"82092AA EIDE"),
        DEVICE( INTEL,          INTEL_7116,     "SAA7116"),
@@ -436,81 +426,6 @@ struct pci_dev_info dev_info[] = {
 };
 
 
-#ifdef CONFIG_PCI_OPTIMIZE
-
-/*
- * An item of this structure has the following meaning:
- * for each optimization, the register address, the mask
- * and value to write to turn it on.
- * There are 5 optimizations for the moment:
- * Cache L2 write back best than write through
- * Posted Write for CPU to PCI enable
- * Posted Write for CPU to MEMORY enable
- * Posted Write for PCI to MEMORY enable
- * PCI Burst enable
- *
- * Half of the bios I've meet don't allow you to turn that on, and you
- * can gain more than 15% on graphic accesses using those
- * optimizations...
- */
-struct optimization_type {
-       const char      *type;
-       const char      *off;
-       const char      *on;
-} bridge_optimization[] = {
-       {"Cache L2",                    "write through",        "write back"},
-       {"CPU-PCI posted write",        "off",          "on"},
-       {"CPU-Memory posted write",     "off",          "on"},
-       {"PCI-Memory posted write",     "off",          "on"},
-       {"PCI burst",                   "off",          "on"}
-};
-
-#define NUM_OPTIMIZATIONS \
-       (sizeof(bridge_optimization) / sizeof(bridge_optimization[0]))
-
-struct bridge_mapping_type {
-       unsigned char   addr;   /* config space address */
-       unsigned char   mask;
-       unsigned char   value;
-} bridge_mapping[] = {
-       /*
-        * Intel Neptune/Mercury/Saturn:
-        *      If the internal cache is write back,
-        *      the L2 cache must be write through!
-        *      I've to check out how to control that
-        *      for the moment, we won't touch the cache
-        */
-       {0x0    ,0x02   ,0x02   },
-       {0x53   ,0x02   ,0x02   },
-       {0x53   ,0x01   ,0x01   },
-       {0x54   ,0x01   ,0x01   },
-       {0x54   ,0x02   ,0x02   },
-
-       /*
-        * UMC 8891A Pentium chipset:
-        *      Why did you think UMC was cheaper ??
-        */
-       {0x50   ,0x10   ,0x00   },
-       {0x51   ,0x40   ,0x40   },
-       {0x0    ,0x0    ,0x0    },
-       {0x0    ,0x0    ,0x0    },
-       {0x0    ,0x0    ,0x0    },
-
-       /*
-        * UMC UM8881F
-        *      This is a dummy entry for my tests.
-        *      I have this chipset and no docs....
-        */
-       {0x0    ,0x1    ,0x1    },
-       {0x0    ,0x2    ,0x0    },
-       {0x0    ,0x0    ,0x0    },
-       {0x0    ,0x0    ,0x0    },
-       {0x0    ,0x0    ,0x0    }
-};
-
-#endif /* CONFIG_PCI_OPTIMIZE */
-
-
 /*
  * device_info[] is sorted so we can use binary search
  */
@@ -783,52 +698,6 @@ const char *pcibios_strerror(int error)
 }
 
 
-/*
- * Turn on/off PCI bridge optimization. This should allow benchmarking.
- */
-__initfunc(static void burst_bridge(unsigned char bus, unsigned char devfn,
-                                   unsigned char pos, int turn_on))
-{
-#ifdef CONFIG_PCI_OPTIMIZE
-       struct bridge_mapping_type *bmap;
-       unsigned char val;
-       int i;
-
-       pos *= NUM_OPTIMIZATIONS;
-       printk("PCI bridge optimization.\n");
-       for (i = 0; i < NUM_OPTIMIZATIONS; i++) {
-               printk("    %s: ", bridge_optimization[i].type);
-               bmap = &bridge_mapping[pos + i];
-               if (!bmap->addr) {
-                       printk("Not supported.");
-               } else {
-                       pcibios_read_config_byte(bus, devfn, bmap->addr, &val);
-                       if ((val & bmap->mask) == bmap->value) {
-                               printk("%s.", bridge_optimization[i].on);
-                               if (!turn_on) {
-                                       pcibios_write_config_byte(bus, devfn,
-                                                                 bmap->addr,
-                                                                 (val | bmap->mask)
-                                                                 - bmap->value);
-                                       printk("Changed!  Now %s.", bridge_optimization[i].off);
-                               }
-                       } else {
-                               printk("%s.", bridge_optimization[i].off);
-                               if (turn_on) {
-                                       pcibios_write_config_byte(bus, devfn,
-                                                                 bmap->addr,
-                                                                 (val & (0xff - bmap->mask))
-                                                                 + bmap->value);
-                                       printk("Changed!  Now %s.", bridge_optimization[i].on);
-                               }
-                       }
-               }
-               printk("\n");
-       }
-#endif /* CONFIG_PCI_OPTIMIZE */
-}
-
-
 /*
  * Convert some of the configuration space registers of the device at
  * address (bus,devfn) into a string (possibly several lines each).
@@ -1010,42 +879,35 @@ __initfunc(static void *pci_malloc(long size, unsigned long *mem_startp))
 {
        void *mem;
 
-#ifdef DEBUG
-       printk("...pci_malloc(size=%ld,mem=%p)", size, (void *)*mem_startp);
-#endif
        mem = (void*) *mem_startp;
        *mem_startp += (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
        memset(mem, 0, size);
        return mem;
 }
 
-
 unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
 {
-       unsigned int devfn, l, max;
-       unsigned char cmd, tmp, irq, hdr_type = 0;
+       unsigned int devfn, l, max, class;
+       unsigned char cmd, irq, tmp, hdr_type = 0;
        struct pci_dev_info *info;
        struct pci_dev *dev;
        struct pci_bus *child;
        int reg;
 
 #ifdef DEBUG
-       printk("...pci_scan_bus(busno=%d,mem=%p)\n", bus->number,
-              (void *)*mem_startp);
+       printk("pci_scan_bus for bus %d\n", bus->number);
 #endif
 
        max = bus->secondary;
        for (devfn = 0; devfn < 0xff; ++devfn) {
                if (PCI_FUNC(devfn) == 0) {
-                       pcibios_read_config_byte(bus->number, devfn,
-                                                PCI_HEADER_TYPE, &hdr_type);
+                       pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type);
                } else if (!(hdr_type & 0x80)) {
                        /* not a multi-function device */
                        continue;
                }
 
-               pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID,
-                                         &l);
+               pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l);
                /* some broken boards return 0 if a slot is empty: */
                if (l == 0xffffffff || l == 0x00000000) {
                        hdr_type = 0;
@@ -1054,14 +916,6 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
 
                dev = pci_malloc(sizeof(*dev), mem_startp);
                dev->bus = bus;
-               /*
-                * Put it into the simple chain of devices on this
-                * bus.  It is used to find devices once everything is
-                * set up.
-                */
-               dev->next = pci_devices;
-               pci_devices = dev;
-
                dev->devfn  = devfn;
                dev->vendor = l & 0xffff;
                dev->device = (l >> 16) & 0xffff;
@@ -1075,47 +929,62 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
                if (!info) {
                        printk("PCI: Warning: Unknown PCI device (%x:%x).  Please read include/linux/pci.h\n",
                                dev->vendor, dev->device);
-               } else {
-                       /* Some BIOS' are lazy. Let's do their job: */
-                       if (info->bridge_type != 0xff) {
-                               burst_bridge(bus->number, devfn,
-                                            info->bridge_type, 1);
-                       }
                }
 
                /* non-destructively determine if device can be a master: */
-               pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND,
-                                        &cmd);
-               pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND,
-                                         cmd | PCI_COMMAND_MASTER);
-               pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND,
-                                        &tmp);
+               pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd);
+               pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+               pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp);
                dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
-               pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND,
-                                         cmd);
+               pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd);
+
+               pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class);
+               class >>= 8;                                /* upper 3 bytes */
+               dev->class = class;
+
+               switch (hdr_type & 0x7f) {                  /* header type */
+               case 0:                                     /* standard header */
+                       if (class >> 8 == PCI_CLASS_BRIDGE_PCI)
+                               goto bad;
+                       /* read irq level (may be changed during pcibios_fixup()): */
+                       pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq);
+                       dev->irq = irq;
+                       /*
+                        * read base address registers, again pcibios_fixup() can
+                        * tweak these
+                        */
+                       for (reg = 0; reg < 6; reg++) {
+                               pcibios_read_config_dword(bus->number, devfn, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
+                               dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
+                       }
+                       break;
+               case 1:                                     /* bridge header */
+                       if (class >> 8 != PCI_CLASS_BRIDGE_PCI)
+                               goto bad;
+                       for (reg = 0; reg < 2; reg++) {
+                               pcibios_read_config_dword(bus->number, devfn, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
+                               dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
+                       }
+                       break;
+               default:                                    /* unknown header */
+               bad:
+                       printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
+                              bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
+                       continue;
+               }
 
-               /* read irq level (may be changed during pcibios_fixup()): */
-               pcibios_read_config_byte(bus->number, devfn,
-                                        PCI_INTERRUPT_LINE, &irq);
-               dev->irq = irq;
+#ifdef DEBUG
+               printk("PCI: %02x:%02x [%04x/%04x]\n",
+                      bus->number, dev->devfn, dev->vendor, dev->device);
+#endif
 
-               /* read base address registers, again pcibios_fixup() can
-                * tweak these
+               /*
+                * Put it into the global PCI device chain. It's used to
+                * find devices once everything is set up.
                 */
-               for (reg = 0; reg < 6; reg++) {
-                       pcibios_read_config_dword(bus->number, devfn,
-                                       PCI_BASE_ADDRESS_0 + (reg << 2), &l);
-                       if (l == 0xffffffff)
-                               dev->base_address[reg] = 0;
-                       else
-                               dev->base_address[reg] = l;
-               }
+               dev->next = pci_devices;
+               pci_devices = dev;
 
-               /* check to see if this device is a PCI-PCI bridge: */
-               pcibios_read_config_dword(bus->number, devfn,
-                                         PCI_CLASS_REVISION, &l);
-               l = l >> 8;                     /* upper 3 bytes */
-               dev->class = l;
                /*
                 * Now insert it into the list of devices held
                 * by the parent bus.
@@ -1123,7 +992,10 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
                dev->sibling = bus->devices;
                bus->devices = dev;
 
-               if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) {
+               /*
+                * If it's a bridge, scan the bus behind it.
+                */
+               if (class >> 8 == PCI_CLASS_BRIDGE_PCI) {
                        unsigned int buses;
                        unsigned short cr;
 
@@ -1131,7 +1003,7 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
                         * Insert it into the tree of buses.
                         */
                        child = pci_malloc(sizeof(*child), mem_startp);
-                       child->next   = bus->children;
+                       child->next = bus->children;
                        bus->children = child;
                        child->self = dev;
                        child->parent = bus;
@@ -1147,20 +1019,16 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
                         * Clear all status bits and turn off memory,
                         * I/O and master enables.
                         */
-                       pcibios_read_config_word(bus->number, devfn,
-                                                 PCI_COMMAND, &cr);
-                       pcibios_write_config_word(bus->number, devfn,
-                                                 PCI_COMMAND, 0x0000);
-                       pcibios_write_config_word(bus->number, devfn,
-                                                 PCI_STATUS, 0xffff);
+                       pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
+                       pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
+                       pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
                        /*
                         * Read the existing primary/secondary/subordinate bus
                         * number configuration to determine if the PCI bridge
                         * has already been configured by the system.  If so,
                         * do not modify the configuration, merely note it.
                         */
-                       pcibios_read_config_dword(bus->number, devfn, 0x18,
-                                                 &buses);
+                       pcibios_read_config_dword(bus->number, devfn, 0x18, &buses);
                        if ((buses & 0xFFFFFF) != 0)
                          {
                            child->primary = buses & 0xFF;
@@ -1179,8 +1047,7 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
                              (((unsigned int)(child->primary)     <<  0) |
                               ((unsigned int)(child->secondary)   <<  8) |
                               ((unsigned int)(child->subordinate) << 16));
-                           pcibios_write_config_dword(bus->number, devfn, 0x18,
-                                                      buses);
+                           pcibios_write_config_dword(bus->number, devfn, 0x18, buses);
                            /*
                             * Now we can scan all subordinate buses:
                             */
@@ -1192,11 +1059,9 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
                            child->subordinate = max;
                            buses = (buses & 0xff00ffff)
                              | ((unsigned int)(child->subordinate) << 16);
-                           pcibios_write_config_dword(bus->number, devfn, 0x18,
-                                                      buses);
+                           pcibios_write_config_dword(bus->number, devfn, 0x18, buses);
                          }
-                       pcibios_write_config_word(bus->number, devfn,
-                                                 PCI_COMMAND, cr);
+                       pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
                }
        }
        /*
@@ -1206,6 +1071,9 @@ unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
         *
         * Return how far we've got finding sub-buses.
         */
+#ifdef DEBUG
+       printk("PCI: pci_scan_bus returning with max=%02x\n", max);
+#endif
        return max;
 }
 
@@ -1236,5 +1104,10 @@ __initfunc(unsigned long pci_init (unsigned long mem_start, unsigned long mem_en
                }
        }
 #endif
+
+#ifdef CONFIG_PCI_OPTIMIZE
+       pci_quirks_init();
+#endif
+
        return mem_start;
 }
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
new file mode 100644 (file)
index 0000000..eb51794
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * $Id: quirks.c,v 1.2 1997/09/20 21:43:34 davem Exp $
+ *
+ * PCI Chipset-Specific Quirks
+ *
+ * Extracted from pci.c and rewritten by Martin Mares
+ *
+ * This is the right place for all special fixups for on-board
+ * devices not depending on system architecture -- for example
+ * bus bridges. The only thing implemented in this release is
+ * the bridge optimization, but others might appear later.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#undef DEBUG
+
+/*
+ *     The PCI Bridge Optimization -- Some BIOS'es are too lazy
+ *     and are unable to turn on several features which can burst
+ *     system performance.
+ */
+
+/*
+ * An item of this structure has the following meaning:
+ * for each optimization, the register address, the mask
+ * and value to write to turn it on.
+ */
+struct optimization_type {
+       const char      *type;
+       const char      *off;
+       const char      *on;
+} bridge_optimization[] __initdata = {
+       {"Cache L2",                    "write through",        "write back"},
+       {"CPU-PCI posted write",        "off",                  "on"},
+       {"CPU-Memory posted write",     "off",                  "on"},
+       {"PCI-Memory posted write",     "off",                  "on"},
+       {"PCI burst",                   "off",                  "on"}
+};
+
+#define NUM_OPTIMIZATIONS \
+       (sizeof(bridge_optimization) / sizeof(bridge_optimization[0]))
+
+struct bridge_mapping_type {
+       unsigned char   addr;   /* config space address */
+       unsigned char   mask;
+       unsigned char   value;
+} bridge_mapping[] = {
+       /*
+        * Intel Neptune/Mercury/Saturn:
+        *      If the internal cache is write back,
+        *      the L2 cache must be write through!
+        *      I've to check out how to control that
+        *      for the moment, we won't touch the cache
+        */
+       {0x0    ,0x02   ,0x02   },
+       {0x53   ,0x02   ,0x02   },
+       {0x53   ,0x01   ,0x01   },
+       {0x54   ,0x01   ,0x01   },
+       {0x54   ,0x02   ,0x02   },
+
+       /*
+        * UMC 8891A Pentium chipset:
+        *      Why did you think UMC was cheaper ??
+        */
+       {0x50   ,0x10   ,0x00   },
+       {0x51   ,0x40   ,0x40   },
+       {0x0    ,0x0    ,0x0    },
+       {0x0    ,0x0    ,0x0    },
+       {0x0    ,0x0    ,0x0    },
+};
+
+__initfunc(static void quirk_bridge(struct pci_dev *dev, int pos))
+{
+       struct bridge_mapping_type *bmap;
+       unsigned char val;
+       int i;
+
+       pos *= NUM_OPTIMIZATIONS;
+       for (i = 0; i < NUM_OPTIMIZATIONS; i++) {
+               printk("    %s: ", bridge_optimization[i].type);
+               bmap = &bridge_mapping[pos + i];
+               if (!bmap->addr) {
+                       printk("Not supported.");
+               } else {
+                       pcibios_read_config_byte(dev->bus->number, dev->devfn, bmap->addr, &val);
+                       if ((val & bmap->mask) == bmap->value)
+                               printk("%s.", bridge_optimization[i].on);
+                       else {
+                               printk("%s.", bridge_optimization[i].off);
+                               pcibios_write_config_byte(dev->bus->number, dev->devfn,
+                                                         bmap->addr,
+                                                         (val & (0xff - bmap->mask))
+                                                         + bmap->value);
+                               printk("Changed!  Now %s.", bridge_optimization[i].on);
+                       }
+               }
+               printk("\n");
+       }
+}
+
+/*
+ * Table of quirk handler functions
+ */
+
+#define Q_BRIDGE 0
+
+struct quirk_type {
+       void (*handler)(struct pci_dev *, int);
+       char *name;
+};
+
+static struct quirk_type quirk_types[] __initdata = {
+       { quirk_bridge,         "Bridge optimization" },
+};
+
+/*
+ * Mapping from PCI vendor/device ID pairs to quirk function types and arguments
+ */
+
+struct quirk_info {
+       unsigned short vendor, device;
+       unsigned short quirk, arg;
+};
+
+static struct quirk_info quirk_list[] __initdata = {
+       { PCI_VENDOR_ID_DEC,    PCI_DEVICE_ID_DEC_BRD,          Q_BRIDGE,       0x00 },
+       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8891A,      Q_BRIDGE,       0x01 },
+       { PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82424,      Q_BRIDGE,       0x00 },
+       { PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82434,      Q_BRIDGE,       0x00 }
+};
+
+__initfunc(void pci_quirks_init(void))
+{
+       struct pci_dev *d;
+       int i;
+
+#ifdef DEBUG
+       printk("PCI: pci_quirks_init\n");
+#endif
+       for(d=pci_devices; d; d=d->next) {
+               for(i=0; i<sizeof(quirk_list)/sizeof(quirk_list[0]); i++) {
+                       struct quirk_info *q = quirk_list + i;
+                       if (q->vendor == d->vendor && q->device == d->device) {
+                               struct quirk_type *t = quirk_types + q->quirk;
+                               printk("PCI: %02x:%02x [%04x/%04x]: %s (%02x)\n",
+                                      d->bus->number, d->devfn, d->vendor, d->device,
+                                      t->name, q->arg);
+                               t->handler(d, q->arg);
+                       }
+               }
+       }
+}
index cb0071e9d76ff474767183246e6c4c35630def34..994577ab059fc738cc520df681ea4da8a9fa09fd 100644 (file)
@@ -66,66 +66,22 @@ extern int NCR53c7xx_release(struct Scsi_Host *);
 #define NCR53c7xx_release NULL
 #endif
 
-#ifdef LINUX_1_2
-#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
-       NULL, /* info */ NULL, /* command, deprecated */ NULL,          \
-       NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,      \
-       NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
-       /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3,          \
-       /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
-#else
-#define NCR53c7xx {NULL, NULL, NULL, NULL, \
-        "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
-        NULL, /* info */ NULL, /* command, deprecated */ NULL,         \
-       NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,      \
-       NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
-       /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3,          \
-       /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
-#endif
+#define NCR53c7xx {                                    \
+          name:           "NCR53c{7,8}xx (rel 17)",    \
+         detect:         NCR53c7xx_detect,             \
+         queuecommand:   NCR53c7xx_queue_command,      \
+         abort:          NCR53c7xx_abort,              \
+         reset:          NCR53c7xx_reset,              \
+         bios_param:     scsicam_bios_param,           \
+         can_queue:      24,                           \
+         this_id:        7,                            \
+         sg_tablesize:   127,                          \
+         cmd_per_lun:    3,                            \
+         use_clustering: DISABLE_CLUSTERING} 
 
 #endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
 #ifndef HOSTS_C
-#ifdef LINUX_1_2
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
- * make the kernel segment mapped at 0, we need to do translation
- * on the i386 as well)
- */
-extern inline unsigned long virt_to_phys(volatile void * address)
-{       
-       return (unsigned long) address;
-}       
-
-extern inline void * phys_to_virt(unsigned long address)
-{
-       return (void *) address;      
-}
-
-/*
- * IO bus memory addresses are also 1:1 with the physical address
- */
-#define virt_to_bus virt_to_phys
-#define bus_to_virt phys_to_virt
-
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the x86 architecture, we just read/write the
- * memory location directly.
- */
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
-
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
-
-#define mb()
-
-#endif /* def LINUX_1_2 */
 
 /* Register addresses, ordered numerically */
 
index 0ea714166cdbc743fbb4a140ecffbbed154bddbc..f19065027b6ddd68a556c3b1e20d2a1ca90c40fe 100644 (file)
@@ -2543,52 +2543,54 @@ return(SCSI_ABORT_NOT_RUNNING);
 * Inputs : cmd -- which command within the command block was responsible for the reset
 * 
 * Returns : status (SCSI_ABORT_SUCCESS)
+* 
+* FIXME(eric) the reset_flags are ignored.
 **************************************************************************/
-int AM53C974_reset(Scsi_Cmnd *cmd)
+int AM53C974_reset(Scsi_Cmnd *cmd, unsigned int reset_flags)
 {
-AM53C974_local_declare();
-int                      i;
-struct Scsi_Host         *instance = cmd->host;
-struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata;
-AM53C974_setio(instance);
-
-cli();
-DEB(printk("AM53C974_reset called; "));
-
-printk("AM53C974_reset called\n");
-AM53C974_print(instance);
-AM53C974_keywait();
-
+    AM53C974_local_declare();
+    int                      i;
+    struct Scsi_Host         *instance = cmd->host;
+    struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata;
+    AM53C974_setio(instance);
+    
+    cli();
+    DEB(printk("AM53C974_reset called; "));
+    
+    printk("AM53C974_reset called\n");
+    AM53C974_print(instance);
+    AM53C974_keywait();
+    
 /* do hard reset */
-AM53C974_write_8(CMDREG, CMDREG_RDEV);
-AM53C974_write_8(CMDREG, CMDREG_NOP);
-hostdata->msgout[0] = NOP;
-for (i = 0; i < 8; i++) {
-    hostdata->busy[i] = 0;
-    hostdata->sync_per[i] = DEF_STP;
-    hostdata->sync_off[i] = 0;
-    hostdata->sync_neg[i] = 0; }
-hostdata->last_message[0] = NOP;
-hostdata->sel_cmd = NULL;
-hostdata->connected = NULL;
-hostdata->issue_queue = NULL;
-hostdata->disconnected_queue = NULL;
-hostdata->in_reset = 0;
-hostdata->aborted = 0;
-hostdata->selecting = 0;
-hostdata->disconnecting = 0;
-hostdata->dma_busy = 0;
-
+    AM53C974_write_8(CMDREG, CMDREG_RDEV);
+    AM53C974_write_8(CMDREG, CMDREG_NOP);
+    hostdata->msgout[0] = NOP;
+    for (i = 0; i < 8; i++) {
+       hostdata->busy[i] = 0;
+       hostdata->sync_per[i] = DEF_STP;
+       hostdata->sync_off[i] = 0;
+       hostdata->sync_neg[i] = 0; }
+    hostdata->last_message[0] = NOP;
+    hostdata->sel_cmd = NULL;
+    hostdata->connected = NULL;
+    hostdata->issue_queue = NULL;
+    hostdata->disconnected_queue = NULL;
+    hostdata->in_reset = 0;
+    hostdata->aborted = 0;
+    hostdata->selecting = 0;
+    hostdata->disconnecting = 0;
+    hostdata->dma_busy = 0;
+    
 /* reset bus */
-AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */
-AM53C974_write_8(CMDREG, CMDREG_RBUS);     /* reset SCSI bus */
-udelay(40);
-AM53C974_config_after_reset(instance);
-
-sti();
-cmd->result = DID_RESET << 16;
-cmd->scsi_done(cmd);
-return SCSI_ABORT_SUCCESS;
+    AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */
+    AM53C974_write_8(CMDREG, CMDREG_RBUS);     /* reset SCSI bus */
+    udelay(40);
+    AM53C974_config_after_reset(instance);
+    
+    sti();
+    cmd->result = DID_RESET << 16;
+    cmd->scsi_done(cmd);
+    return SCSI_ABORT_SUCCESS;
 }
 
 
index 4e187d993753cb5f9f99d7e4f8bb5f71bfe7696f..f4542c778aef55230231321a83ef2ac5517b2c08 100644 (file)
@@ -52,29 +52,22 @@ struct AM53C974_hostdata {
 
 extern struct proc_dir_entry proc_scsi_am53c974;
 
-#define AM53C974 { \
-    NULL,                              /* pointer to next in list                      */  \
-    NULL,                      /* struct module *module                        */  \
-    &proc_scsi_am53c974,        /* struct proc_dir_entry *proc_dir              */ \
-    NULL,                       /* int (*proc_info)(char *, char **, off_t, int, int, int); */ \
-    "AM53C974",                        /* name                                         */  \
-    AM53C974_detect,                   /* int (* detect)(struct SHT *)                 */  \
-    AM53C974_release,          /* int (*release)(struct Scsi_Host *)           */  \
-    AM53C974_info,                     /* const char *(* info)(struct Scsi_Host *)     */  \
-    AM53C974_command,                  /* int (* command)(Scsi_Cmnd *)                 */  \
-    AM53C974_queue_command,    /* int (* queuecommand)(Scsi_Cmnd *,                \
-                                           void (*done)(Scsi_Cmnd *))           */  \
-    AM53C974_abort,                    /* int (* abort)(Scsi_Cmnd *)                   */  \
-    AM53C974_reset,                    /* int (* reset)(Scsi_Cmnd *)                   */  \
-    NULL,                      /* int (* slave_attach)(int, int)               */  \
-    scsicam_bios_param,                /* int (* bios_param)(Disk *, int, int[])       */  \
-    12,                        /* can_queue                                    */  \
-    -1,                         /* this_id                                      */  \
-    SG_ALL,                            /* sg_tablesize                                 */  \
-    1,                                 /* cmd_per_lun                                  */  \
-    0,                                 /* present, i.e. how many adapters of this kind */  \
-    0,                                 /* unchecked_isa_dma                            */  \
-    DISABLE_CLUSTERING                 /* use_clustering                               */  \
+#define AM53C974 {                               \
+    proc_dir:       &proc_scsi_am53c974,          \
+    name:           "AM53C974",                          \
+    detect:         AM53C974_detect,                     \
+    release:        AM53C974_release,            \
+    info:           AM53C974_info,                       \
+    command:        AM53C974_command,                    \
+    queuecommand:   AM53C974_queue_command,      \
+    abort:          AM53C974_abort,                      \
+    reset:          AM53C974_reset,                      \
+    bios_param:     scsicam_bios_param,                  \
+    can_queue:      12,                          \
+    this_id:        -1,                           \
+    sg_tablesize:   SG_ALL,                              \
+    cmd_per_lun:    1,                                   \
+    use_clustering: DISABLE_CLUSTERING                   \
     }
 
 void AM53C974_setup(char *str, int *ints);
@@ -85,7 +78,7 @@ const char *AM53C974_info(struct Scsi_Host *);
 int AM53C974_command(Scsi_Cmnd *SCpnt);
 int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
 int AM53C974_abort(Scsi_Cmnd *cmd);
-int AM53C974_reset (Scsi_Cmnd *cmd);
+int AM53C974_reset (Scsi_Cmnd *cmd, unsigned int);
 
 #endif /* AM53C974_H */
 
index 6f62e04b0af664684c0c6125646dfd01be4f3d71..415658d43a36b82e538d2dec27679b412f17a49e 100644 (file)
@@ -27,9 +27,6 @@
 */
 
 
-#include <linux/config.h>
-
-
 /*
   Define types for some of the structures that interface with the rest
   of the Linux Kernel and SCSI Subsystem.
@@ -67,27 +64,18 @@ extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
 */
 
 #define BUSLOGIC                                                        \
-  { NULL,                              /* Next                      */  \
-    NULL,                              /* Usage Count Pointer       */  \
-    &BusLogic_ProcDirectoryEntry,      /* /proc Directory Entry     */  \
-    BusLogic_ProcDirectoryInfo,                /* /proc Info Function       */  \
-    "BusLogic",                                /* Driver Name               */  \
-    BusLogic_DetectHostAdapter,                /* Detect Host Adapter       */  \
-    BusLogic_ReleaseHostAdapter,       /* Release Host Adapter      */  \
-    BusLogic_DriverInfo,               /* Driver Info Function      */  \
-    NULL,                              /* Command Function          */  \
-    BusLogic_QueueCommand,             /* Queue Command Function    */  \
-    BusLogic_AbortCommand,             /* Abort Command Function    */  \
-    BusLogic_ResetCommand,             /* Reset Command Function    */  \
-    NULL,                              /* Slave Attach Function     */  \
-    BusLogic_BIOSDiskParameters,       /* BIOS Disk Parameters      */  \
-    0,                                 /* Can Queue                 */  \
-    0,                                 /* This ID                   */  \
-    0,                                 /* Scatter/Gather Table Size */  \
-    0,                                 /* SCSI Commands per LUN     */  \
-    0,                                 /* Present                   */  \
-    1,                                 /* Default Unchecked ISA DMA */  \
-    ENABLE_CLUSTERING }                        /* Enable Clustering         */
+  { proc_dir:          &BusLogic_ProcDirectoryEntry,   /* /proc Directory Entry     */  \
+    proc_info:         BusLogic_ProcDirectoryInfo,     /* /proc Info Function       */  \
+    name:              "BusLogic",                     /* Driver Name               */  \
+    detect:            BusLogic_DetectHostAdapter,     /* Detect Host Adapter       */  \
+    release:           BusLogic_ReleaseHostAdapter,    /* Release Host Adapter      */  \
+    info:              BusLogic_DriverInfo,            /* Driver Info Function      */  \
+    queuecommand:      BusLogic_QueueCommand,          /* Queue Command Function    */  \
+    abort:             BusLogic_AbortCommand,          /* Abort Command Function    */  \
+    reset:             BusLogic_ResetCommand,          /* Reset Command Function    */  \
+    bios_param:        BusLogic_BIOSDiskParameters,    /* BIOS Disk Parameters      */  \
+    unchecked_isa_dma: 1,                              /* Default Unchecked ISA DMA */  \
+    use_clustering:    ENABLE_CLUSTERING }             /* Enable Clustering         */
 
 
 /*
index 15508a43676e1a5940ed5932effe22ad7b6193f0..7738a5bb383ac270b71c7d51564a71e8a67dbb3d 100644 (file)
@@ -13,6 +13,7 @@ comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
 bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
 
 bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+bool 'SCSI logging facility' CONFIG_SCSI_LOGGING
 
 mainmenu_option next_comment
 comment 'SCSI low-level drivers'
@@ -113,7 +114,17 @@ dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
     int  '  maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
   fi
 dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
-#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+#
+# Note - this is a very special 'host' adapter that simulates the presence of some disks.
+# It can come in very handy for troubleshooting.  Anyone else is welcome to use it - all
+# you do is hack it to simulate the condition you want to test for, and then use it.
+#
+# The actual configuration in any kernel release could change at any time as I hack it to
+# simulate various conditions that I am testing.
+#
+if [ "`whoami`" = "eric" ]; then
+  dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+fi
 if [ "$CONFIG_PPC" = "y" ]; then
   dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI
   if [ "$CONFIG_SCSI_MESH" != "n" ]; then
index dbe98db15991bff9cdf0331d7c07d750373fd6d4..b071f8eda6012f181c04a372c9e7884802bd8978 100644 (file)
@@ -37,7 +37,7 @@ ifeq ($(CONFIG_SCSI),y)
   SCSI=scsi.o
   ifeq ($(CONFIG_MODULES),y)
     O_TARGET := scsi_n_syms.o
-    O_OBJS   := scsi.o
+    O_OBJS   := scsi.o scsi_error.o scsi_obsolete.o scsi_queue.o
     OX_OBJS  := scsi_syms.o
     SCSI     := $(O_TARGET)
   endif
@@ -490,8 +490,10 @@ seagate.o: seagate.c
        rm fake.c
 
 scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
-               scsicam.o scsi_proc.o
-       $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+               scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o scsi_queue.o
+       $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o \
+               constants.o scsicam.o scsi_proc.o               \
+               scsi_error.o scsi_obsolete.o scsi_queue.o \
 
 sr_mod.o: sr.o sr_ioctl.o sr_vendor.o
        $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o sr_vendor.o
index 88e45e5e6a9201e9d6546f2699b53ba55bbf0c63..4ec3abbd5365f02a0541fe9352654c18839b2da6 100644 (file)
  * Use SG_NONE if DMA mode is enabled!
  */
 #define NCR53c406a { \
-     NULL                      /* next */, \
-     NULL                      /* usage count */, \
-     &proc_scsi_NCR53c406a      /* proc_dir */, \
-     NULL                      /* proc_info */, \
-     "NCR53c406a"              /* name */, \
-     NCR53c406a_detect         /* detect */, \
-     NULL                      /* release */, \
-     NCR53c406a_info           /* info */, \
-     NCR53c406a_command                /* command */, \
-     NCR53c406a_queue          /* queuecommand */, \
-     NCR53c406a_abort          /* abort */, \
-     NCR53c406a_reset          /* reset */, \
-     NULL                      /* slave_attach */, \
-     NCR53c406a_biosparm       /* biosparm */, \
-     1                         /* can_queue */, \
-     7                         /* SCSI ID of the chip */, \
-     32                                /*SG_ALL*/ /*SG_NONE*/, \
-     1                         /* commands per lun */, \
-     0                         /* number of boards in system */, \
-     1                         /* unchecked_isa_dma */, \
-     ENABLE_CLUSTERING \
+     proc_dir:          &proc_scsi_NCR53c406a   /* proc_dir */,         \
+     name:              "NCR53c406a"           /* name */,             \
+     detect:            NCR53c406a_detect      /* detect */,           \
+     info:              NCR53c406a_info                /* info */,             \
+     command:           NCR53c406a_command     /* command */,          \
+     queuecommand:      NCR53c406a_queue       /* queuecommand */,     \
+     abort:             NCR53c406a_abort       /* abort */,            \
+     reset:             NCR53c406a_reset       /* reset */,            \
+     bios_param:        NCR53c406a_biosparm    /* biosparm */,         \
+     can_queue:         1                      /* can_queue */,        \
+     this_id:           7                      /* SCSI ID of the chip */, \
+     sg_tablesize:      32                     /*SG_ALL*/ /*SG_NONE*/, \
+     cmd_per_lun:       1                      /* commands per lun */, \
+     unchecked_isa_dma: 1                      /* unchecked_isa_dma */, \
+     use_clustering:    ENABLE_CLUSTERING                               \
 }
 
 extern struct proc_dir_entry proc_scsi_NCR53c406a;
index 2689083586ff2c7817638cfbee033faf87cf7da5..b04ef6c2585208d194913263975b5f9c9c64a20c 100644 (file)
@@ -33,27 +33,18 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 extern struct proc_dir_entry proc_scsi_a2091;
 
-#define A2091_SCSI {  /* next */                NULL,            \
-                     /* module */         NULL,                 \
-                     /* proc_dir_entry */      &proc_scsi_a2091, \
-                     /* proc_info */           NULL,            \
-                     /* name */                "Commodore A2091/A590 SCSI", \
-                     /* detect */              a2091_detect,    \
-                     /* release */             a2091_release,   \
-                     /* info */                NULL,            \
-                     /* command */             NULL,            \
-                     /* queuecommand */        wd33c93_queuecommand, \
-                     /* abort */               wd33c93_abort,   \
-                     /* reset */               wd33c93_reset,   \
-                     /* slave_attach */        NULL,            \
-                     /* bios_param */          NULL,            \
-                     /* can_queue */           CAN_QUEUE,       \
-                     /* this_id */             7,               \
-                     /* sg_tablesize */        SG_ALL,          \
-                     /* cmd_per_lun */         CMD_PER_LUN,     \
-                     /* present */             0,               \
-                     /* unchecked_isa_dma */   0,               \
-                     /* use_clustering */      DISABLE_CLUSTERING }
+#define A2091_SCSI {  proc_dir:                   &proc_scsi_a2091, \
+                     name:                "Commodore A2091/A590 SCSI", \
+                     detect:              a2091_detect,    \
+                     release:             a2091_release,   \
+                     queuecommand:        wd33c93_queuecommand, \
+                     abort:               wd33c93_abort,   \
+                     reset:               wd33c93_reset,   \
+                     can_queue:           CAN_QUEUE,       \
+                     this_id:             7,               \
+                     sg_tablesize:        SG_ALL,          \
+                     cmd_per_lun:         CMD_PER_LUN,     \
+                     use_clustering:      DISABLE_CLUSTERING }
 #else
 
 /*
index 1b13557b9b2b49f74010e42cee6a1d1b88d208c2..c088f1d9890ac941aa06fb341e0eb06cb8795fbe 100644 (file)
@@ -33,27 +33,19 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 extern struct proc_dir_entry proc_scsi_a3000;
 
-#define A3000_SCSI {  /* next */                NULL,            \
-                     /* module */         NULL,                 \
-                     /* proc_dir_entry */      &proc_scsi_a3000, \
-                     /* proc_info */           NULL,            \
-                     /* name */                "Amiga 3000 built-in SCSI", \
-                     /* detect */              a3000_detect,    \
-                     /* release */             a3000_release,   \
-                     /* info */                NULL,            \
-                     /* command */             NULL,            \
-                     /* queuecommand */        wd33c93_queuecommand, \
-                     /* abort */               wd33c93_abort,   \
-                     /* reset */               wd33c93_reset,   \
-                     /* slave_attach */        NULL,            \
-                     /* bios_param */          NULL,            \
-                     /* can_queue */           CAN_QUEUE,       \
-                     /* this_id */             7,               \
-                     /* sg_tablesize */        SG_ALL,          \
-                     /* cmd_per_lun */         CMD_PER_LUN,     \
-                     /* present */             0,               \
-                     /* unchecked_isa_dma */   0,               \
-                     /* use_clustering */      ENABLE_CLUSTERING }
+#define A3000_SCSI {  proc_dir:                   &proc_scsi_a3000,            \
+                     proc_info:           NULL,                        \
+                     name:                "Amiga 3000 built-in SCSI",  \
+                     detect:              a3000_detect,                \
+                     release:             a3000_release,               \
+                     queuecommand:        wd33c93_queuecommand,        \
+                     abort:               wd33c93_abort,               \
+                     reset:               wd33c93_reset,               \
+                     can_queue:           CAN_QUEUE,                   \
+                     this_id:             7,                           \
+                     sg_tablesize:        SG_ALL,                      \
+                     cmd_per_lun:         CMD_PER_LUN,                 \
+                     use_clustering:      ENABLE_CLUSTERING }
 #else
 
 /*
index 737793e2950fe2a9cb334fd5909ad0a08f1db413..667b2148259bf2dd28e6c5d3167f22484c08a80d 100644 (file)
@@ -2815,7 +2815,7 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
     int                 leftlen;
     char                *curbuf;
     off_t               advoffset;
-    Scsi_Device         *scd;
+    Scsi_Device         *scd = NULL;
 
     ASC_DBG(1, "advansys_proc_info: begin\n");
 
@@ -2889,8 +2889,7 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
      * Display target driver information for each device attached
      * to the board.
      */
-    for (scd = scsi_devices; scd; scd = scd->next) {
-        if (scd->host == shp) {
+    for (scd = scd->host->host_queue; scd; scd = scd->next) {
             cp = boardp->prtbuf;
             /*
              * Note: If proc_print_scsidevice() writes more than
@@ -2907,7 +2906,6 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
             }
             advoffset += cplen;
             curbuf += cnt;
-        }
     }
     
     /*
@@ -3409,15 +3407,20 @@ advansys_detect(Scsi_Host_Template *tpnt)
             shp->select_queue_depths = advansys_select_queue_depths;
 
 #ifdef MODULE
-            /*
-             * Following v1.3.89, 'cmd_per_lun' is no longer needed
-             * and should be set to zero. But because of a bug introduced
-             * in v1.3.89 if the driver is compiled as a module and
-             * 'cmd_per_lun' is zero, the Mid-Level SCSI function
-             * 'allocate_device' will panic. To allow the driver to
-             * work as a module in these kernels set 'cmd_per_lun' to 1.
-             */
-            shp->cmd_per_lun = 1;
+           /*
+            * FIXME(eric) - this is completely bogus.  We need to
+            * figure out what exactly the real problem is and deal
+            * with it.
+            */
+           /*
+            * Following v1.3.89, 'cmd_per_lun' is no longer needed
+            * and should be set to zero. But because of a bug introduced
+            * in v1.3.89 if the driver is compiled as a module and
+            * 'cmd_per_lun' is zero, the Mid-Level SCSI function
+            * 'scsi_allocate_device' will panic. To allow the driver to
+            * work as a module in these kernels set 'cmd_per_lun' to 1.
+            */
+           shp->cmd_per_lun = 1;
 #else /* MODULE */
             shp->cmd_per_lun = 0;
 #endif /* MODULE */
@@ -6677,10 +6680,16 @@ asc_prt_scsi_host(struct Scsi_Host *s)
         (unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no,
         (unsigned) s->last_reset);
 
+#ifdef ERIC_neverdef /* { */
+       /*
+        * This information is private to the mid-layer scsi and the
+        * the low-level drivers shouldn't even be aware that it is there.
+        */
     printk(
 " host_wait %x, host_queue %x, hostt %x, block %x,\n",
         (unsigned) s->host_wait, (unsigned) s->host_queue,
         (unsigned) s->hostt, (unsigned) s->block);
+#endif /* ERIC_neverdef */ /* } */
 
     printk(
 " wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n",
index eb3d65e65bb21ca2e01b9ce06a25b659cb604622..54858404aadea0e7527f09a1fecc8da65f3acb17 100644 (file)
@@ -40,18 +40,10 @@ const char *advansys_info(struct Scsi_Host *);
 int advansys_command(Scsi_Cmnd *);
 int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 int advansys_abort(Scsi_Cmnd *);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
-int advansys_reset(Scsi_Cmnd *);
-#else /* version >= v1.3.89 */
 int advansys_reset(Scsi_Cmnd *, unsigned int);
-#endif /* version >= v1.3.89 */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
-int advansys_biosparam(Disk *, int, int[]);
-#else /* version >= v1.3.0 */
 int advansys_biosparam(Disk *, kdev_t, int[]);
 extern struct proc_dir_entry proc_scsi_advansys;
 int advansys_proc_info(char *, char **, off_t, int, int, int);
-#endif /* version >= v1.3.0 */
 
 /* init/main.c setup function */
 void advansys_setup(char *, int *);
@@ -59,88 +51,31 @@ void advansys_setup(char *, int *);
 /*
  * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h.
  */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
 #define ADVANSYS { \
-    NULL,                     /* struct SHT *next */ \
-    NULL,                     /* int *usage_count */ \
-    "advansys",               /* char *name */ \
-    advansys_detect,          /* int (*detect)(struct SHT *) */ \
-    advansys_release,         /* int (*release)(struct Scsi_Host *) */ \
-    advansys_info,            /* const char *(*info)(struct Scsi_Host *) */ \
-    advansys_command,         /* int (*command)(Scsi_Cmnd *) */ \
-    advansys_queuecommand, \
-            /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
-    advansys_abort,           /* int (*abort)(Scsi_Cmnd *) */ \
-    advansys_reset,           /* int (*reset)(Scsi_Cmnd *) */ \
-    NULL,                     /* int (*slave_attach)(int, int) */ \
-    advansys_biosparam,       /* int (* bios_param)(Disk *, int, int []) */ \
-    /* \
-     * The following fields are set per adapter in advansys_detect(). \
-     */ \
-    0,                        /* int can_queue */ \
-    0,                        /* int this_id */ \
-    0,                        /* short unsigned int sg_tablesize */ \
-    0,                        /* short cmd_per_lun */ \
-    0,                        /* unsigned char present */    \
-    /* \
-     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
-     * must be set. The flag will be cleared in advansys_detect for non-ISA \
-     * adapters. Refer to the comment in scsi_module.c for more information. \
-     */ \
-    1,                        /* unsigned unchecked_isa_dma:1 */ \
-    /* \
-     * All adapters controlled by this driver are capable of large \
-     * scatter-gather lists. According to the mid-level SCSI documentation \
-     * this obviates any performance gain provided by setting \
-     * 'use_clustering'. But empirically while CPU utilization is increased \
-     * by enabling clustering, I/O throughput increases as well. \
-     */ \
-    ENABLE_CLUSTERING,        /* unsigned use_clustering:1 */ \
+                       proc_dir:     &proc_scsi_advansys,       \
+                       proc_info:    advansys_proc_info,        \
+                       name:         "advansys",                \
+                       detect:       advansys_detect,           \
+                       release:      advansys_release,          \
+                       info:         advansys_info,             \
+                       command:      advansys_command,          \
+                       queuecommand: advansys_queuecommand,     \
+                       abort:        advansys_abort,            \
+                       reset:        advansys_reset,            \
+                       bios_param:    advansys_biosparam,       \
+       /*                                                       \
+        * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+        * must be set. The flag will be cleared in advansys_detect for non-ISA \
+        * adapters. Refer to the comment in scsi_module.c for more information. \
+        */                                                      \
+                       unchecked_isa_dma: 1,                    \
+       /*                                                       \
+        * All adapters controlled by this driver are capable of large \
+        * scatter-gather lists. According to the mid-level SCSI documentation \
+        * this obviates any performance gain provided by setting \
+        * 'use_clustering'. But empirically while CPU utilization is increased \
+        * by enabling clustering, I/O throughput increases as well. \
+        */                                                      \
+                       use_clustering: ENABLE_CLUSTERING,       \
 }
-#else /* version >= v1.3.0 */
-#define ADVANSYS { \
-    NULL,                    /* struct SHT *next */ \
-    NULL, \
-        /* version < v2.1.23 long *usage_count */ \
-        /* version >= v2.1.23 struct module * */ \
-    &proc_scsi_advansys,     /* struct proc_dir_entry *proc_dir */ \
-    advansys_proc_info,    \
-        /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \
-    "advansys",              /* const char *name */ \
-    advansys_detect,         /* int (*detect)(struct SHT *) */ \
-    advansys_release,        /* int (*release)(struct Scsi_Host *) */ \
-    advansys_info,           /* const char *(*info)(struct Scsi_Host *) */ \
-    advansys_command,        /* int (*command)(Scsi_Cmnd *) */ \
-    advansys_queuecommand, \
-        /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
-    advansys_abort,          /* int (*abort)(Scsi_Cmnd *) */ \
-    advansys_reset, \
-        /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \
-        /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \
-    NULL,                    /* int (*slave_attach)(int, int) */ \
-    advansys_biosparam,      /* int (* bios_param)(Disk *, kdev_t, int []) */ \
-    /* \
-     * The following fields are set per adapter in advansys_detect(). \
-     */ \
-    0,                        /* int can_queue */ \
-    0,                        /* int this_id */ \
-    0,                        /* short unsigned int sg_tablesize */ \
-    0,                        /* short cmd_per_lun */ \
-    0,                        /* unsigned char present */    \
-    /* \
-     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
-     * must be set. The flag will be cleared in advansys_detect for non-ISA \
-     * adapters. Refer to the comment in scsi_module.c for more information. \
-     */ \
-    1,                        /* unsigned unchecked_isa_dma:1 */ \
-    /* \
-     * All adapters controlled by this driver are capable of large \
-     * scatter-gather lists. According to the mid-level SCSI documentation \
-     * this obviates any performance gain provided by setting \
-     * 'use_clustering'. But empirically while CPU utilization is increased \
-     * by enabling clustering, I/O throughput increases as well. \
-     */ \
-    ENABLE_CLUSTERING,        /* unsigned use_clustering:1 */ \
-}
-#endif /* version >= v1.3.0 */
 #endif /* _ADVANSYS_H */
index 56c56e52bf4bdf17183b83614739c539881be9d8..dba7eba9313bace8916a95ec17cf1096cb6ff5ae 100644 (file)
@@ -28,27 +28,23 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int
 extern struct proc_dir_entry proc_scsi_aha152x;
 
 /* Initial value of Scsi_Host entry */
-#define AHA152X { /* next */               0, \
-                  /* module */             0, \
-                  /* proc_dir */           &proc_scsi_aha152x, \
-                  /* proc_info */          aha152x_proc_info, \
-                  /* name */               AHA152X_REVID, \
-                  /* detect */             aha152x_detect, \
-                  /* release */            0, \
-                  /* info */               0, \
-                  /* command */                       aha152x_command, \
-                  /* queuecommand */       aha152x_queue, \
-                  /* abort */              aha152x_abort, \
-                  /* reset */              aha152x_reset, \
-                  /* slave_attach */       0, \
-                  /* bios_param */         aha152x_biosparam, \
-                  /* can_queue */          1, \
-                  /* this_id */            7, \
-                  /* sg_tablesize */       SG_ALL, \
-                  /* cmd_per_lun */        1, \
-                  /* present */            0, \
-                  /* unchecked_isa_dma */  0, \
-                  /* use_clustering */     DISABLE_CLUSTERING }
+#define AHA152X { proc_dir:           &proc_scsi_aha152x, \
+                  proc_info:          aha152x_proc_info,  \
+                  name:               AHA152X_REVID,     \
+                  detect:             aha152x_detect,    \
+                  command:           aha152x_command,    \
+                  queuecommand:       aha152x_queue,     \
+                  abort:              aha152x_abort,     \
+                  reset:              aha152x_reset,     \
+                  slave_attach:       0,                 \
+                  bios_param:         aha152x_biosparam,  \
+                  can_queue:          1,                 \
+                  this_id:            7,                 \
+                  sg_tablesize:       SG_ALL,            \
+                  cmd_per_lun:        1,                 \
+                  present:            0,                 \
+                  unchecked_isa_dma:  0,                 \
+                  use_clustering:     DISABLE_CLUSTERING }
 #endif
 
 
index 29f31e1706c73505529962796f037d61b03d4996..2274ee49a462417bc2ebe5f8db0df3d24a3907fb 100644 (file)
@@ -1117,11 +1117,263 @@ static int aha1542_restart(struct Scsi_Host * shost)
   return 0;
 }
 
-/* The abort command does not leave the device in a clean state where
-   it is available to be used again.  Until this gets worked out, we will
-   leave it commented out.  */
-
 int aha1542_abort(Scsi_Cmnd * SCpnt)
+{
+    
+    /*
+     * The abort command does not leave the device in a clean state where
+     *  it is available to be used again.  Until this gets worked out, we
+     * will leave it commented out.  
+     */
+
+    printk("aha1542.c: Unable to abort command for target %d\n", 
+          SCpnt->target);
+    return FAILED;
+}
+
+/*
+ * This is a device reset.  This is handled by sending a special command
+ * to the device.
+ */
+int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
+{
+    unsigned long flags;
+    struct mailbox * mb;
+    unchar target = SCpnt->target;
+    unchar lun = SCpnt->lun;
+    int mbo;
+    struct ccb  *ccb;
+    unchar ahacmd = CMD_START_SCSI;
+
+    ccb = HOSTDATA(SCpnt->host)->ccb;
+    mb = HOSTDATA(SCpnt->host)->mb;
+
+    save_flags(flags);
+    cli();
+    mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
+    if (mbo >= AHA1542_MAILBOXES) mbo = 0;
+    
+    do{
+       if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
+           break;
+       mbo++;
+       if (mbo >= AHA1542_MAILBOXES) mbo = 0;
+    } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
+    
+    if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
+       panic("Unable to find empty mailbox for aha1542.\n");
+    
+    HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt;  /* This will effectively
+                                                  prevent someone else from
+                                                  screwing with this cdb. */
+           
+    HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;    
+    restore_flags(flags);
+    
+    any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/
+
+    memset(&ccb[mbo], 0, sizeof(struct ccb));
+    
+    ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
+
+    ccb[mbo].idlun = (target&7)<<5 | (lun & 7); /*SCSI Target Id*/
+
+    ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+    ccb[mbo].commlinkid = 0;
+    
+    /* 
+     * Now tell the 1542 to flush all pending commands for this 
+     * target 
+     */
+    aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+    printk("aha1542.c: Trying device reset for target %d\n", SCpnt->target);
+
+    return SUCCESS;
+           
+
+#ifdef ERIC_neverdef
+    /* 
+     * With the 1542 we apparently never get an interrupt to
+     * acknowledge a device reset being sent.  Then again, Leonard
+     * says we are doing this wrong in the first place...
+     *
+     * Take a wait and see attitude.  If we get spurious interrupts,
+     * then the device reset is doing something sane and useful, and
+     * we will wait for the interrupt to post completion.
+     */
+    printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+    
+    /*
+     * Free the command block for all commands running on this 
+     * target... 
+     */
+    for(i=0; i< AHA1542_MAILBOXES; i++)
+    {
+       if(HOSTDATA(SCpnt->host)->SCint[i] &&
+          HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
+       {
+           Scsi_Cmnd * SCtmp;
+           SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+           if (SCtmp->host_scribble) 
+           {
+               scsi_free(SCtmp->host_scribble, 512);
+           }
+           
+           HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+           HOSTDATA(SCpnt->host)->mb[i].status = 0;
+       }
+    }
+    return SUCCESS;
+
+    return FAILED;
+#endif /* ERIC_neverdef */
+}
+
+int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
+{
+    int i;
+
+    /* 
+     * This does a scsi reset for all devices on the bus.
+     * In principle, we could also reset the 1542 - should
+     * we do this?  Try this first, and we can add that later
+     * if it turns out to be useful.
+     */
+    outb(SCRST, CONTROL(SCpnt->host->io_port));
+
+    /*
+     * Wait for the thing to settle down a bit.  Unfortunately
+     * this is going to basically lock up the machine while we
+     * wait for this to complete.  To be 100% correct, we need to
+     * check for timeout, and if we are doing something like this
+     * we are pretty desperate anyways.
+     */
+    scsi_sleep(4*HZ);
+
+    WAIT(STATUS(SCpnt->host->io_port), 
+        STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+    
+    /*
+     * Now try to pick up the pieces.  For all pending commands,
+     * free any internal data structures, and basically clear things
+     * out.  We do not try and restart any commands or anything - 
+     * the strategy handler takes care of that crap.
+     */
+    printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+    for(i=0; i< AHA1542_MAILBOXES; i++)
+    {
+       if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
+       {
+           Scsi_Cmnd * SCtmp;
+           SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+
+    
+           if( SCtmp->device->soft_reset )
+           {
+               /*
+                * If this device implements the soft reset option,
+                * then it is still holding onto the command, and
+                * may yet complete it.  In this case, we don't
+                * flush the data.
+                */
+               continue;
+           }
+
+           if (SCtmp->host_scribble) 
+           {
+               scsi_free(SCtmp->host_scribble, 512);
+           }
+           
+           HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+           HOSTDATA(SCpnt->host)->mb[i].status = 0;
+       }
+    }
+
+    return SUCCESS;
+
+fail:
+    return FAILED;
+}
+
+int aha1542_host_reset(Scsi_Cmnd * SCpnt)
+{
+    int i;
+
+    /* 
+     * This does a scsi reset for all devices on the bus.
+     * In principle, we could also reset the 1542 - should
+     * we do this?  Try this first, and we can add that later
+     * if it turns out to be useful.
+     */
+    outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
+
+    /*
+     * Wait for the thing to settle down a bit.  Unfortunately
+     * this is going to basically lock up the machine while we
+     * wait for this to complete.  To be 100% correct, we need to
+     * check for timeout, and if we are doing something like this
+     * we are pretty desperate anyways.
+     */
+    scsi_sleep(4*HZ);
+
+    WAIT(STATUS(SCpnt->host->io_port), 
+        STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+    
+    /*
+     * We need to do this too before the 1542 can interact with
+     * us again.
+     */
+    setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+    
+    /*
+     * Now try to pick up the pieces.  For all pending commands,
+     * free any internal data structures, and basically clear things
+     * out.  We do not try and restart any commands or anything - 
+     * the strategy handler takes care of that crap.
+     */
+    printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+    
+    for(i=0; i< AHA1542_MAILBOXES; i++)
+    {
+       if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
+       {
+           Scsi_Cmnd * SCtmp;
+           SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+
+           if( SCtmp->device->soft_reset )
+           {
+               /*
+                * If this device implements the soft reset option,
+                * then it is still holding onto the command, and
+                * may yet complete it.  In this case, we don't
+                * flush the data.
+                */
+               continue;
+           }
+
+           if (SCtmp->host_scribble) 
+           {
+               scsi_free(SCtmp->host_scribble, 512);
+           }
+           
+           HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+           HOSTDATA(SCpnt->host)->mb[i].status = 0;
+       }
+    }
+
+    return SUCCESS;
+
+fail:
+    return FAILED;
+}
+
+/*
+ * These are the old error handling routines.  They are only temporarily
+ * here while we play with the new error handling code.
+ */
+int aha1542_old_abort(Scsi_Cmnd * SCpnt)
 {
 #if 0
   unchar ahacmd = CMD_START_SCSI;
@@ -1194,7 +1446,7 @@ int aha1542_abort(Scsi_Cmnd * SCpnt)
    For a first go, we assume that the 1542 notifies us with all of the
    pending commands (it does implement soft reset, after all). */
 
-int aha1542_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
     unchar ahacmd = CMD_START_SCSI;
     int i;
index 6c250d5a54d60bbb19ed15a90382e9a854f5e9e8..820cc4b1ce3b3215c1fc41597b93b9287f705826 100644 (file)
@@ -133,8 +133,12 @@ struct ccb {                       /* Command Control Block 5.3 */
 int aha1542_detect(Scsi_Host_Template *);
 int aha1542_command(Scsi_Cmnd *);
 int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int aha1542_abort(Scsi_Cmnd *);
-int aha1542_reset(Scsi_Cmnd *, unsigned int);
+int aha1542_abort(Scsi_Cmnd * SCpnt);
+int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
+int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
+int aha1542_host_reset(Scsi_Cmnd * SCpnt);
+extern int aha1542_old_abort(Scsi_Cmnd * SCpnt);
+int aha1542_old_reset(Scsi_Cmnd *, unsigned int);
 int aha1542_biosparam(Disk *, kdev_t, int*);
 
 #define AHA1542_MAILBOXES 8
@@ -147,25 +151,24 @@ int aha1542_biosparam(Disk *, kdev_t, int*);
 
 extern struct proc_dir_entry proc_scsi_aha1542;
 
-#define AHA1542 {  NULL, NULL,                         \
-                     &proc_scsi_aha1542,/* proc_dir_entry */ \
-                    NULL,                              \
-                    "Adaptec 1542",                    \
-                    aha1542_detect,                    \
-                    NULL,                              \
-                    NULL,                              \
-                    aha1542_command,                   \
-                    aha1542_queuecommand,              \
-                    aha1542_abort,                     \
-                    aha1542_reset,                     \
-                    NULL,                              \
-                    aha1542_biosparam,                 \
-                    AHA1542_MAILBOXES,                 \
-                    7,                                 \
-                    AHA1542_SCATTER,                   \
-                    AHA1542_CMDLUN,                    \
-                    0,                                 \
-                    1,                                 \
-                    ENABLE_CLUSTERING}
+#define AHA1542 {    proc_dir:                 &proc_scsi_aha1542,     \
+                    name:                      "Adaptec 1542",         \
+                    detect:                    aha1542_detect,         \
+                    command:                   aha1542_command,        \
+                    queuecommand:              aha1542_queuecommand,   \
+                     abort:                    aha1542_old_abort,      \
+                     reset:                    aha1542_old_reset,      \
+                    eh_abort_handler:          aha1542_abort,          \
+                    eh_device_reset_handler:   aha1542_dev_reset,      \
+                    eh_bus_reset_handler:      aha1542_bus_reset,      \
+                    eh_host_reset_handler:     aha1542_host_reset,     \
+                    bios_param:                aha1542_biosparam,      \
+                    can_queue:                 AHA1542_MAILBOXES,      \
+                    this_id:                   7,                      \
+                    sg_tablesize:              AHA1542_SCATTER,        \
+                    cmd_per_lun:               AHA1542_CMDLUN,         \
+                    unchecked_isa_dma:         1,                      \
+                    use_clustering:            ENABLE_CLUSTERING,      \
+                    use_new_eh_code:           1}
 
 #endif
index cd38a894b3c905b41e242361787e79295873075d..597ec8be34c6c76b7dd80c1eeb5d0902df52e52f 100644 (file)
@@ -172,25 +172,19 @@ int aha1740_proc_info(char *buffer, char **start, off_t offset,
 
 extern struct proc_dir_entry proc_scsi_aha1740;
 
-#define AHA1740 {NULL, NULL,                           \
-                   &proc_scsi_aha1740,                 \
-                  aha1740_proc_info,                   \
-                  "Adaptec 174x (EISA)",               \
-                  aha1740_detect,                      \
-                  NULL,                                \
-                  NULL,                                \
-                  aha1740_command,                     \
-                  aha1740_queuecommand,                \
-                  aha1740_abort,                       \
-                  aha1740_reset,                       \
-                  NULL,                                \
-                  aha1740_biosparam,                   \
-                  AHA1740_ECBS,                        \
-                  7,                                   \
-                  AHA1740_SCATTER,                     \
-                  AHA1740_CMDLUN,                      \
-                  0,                                   \
-                  0,                                   \
-                  ENABLE_CLUSTERING}
+#define AHA1740 {  proc_dir:       &proc_scsi_aha1740,                 \
+                  proc_info:      aha1740_proc_info,                   \
+                  name:           "Adaptec 174x (EISA)",               \
+                  detect:         aha1740_detect,                      \
+                  command:        aha1740_command,                     \
+                  queuecommand:   aha1740_queuecommand,                \
+                  abort:          aha1740_abort,                       \
+                  reset:          aha1740_reset,                       \
+                  bios_param:     aha1740_biosparam,                   \
+                  can_queue:      AHA1740_ECBS,                        \
+                  this_id:        7,                                   \
+                  sg_tablesize:   AHA1740_SCATTER,                     \
+                  cmd_per_lun:    AHA1740_CMDLUN,                      \
+                  use_clustering: ENABLE_CLUSTERING}
 
 #endif
index 5ba54acfa79983459ee9577128b56ad1889b741a..fd40554f3c66e4089d8db6adb7fe0a0eb3e92d8f 100644 (file)
  * to do with card config are filled in after the card is detected.
  */
 #define AIC7XXX        {                                               \
-       NULL,                                                   \
-       NULL,                                                   \
-       NULL,                                                   \
-       aic7xxx_proc_info,                                      \
-       NULL,                                                   \
-       aic7xxx_detect,                                         \
-       NULL,                                                   \
-       aic7xxx_info,                                           \
-       NULL,                                                   \
-       aic7xxx_queue,                                          \
-       NULL,                                                   \
-       aic7xxx_reset,                                          \
-       NULL,                                                   \
-       aic7xxx_biosparam,                                      \
-       -1,                     /* max simultaneous cmds      */\
-       -1,                     /* scsi id of host adapter    */\
-       0,                      /* max scatter-gather cmds    */\
-       2,                      /* cmds per lun (linked cmds) */\
-       0,                      /* number of 7xxx's present   */\
-       0,                      /* no memory DMA restrictions */\
-       ENABLE_CLUSTERING                                       \
+       proc_info:       aic7xxx_proc_info,                                     \
+       detect:          aic7xxx_detect,                                        \
+       info:            aic7xxx_info,                                          \
+       queuecommand:    aic7xxx_queue,                                         \
+       abort:           aic7xxx_abort,                                         \
+       reset:           aic7xxx_reset,                                         \
+       bios_param:      aic7xxx_biosparam,                                     \
+       can_queue:       -1,                    /* max simultaneous cmds      */\
+       this_id:         -1,                    /* scsi id of host adapter    */\
+       sg_tablesize:    SG_ALL,                /* max scatter-gather cmds    */\
+       cmd_per_lun:     2,                     /* cmds per lun (linked cmds) */\
+       use_clustering:  ENABLE_CLUSTERING,                                     \
+       use_new_eh_code: 0                      /* Enable new error code */     \
 }
 
 extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
 extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
 extern int aic7xxx_detect(Scsi_Host_Template *);
 extern int aic7xxx_command(Scsi_Cmnd *);
+extern int aic7xxx_abort(Scsi_Cmnd *);
 extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
index ca85dca7b94380b48cc85c4c1b60e80bb3599958..09317d376b9b30f82ddfa202b63c3fec80ad7da6 100644 (file)
@@ -27,26 +27,16 @@ void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
 
 extern struct proc_dir_entry proc_scsi_amiga7xx;
 
-#define AMIGA7XX_SCSI {/* next */                NULL,            \
-                     /* usage_count */         NULL,            \
-                     /* proc_dir_entry */      NULL, \
-                     /* proc_info */           NULL,            \
-                     /* name */                "Amiga NCR53c710 SCSI", \
-                     /* detect */              amiga7xx_detect,    \
-                     /* release */             NULL,   \
-                     /* info */                NULL,            \
-                     /* command */             NULL,            \
-                     /* queuecommand */        NCR53c7xx_queue_command, \
-                     /* abort */               NCR53c7xx_abort,   \
-                     /* reset */               NCR53c7xx_reset,   \
-                     /* slave_attach */        NULL,            \
-                     /* bios_param */          scsicam_bios_param,   \
-                     /* can_queue */           24,       \
-                     /* this_id */             7,               \
-                     /* sg_tablesize */        127,          \
-                     /* cmd_per_lun */         3,     \
-                     /* present */             0,               \
-                     /* unchecked_isa_dma */   0,               \
-                     /* use_clustering */      DISABLE_CLUSTERING }
+#define AMIGA7XX_SCSI {name:                "Amiga NCR53c710 SCSI", \
+                      detect:              amiga7xx_detect,    \
+                      queuecommand:        NCR53c7xx_queue_command, \
+                      abort:               NCR53c7xx_abort,   \
+                      reset:               NCR53c7xx_reset,   \
+                      bios_param:          scsicam_bios_param,   \
+                      can_queue:           24,       \
+                      this_id:             7,               \
+                      sg_tablesize:        127,          \
+                      cmd_per_lun:         3,     \
+                      use_clustering:      DISABLE_CLUSTERING }
 #endif
 #endif /* AMIGA7XX_H */
index 79a1a9580cb5ca46b35cc361d90619cfa20df04e..15280b82cc9504642e30822f98f727ea53bd4295 100644 (file)
@@ -53,25 +53,19 @@ int atari_scsi_release (struct Scsi_Host *);
 
 #if defined (HOSTS_C) || defined (MODULE)
 
-#define ATARI_SCSI { NULL, NULL, NULL,                         \
-  atari_scsi_proc_info,                                                \
-  "Atari native SCSI",                                         \
-  atari_scsi_detect,                                           \
-  atari_scsi_release,                                          \
-  atari_scsi_info,                                             \
-  /* command */ NULL,                                          \
-  atari_scsi_queue_command,                                    \
-  atari_scsi_abort,                                            \
-  atari_scsi_reset,                                            \
-  /* slave_attach */   NULL,                                   \
-  /* bios_param */     NULL,                                   \
-  /* can queue */      0, /* initialized at run-time */        \
-  /* host_id */                0, /* initialized at run-time */        \
-  /* scatter gather */ 0, /* initialized at run-time */        \
-  /* cmd per lun */    0, /* initialized at run-time */        \
-  /* present */                0,                                      \
-  /* unchecked ISA DMA */ 0,                                   \
-  /* use_clustering */ DISABLE_CLUSTERING }
+#define ATARI_SCSI {    proc_info:         atari_scsi_proc_info,       \
+                       name:              "Atari native SCSI",         \
+                       detect:            atari_scsi_detect,           \
+                       release:           atari_scsi_release,          \
+                       info:              atari_scsi_info,             \
+                       queuecommand:      atari_scsi_queue_command,    \
+                       abort:             atari_scsi_abort,            \
+                       reset:             atari_scsi_reset,            \
+                       can_queue:         0, /* initialized at run-time */     \
+                       this_id:           0, /* initialized at run-time */     \
+                       sg_tablesize:      0, /* initialized at run-time */     \
+                       cmd_per_lun:       0, /* initialized at run-time */     \
+                       use_clustering:    DISABLE_CLUSTERING }
 
 #endif
 
index 1495a5d81a8a4825cab2bc4c85fba94869d0f8bb..d6c766635cb3a1fe22a4862f27d505871ff5a040 100644 (file)
@@ -3,11 +3,6 @@
  * etc.
  */
 
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
 #define __NO_VERSION__
 #include <linux/module.h>
 
index bfe20c96b836f3e231f8fc197d922b8976a20b8a..d2a7c7abd757a89fbdd3cfaf2c72ad92f6137d6d 100644 (file)
@@ -63,29 +63,22 @@ extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int lengt
 
 #ifdef VERSION_2_0_0
 
-#define DC390_T    {                   \
-       NULL,   /* *next */             \
-       NULL,   /* *usage_count */      \
-       &proc_scsi_tmscsim,     /* *proc_dir */         \
-       tmscsim_proc_info,      /* (*proc_info)() */    \
-       "Tekram DC390(T) V1.10 Dec-05-1996",  /* *name */ \
-       DC390_detect,                   \
-       DC390_release,  /* (*release)() */      \
-       NULL,   /* *(*info)() */        \
-       NULL,   /* (*command)() */      \
-       DC390_queue_command,    \
-       DC390_abort,            \
-       DC390_reset,            \
-       NULL, /* slave attach */\
-       DC390_bios_param,       \
-       10,/* can queue(-1) */  \
-       7, /* id(-1) */         \
-       SG_ALL,                 \
-       2, /* cmd per lun(2) */ \
-       0, /* present */        \
-       0, /* unchecked isa dma */ \
-       DISABLE_CLUSTERING      \
-       }
+#define DC390_T    {                             \
+   proc_dir:       &proc_scsi_tmscsim,            \
+   proc_info:      tmscsim_proc_info
+   name:           "Tekram DC390(T) V1.10 Dec-05-1996",\
+   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            \
+   }
 #endif
 
 
index 9216ac1d2d2a05ee4cfc8ae49c917b39c9b2da88..c0e15f6ea5c165cb578afa650c1922cb606ec14c 100644 (file)
@@ -57,13 +57,18 @@ int dtc_proc_info (char *buffer, char **start, off_t offset,
 
 #if defined(HOSTS_C) || defined(MODULE)
 
-#define DTC3x80 {NULL, NULL, NULL, NULL, \
-       "DTC 3180/3280 ", dtc_detect, NULL,  \
-       NULL,                                                   \
-       NULL, dtc_queue_command, dtc_abort, dtc_reset, NULL,    \
-       dtc_biosparam,                                          \
-       /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,                  \
-       /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+#define DTC3x80 {                              \
+       name:           "DTC 3180/3280 ",       \
+       detect:         dtc_detect,             \
+       queuecommand:   dtc_queue_command,      \
+       abort:          dtc_abort,              \
+       reset:          dtc_reset,              \
+       bios_param:     dtc_biosparam,          \
+       can_queue:      CAN_QUEUE,              \
+       this_id:        7,                      \
+       sg_tablesize:   SG_ALL,                 \
+       cmd_per_lun:    CMD_PER_LUN ,           \
+       use_clustering: DISABLE_CLUSTERING}
 
 #endif
 
index 8292ef5148065053973471a87861f886f9ab1fc2..0a01d00b0f36b5f9b38610468717bb685f025e12 100644 (file)
@@ -15,27 +15,16 @@ int eata2x_reset(Scsi_Cmnd *, unsigned int);
 #define EATA_VERSION "3.11.00"
 
 
-#define EATA {                                                 \
-               NULL, /* Ptr for modules */                    \
-               NULL, /* usage count for modules */            \
-               NULL,                                          \
-               NULL,                                          \
-               "EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
-               eata2x_detect,                                 \
-               eata2x_release,                                \
-               NULL,                                          \
-               NULL,                                          \
-               eata2x_queuecommand,                           \
-               eata2x_abort,                                  \
-               eata2x_reset,                                  \
-               NULL,                                          \
-               scsicam_bios_param,                            \
-               0,   /* can_queue, reset by detect */          \
-               7,   /* this_id, reset by detect */            \
-               0,   /* sg_tablesize, reset by detect */       \
-               0,   /* cmd_per_lun, reset by detect */        \
-               0,   /* number of boards present */            \
-               1,   /* unchecked isa dma, reset by detect */  \
-               ENABLE_CLUSTERING                              \
+#define EATA {                                                                 \
+               name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",      \
+               detect:            eata2x_detect,                               \
+               release:           eata2x_release,                              \
+               queuecommand:      eata2x_queuecommand,                         \
+               abort:             eata2x_abort,                                \
+               reset:             eata2x_reset,                                \
+               bios_param:        scsicam_bios_param,                          \
+               this_id:           7,   /* this_id, reset by detect */          \
+               unchecked_isa_dma: 1,   /* unchecked isa dma, reset by detect */\
+               use_clustering:    ENABLE_CLUSTERING                            \
                }
 #endif
index a23931bf9a3094496596ccf04e75de1c545d7478..616744efe98b83ad7c0e29c59b4af42d81c7d04a 100644 (file)
@@ -84,26 +84,17 @@ int eata_release(struct Scsi_Host *);
 
 #include <scsi/scsicam.h>
 
-#define EATA_DMA {                   \
-        NULL, NULL,                  \
-        NULL,               /* proc_dir_entry */ \
-        eata_proc_info,     /* procinfo       */ \
-        "EATA (Extended Attachment) HBA driver", \
-        eata_detect,                 \
-        eata_release,                \
-       NULL, NULL,                  \
-       eata_queue,                  \
-       eata_abort,                  \
-       eata_reset,                  \
-       NULL,   /* Slave attach */   \
-       scsicam_bios_param,          \
-       0,      /* Canqueue     */   \
-       0,      /* this_id      */   \
-       0,      /* sg_tablesize */   \
-       0,      /* cmd_per_lun  */   \
-       0,      /* present      */   \
-       1,      /* True if ISA  */   \
-       ENABLE_CLUSTERING }
+#define EATA_DMA {                                      \
+        proc_info:         eata_proc_info,     /* procinfo       */ \
+        name:              "EATA (Extended Attachment) HBA driver", \
+        detect:            eata_detect,                 \
+        release:           eata_release,                \
+       queuecommand:      eata_queue,                  \
+       abort:             eata_abort,                  \
+       reset:             eata_reset,                  \
+       bios_param:        scsicam_bios_param,          \
+       unchecked_isa_dma: 1,      /* True if ISA  */   \
+       use_clustering:    ENABLE_CLUSTERING }
 
 
 #endif /* _EATA_DMA_H */
index 3a3a19aa557e427a7d614ac481de2d69cfbb054c..267d8bf82a545bef62bdec765ecc5afb1978a39d 100644 (file)
@@ -439,15 +439,12 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
            goto stop_output;
     }
 
-#if 0
-    scd = scsi_devices;
-    
-    size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+    size = sprintf(buffer+len,"Attached devices: %s\n", 
+                  (HBA_ptr->host_queue)?"":"none");
     len += size; 
     pos = begin + len;
     
-    while (scd) {
-       if (scd->host == HBA_ptr) {
+    for(scd = HBA_ptr->host_queue; scd; scd = scd->next) {
            proc_print_scsidevice(scd, buffer, &size, len);
            len += size; 
            pos = begin + len;
@@ -458,10 +455,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
            }
            if (pos > offset + length)
                goto stop_output;
-       }
-       scd = scd->next;
     }
-#endif
     
  stop_output:
     DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
index 333f7c4a7696d78a56acd2c49b755f96a7edd9d5..7531e78a4a5f737ea9741e81dc0347865e7e091d 100644 (file)
@@ -74,26 +74,17 @@ int eata_pio_release(struct Scsi_Host *);
 #endif
 
 
-#define EATA_PIO {              \
-    NULL, NULL,                  \
-    NULL,               /* proc_dir_entry */ \
-    eata_pio_proc_info, /* procinfo      */ \
-    "EATA (Extended Attachment) PIO driver", \
-    eata_pio_detect,            \
-    eata_pio_release,           \
-    NULL, NULL,                         \
-    eata_pio_queue,             \
-    eata_pio_abort,             \
-    eata_pio_reset,             \
-    NULL,   /* Slave attach */  \
-    scsicam_bios_param,                 \
-    0,     /* Canqueue     */   \
-    0,     /* this_id      */   \
-    0,     /* sg_tablesize */   \
-    0,     /* cmd_per_lun  */   \
-    0,     /* present      */   \
-    1,     /* True if ISA  */   \
-    ENABLE_CLUSTERING }
+#define EATA_PIO {                                             \
+    proc_info:         eata_pio_proc_info, /* procinfo   */    \
+    name:              "EATA (Extended Attachment) PIO driver",        \
+    detect:            eata_pio_detect,                                \
+    release:           eata_pio_release,                       \
+    queuecommand:      eata_pio_queue,                         \
+    abort:             eata_pio_abort,                         \
+    reset:             eata_pio_reset,                         \
+    bios_param:        scsicam_bios_param,                     \
+    unchecked_isa_dma: 1,          /* True if ISA  */          \
+    use_clustering:    ENABLE_CLUSTERING }
 
 #endif /* _EATA_PIO_H */
 
index d98958703679dc746dd49142f04ee7ad101c80bf..8290533156660ce50288d985fca15b6f5884b455 100644 (file)
@@ -81,14 +81,12 @@ int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length,
     if (pos > offset + length)
        goto stop_output;
     
-    scd = scsi_devices;
-    
-    size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+    size = sprintf(buffer+len,"Attached devices: %s\n", 
+                  (HBA_ptr->host_queue)?"":"none");
     len += size; 
     pos = begin + len;
     
-    while (scd) {
-       if (scd->host == HBA_ptr) {
+    for(scd = HBA_ptr->host_queue; scd; scd = scd->next) {
            proc_print_scsidevice(scd, buffer, &size, len);
            len += size; 
            pos = begin + len;
@@ -99,8 +97,6 @@ int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length,
            }
            if (pos > offset + length)
                goto stop_output;
-       }
-       scd = scd->next;
     }
     
  stop_output:
index f1be3e5b4043f988958af8a23f093d3a862634af..c57d5a9a26433b5bfd0242163530972cd73e0cf8 100644 (file)
@@ -1163,7 +1163,7 @@ static int esp_host_info(struct Sparc_ESP *esp, char *ptr, off_t offset, int len
        copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
        for(i = 0; i < 15; i++) {
                if(esp->targets_present & (1 << i)) {
-                       Scsi_Device *SDptr = scsi_devices;
+                       Scsi_Device *SDptr = esp->ehost->host_queue;
 
                        while((SDptr->host != esp->ehost) &&
                              (SDptr->id != i) &&
index 23a7e35e369cb51eec1a8d580c6b1b5028a6e0fa..dcd8d894133062897cd3f033ec819e95b0450fc7 100644 (file)
@@ -395,28 +395,21 @@ extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
 
 extern struct proc_dir_entry proc_scsi_esp;
 
-#define SCSI_SPARC_ESP {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* struct module *module */                                    NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,         \
-/* const char *name */                                         "Sun ESP 100/100a/200", \
-/* int detect(struct SHT *) */                                 esp_detect,             \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *, int) */                              esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_SPARC_ESP {                                        \
+               proc_dir:       &proc_scsi_esp,                 \
+               proc_info:      &esp_proc_info,                 \
+               name:           "Sun ESP 100/100a/200",         \
+               detect:         esp_detect,                     \
+               info:           esp_info,                       \
+               command:        esp_command,                    \
+               queuecommand:   esp_queue,                      \
+               abort:          esp_abort,                      \
+               reset:          esp_reset,                      \
+               can_queue:      7,                              \
+               this_id:        7,                              \
+               sg_tablesize:   SG_ALL,                         \
+               cmd_per_lun:    1,                              \
+               use_clustering: DISABLE_CLUSTERING, }
 
 /* For our interrupt engine. */
 #define for_each_esp(esp) \
index c15255819575d707daeefcdde7c5a14ff68cb910..0983e5383439b3fd7fb0c5430825b5213fce0b94 100644 (file)
@@ -37,25 +37,17 @@ int        fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
 
 extern struct proc_dir_entry proc_scsi_fdomain;
 
-#define FDOMAIN_16X0 { NULL,                             \
-                      NULL,                             \
-                      NULL,                             \
-                      fdomain_16x0_proc_info,           \
-                      NULL,                             \
-                      fdomain_16x0_detect,              \
-                      NULL,                             \
-                      fdomain_16x0_info,                \
-                      fdomain_16x0_command,             \
-                      fdomain_16x0_queue,               \
-                      fdomain_16x0_abort,               \
-                      fdomain_16x0_reset,               \
-                      NULL,                             \
-                      fdomain_16x0_biosparam,           \
-                      1,                                \
-                      6,                                \
-                      64,                               \
-                      1,                                \
-                      0,                                \
-                      0,                                \
-                      DISABLE_CLUSTERING }
+#define FDOMAIN_16X0 { proc_info:      fdomain_16x0_proc_info,           \
+                      detect:         fdomain_16x0_detect,              \
+                      info:           fdomain_16x0_info,                \
+                      command:        fdomain_16x0_command,             \
+                      queuecommand:   fdomain_16x0_queue,               \
+                      abort:          fdomain_16x0_abort,               \
+                      reset:          fdomain_16x0_reset,               \
+                      bios_param:     fdomain_16x0_biosparam,           \
+                      can_queue:      1,                                \
+                      this_id:        6,                                \
+                      sg_tablesize:   64,                               \
+                      cmd_per_lun:    1,                                \
+                      use_clustering: DISABLE_CLUSTERING }
 #endif
index 0d65f36a9d3e9e58a31c8559f0302ee08752ecf1..006c98d8f62bf5425213827e20d8a5d01e3d1b50 100644 (file)
@@ -658,8 +658,7 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
        PRINTP("  %d pending writes" ANDP hostdata->pendingw);
     if (hostdata->pendingr || hostdata->pendingw)
        PRINTP("\n");
-    for (dev = scsi_devices; dev; dev=dev->next) {
-       if (dev->host == scsi_ptr) {
+    for (dev = scsi_ptr->host_queue; dev; dev=dev->next) {
            unsigned long br = hostdata->bytes_read[dev->id];
            unsigned long bw = hostdata->bytes_write[dev->id];
            long tr = hostdata->time_read[dev->id] / HZ;
@@ -687,7 +686,6 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
            if (tw)
                PRINTP(" @ %5ld bps" ANDP bw / tw); 
            PRINTP("\n");
-       }
     }
 #endif
        
index 2730723eb33641605fb0d08b9185767f454a66b8..00044927709c64dd331b5ff3dc3cb6b5e846f808 100644 (file)
@@ -72,16 +72,21 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
 
 #if defined(HOSTS_C) || defined(MODULE)
 
-#define GENERIC_NCR5380 {NULL, NULL, NULL,                             \
-       generic_NCR5380_proc_info,                                      \
-       "Generic NCR5380/NCR53C400 Scsi Driver",                        \
-       generic_NCR5380_detect, generic_NCR5380_release_resources,      \
-       (void *)generic_NCR5380_info, NULL,                             \
-       generic_NCR5380_queue_command, generic_NCR5380_abort,           \
-       generic_NCR5380_reset, NULL,                                    \
-       NCR5380_BIOSPARAM,                                              \
-       /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,                  \
-       /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+#define GENERIC_NCR5380 {                                              \
+       proc_info:      generic_NCR5380_proc_info,                      \
+       name:           "Generic NCR5380/NCR53C400 Scsi Driver",        \
+       detect:         generic_NCR5380_detect,                         \
+       release:        generic_NCR5380_release_resources,              \
+       info:           (void *)generic_NCR5380_info,                   \
+       queuecommand:   generic_NCR5380_queue_command,                  \
+       abort:          generic_NCR5380_abort,                          \
+       reset:          generic_NCR5380_reset,                          \
+       bios_param:     NCR5380_BIOSPARAM,                              \
+       can_queue:      CAN_QUEUE,                                      \
+        this_id:        7,                                             \
+        sg_tablesize:   SG_ALL,                                                \
+       cmd_per_lun:    CMD_PER_LUN ,                                   \
+        use_clustering: DISABLE_CLUSTERING}
 
 #endif
 
index 4e2c4774207f021b873a4fd8fa3cd46294c23ae2..ad2c3eed008361eb4199e539972cc30f93bd0443 100644 (file)
@@ -670,51 +670,26 @@ int gdth_reset(Scsi_Cmnd *);
 const char *gdth_info(struct Scsi_Host *);
 
 
-#if LINUX_VERSION_CODE >= 0x010300
 int gdth_bios_param(Disk *,kdev_t,int *);
 extern struct proc_dir_entry proc_scsi_gdth;
 int gdth_proc_info(char *,char **,off_t,int,int,int);
-#define GDTH { NULL, NULL,                              \
-                   &proc_scsi_gdth,                     \
-                   gdth_proc_info,                      \
-                   "GDT SCSI Disk Array Controller",    \
-                   gdth_detect,                         \
-                   gdth_release,                        \
-                   gdth_info,                           \
-                   gdth_command,                        \
-                   gdth_queuecommand,                   \
-                   gdth_abort,                          \
-                   gdth_reset,                          \
-                   NULL,                                \
-                   gdth_bios_param,                     \
-                   GDTH_MAXCMDS,                        \
-                   -1,                                  \
-                   GDTH_MAXSG,                          \
-                   GDTH_MAXC_P_L,                       \
-                   0,                                   \
-                   1,                                   \
-                   ENABLE_CLUSTERING}
-#else
-int gdth_bios_param(Disk *,int,int *);
-#define GDTH { NULL, NULL,                              \
-                   "GDT SCSI Disk Array Controller",    \
-                   gdth_detect,                         \
-                   gdth_release,                        \
-                   gdth_info,                           \
-                   gdth_command,                        \
-                   gdth_queuecommand,                   \
-                   gdth_abort,                          \
-                   gdth_reset,                          \
-                   NULL,                                \
-                   gdth_bios_param,                     \
-                   GDTH_MAXCMDS,                        \
-                   -1,                                  \
-                   GDTH_MAXSG,                          \
-                   GDTH_MAXC_P_L,                       \
-                   0,                                   \
-                   1,                                   \
-                   ENABLE_CLUSTERING}
-#endif
+#define GDTH { proc_dir:          &proc_scsi_gdth,                     \
+               proc_info:         gdth_proc_info,                      \
+               name:              "GDT SCSI Disk Array Controller",    \
+               detect:            gdth_detect,                         \
+               release:           gdth_release,                        \
+               info:              gdth_info,                           \
+               command:           gdth_command,                        \
+               queuecommand:      gdth_queuecommand,                   \
+               abort:             gdth_abort,                          \
+               reset:             gdth_reset,                          \
+               bios_param:        gdth_bios_param,                     \
+               can_queue:         GDTH_MAXCMDS,                        \
+               this_id:           -1,                                  \
+               sg_tablesize:      GDTH_MAXSG,                          \
+               cmd_per_lun:       GDTH_MAXC_P_L,                       \
+               unchecked_isa_dma: 1,                                   \
+               use_clustering:    ENABLE_CLUSTERING}
 
 #endif
 
index 77004d0d397ebe457828748f293820b77bcbdf54..d03886baa11384fde175d4abd0abdae38ef73990 100644 (file)
@@ -34,27 +34,18 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
 extern struct proc_dir_entry proc_scsi_gvp11;
 
-#define GVP11_SCSI {  /* next */                NULL,            \
-                     /* module */              NULL,            \
-                      /* proc_dir_entry */      &proc_scsi_gvp11, \
-                     /* proc_info */           NULL,            \
-                     /* name */                "GVP Series II SCSI", \
-                     /* detect */              gvp11_detect,    \
-                     /* release */             gvp11_release,   \
-                     /* info */                NULL,            \
-                     /* command */             NULL,            \
-                     /* queuecommand */        wd33c93_queuecommand, \
-                     /* abort */               wd33c93_abort,   \
-                     /* reset */               wd33c93_reset,   \
-                     /* slave_attach */        NULL,            \
-                     /* bios_param */          NULL,            \
-                     /* can_queue */           CAN_QUEUE,       \
-                     /* this_id */             7,               \
-                     /* sg_tablesize */        SG_ALL,          \
-                     /* cmd_per_lun */         CMD_PER_LUN,     \
-                     /* present */             0,               \
-                     /* unchecked_isa_dma */   0,               \
-                     /* use_clustering */      DISABLE_CLUSTERING }
+#define GVP11_SCSI {  proc_dir:                   &proc_scsi_gvp11, \
+                     name:                "GVP Series II SCSI", \
+                     detect:              gvp11_detect,    \
+                     release:             gvp11_release,   \
+                     queuecommand:        wd33c93_queuecommand, \
+                     abort:               wd33c93_abort,   \
+                     reset:               wd33c93_reset,   \
+                     can_queue:           CAN_QUEUE,       \
+                     this_id:             7,               \
+                     sg_tablesize:        SG_ALL,          \
+                     cmd_per_lun:         CMD_PER_LUN,     \
+                     use_clustering:      DISABLE_CLUSTERING }
 #else
 
 /*
index c871f93b23a0c7f7748ff6cd99123626e80d1d80..cf5a87814d31366d30a3cf391cb9ae6590a08260 100644 (file)
  *  hosts currently present in the system.
  */
 
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
 #define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
 #include "scsi.h"
 
 #ifndef NULL
@@ -433,7 +432,9 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
     struct Scsi_Host * retval, *shpnt;
     retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
                                                  (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
+    atomic_set(&retval->host_active,0);
     retval->host_busy = 0;
+    retval->host_failed = 0;
     retval->block = NULL;
     retval->wish_block = 0;
     if(j > 0xffff) panic("Too many extra bytes requested\n");
@@ -456,6 +457,16 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
     retval->io_port = 0;
     retval->hostt = tpnt;
     retval->next = NULL;
+    retval->in_recovery = 0;
+    retval->ehandler = NULL;    /* Initial value until the thing starts up. */
+    retval->eh_notify   = NULL;    /* Who we notify when we exit. */
+
+    /*
+     * Initialize the fields used for mid-level queueing.
+     */
+    retval->pending_commands = NULL;
+    retval->host_busy = FALSE;
+
 #ifdef DEBUG
     printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
 #endif
@@ -542,6 +553,25 @@ __initfunc(unsigned int scsi_init(void))
            name = shpnt->hostt->name;
        printk ("scsi%d : %s\n", /* And print a little message */
                shpnt->host_no, name);
+
+        /*
+         * Now start the error recovery thread for the host.
+         */
+        if( shpnt->hostt->use_new_eh_code )
+        {
+            struct semaphore sem = MUTEX_LOCKED;
+            
+            shpnt->eh_notify = &sem;
+
+            kernel_thread((int (*)(void *))scsi_error_handler, 
+                          (void *) shpnt, 0);
+            /*
+             * Now wait for the kernel error thread to initialize itself
+             * as it might be needed when we scan the bus.
+             */
+            down (&sem);
+            shpnt->eh_notify = NULL;
+        }
     }
     
     printk ("scsi : %d host%s.\n", next_scsi_host,
index d7e366350a0416afb5e7c68366874273330bb23f..4d1b095c2f5ffe021f10576fc6f4651f0c8dcffc 100644 (file)
@@ -127,9 +127,33 @@ typedef struct     SHT
      * # and exit result when the command is complete.
      * Host number is the POSITION IN THE hosts array of THIS
      * host adapter.
+     *
+     * The done() function must only be called after QueueCommand() 
+     * has returned.
      */
     int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 
+    /*
+     * This is an error handling strategy routine.  You don't need to
+     * define one of these if you don't want to - there is a default
+     * routine that is present that should work in most cases.  For those
+     * driver authors that have the inclination and ability to write their
+     * own strategy routine, this is where it is specified.  Note - the
+     * strategy routine is *ALWAYS* run in the context of the kernel eh
+     * thread.  Thus you are guaranteed to *NOT* be in an interrupt handler
+     * when you execute this, and you are also guaranteed to *NOT* have any
+     * other commands being queued while you are in the strategy routine.
+     * When you return from this function, operations return to normal.
+     *
+     * See scsi_error.c scsi_unjam_host for additional comments about what
+     * this function should and should not be attempting to do.
+     */
+     int (*eh_strategy_handler)(struct Scsi_Host *);
+     int (*eh_abort_handler)(Scsi_Cmnd *);
+     int (*eh_device_reset_handler)(Scsi_Cmnd *);
+     int (*eh_bus_reset_handler)(Scsi_Cmnd *);
+     int (*eh_host_reset_handler)(Scsi_Cmnd *);
+
     /*
      * Since the mid level driver handles time outs, etc, we want to
      * be able to abort the current command.  Abort returns 0 if the
@@ -143,6 +167,9 @@ typedef struct      SHT
      *
      * Note that the scsi driver should "clean up" after itself,
      * resetting the bus, etc. if necessary.
+     *
+     * NOTE - this interface is depreciated, and will go away.  Use
+     * the eh_ routines instead.
      */
     int (* abort)(Scsi_Cmnd *);
 
@@ -155,6 +182,9 @@ typedef struct      SHT
      * the first place.         Some hosts do not implement a reset function,
      * and these hosts must call scsi_request_sense(SCpnt) to keep
      * the command alive.
+     *
+     * NOTE - this interface is depreciated, and will go away.  Use
+     * the eh_ routines instead.
      */
     int (* reset)(Scsi_Cmnd *, unsigned int);
 
@@ -227,6 +257,13 @@ typedef struct     SHT
      */
     unsigned use_clustering:1;
 
+    /*
+     * True if this driver uses the new error handling code.  This flag is
+     * really only temporary until all of the other drivers get converted
+     * to use the new error handling code.
+     */
+    unsigned use_new_eh_code:1;
+
 } Scsi_Host_Template;
 
 /*
@@ -240,14 +277,40 @@ typedef struct    SHT
 
 struct Scsi_Host
 {
-    struct Scsi_Host * next;
+/* private: */
+    /*
+     * This information is private to the scsi mid-layer.  Wrapping it in a
+     * struct private is a way of marking it in a sort of C++ type of way.
+     */
+    struct Scsi_Host      * next;
+    Scsi_Device           * host_queue;
+    /*
+     * List of commands that have been rejected because either the host
+     * or the device was busy.  These need to be retried relatively quickly,
+     * but we need to hold onto it for a short period until the host/device
+     * is available.
+     */
+    Scsi_Cmnd             * pending_commands;
+
+    struct task_struct    * ehandler;  /* Error recovery thread. */
+    struct semaphore      * eh_wait;   /* The error recovery thread waits on
+                                          this. */
+    struct semaphore      * eh_notify; /* wait for eh to begin */
+    struct semaphore      * eh_action; /* Wait for specific actions on the
+                                          host. */
+    unsigned int            eh_active:1; /* Indicates the eh thread is awake and active if
+                                          this is true. */
+    struct wait_queue     * host_wait;
+    Scsi_Host_Template    * hostt;
+    atomic_t                host_active; /* commands checked out */
+    volatile unsigned short host_busy;   /* commands actually active on low-level */
+    volatile unsigned short host_failed; /* commands that failed. */
+    
+/* public: */
     unsigned short extra_bytes;
-    volatile unsigned char host_busy;
-    char host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
+    unsigned short host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
     unsigned long last_reset;
-    struct wait_queue *host_wait;
-    Scsi_Cmnd *host_queue;
-    Scsi_Host_Template * hostt;
+
 
     /*
      * These three parameters can be used to allow for wide scsi,
@@ -292,6 +355,8 @@ struct Scsi_Host
     int can_queue;
     short cmd_per_lun;
     short unsigned int sg_tablesize;
+
+    unsigned in_recovery:1;
     unsigned unchecked_isa_dma:1;
     unsigned use_clustering:1;
     /*
@@ -299,6 +364,11 @@ struct Scsi_Host
      */
     unsigned loaded_as_module:1;
 
+    /*
+     * Host has rejected a command because it was busy.
+     */
+    unsigned host_blocked:1;
+
     void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
     unsigned long hostdata[0];  /* Used for storage of host specific stuff */
index 4306f52acb860abdef63c20f7ba14a10b23f00da..c858b5935f8be24c79c5d256ec34b1bbacef266e 100644 (file)
@@ -19,28 +19,22 @@ int ibmmca_biosparam (Disk *, kdev_t, int *);
 extern struct proc_dir_entry proc_scsi_ibmmca;
 
 /*initialization for Scsi_host_template type */
-#define IBMMCA {                                      \
-          NULL,                 /*next*/              \
-          NULL,                 /*usage_count*/       \
-          &proc_scsi_ibmmca,    /*proc_dir*/          \
-          ibmmca_proc_info,     /*proc info fn*/      \
-          "IBMMCA",             /*name*/              \
-          ibmmca_detect,        /*detect fn*/         \
-          ibmmca_release,       /*release fn*/        \
-          NULL,                 /*info fn*/           \
-          ibmmca_command,       /*command fn*/        \
-          ibmmca_queuecommand,  /*queuecommand fn*/   \
-          ibmmca_abort,         /*abort fn*/          \
-          ibmmca_reset,         /*reset fn*/          \
-          NULL,                 /*slave_attach fn*/   \
-          ibmmca_biosparam,     /*bios fn*/           \
-          16,                   /*can_queue*/         \
-          7,                    /*set by detect*/     \
-          16,                   /*sg_tablesize*/      \
-          1,                    /*cmd_per_lun*/       \
-          0,                    /*present*/           \
-          0,                    /*unchecked_isa_dma*/ \
-          ENABLE_CLUSTERING     /*use_clustering*/    \
+#define IBMMCA {                                                     \
+          proc_dir:       &proc_scsi_ibmmca,    /*proc_dir*/          \
+         proc_info:      ibmmca_proc_info,     /*proc info fn*/      \
+          name:           "IBMMCA",             /*name*/              \
+          detect:         ibmmca_detect,        /*detect fn*/         \
+          release:        ibmmca_release,       /*release fn*/        \
+          command:        ibmmca_command,       /*command fn*/        \
+          queuecommand:   ibmmca_queuecommand,  /*queuecommand fn*/   \
+          abort:          ibmmca_abort,         /*abort fn*/          \
+          reset:          ibmmca_reset,         /*reset fn*/          \
+          bios_param:     ibmmca_biosparam,     /*bios fn*/           \
+          can_queue:      16,                   /*can_queue*/         \
+          this_id:        7,                    /*set by detect*/     \
+          sg_tablesize:   16,                   /*sg_tablesize*/      \
+          cmd_per_lun:    1,                    /*cmd_per_lun*/       \
+          use_clustering: ENABLE_CLUSTERING     /*use_clustering*/    \
         }
 
 #endif /* _IBMMCA_H */
index 2ccbc3c03150e7e43166ac5c612901db94cd654c..360850d75967a2975deea7316896e53199cd5eef 100644 (file)
@@ -15,28 +15,20 @@ extern int idescsi_abort (Scsi_Cmnd *cmd);
 extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
 extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
 
-#define IDESCSI                                                                \
-{      NULL,                   /* next         */                      \
-       NULL,                   /* module       */                      \
-       NULL,                   /* proc_dir     */                      \
-       NULL,                   /* proc_info    */                      \
-       "idescsi",              /* name         */                      \
-       idescsi_detect,         /* detect       */                      \
-       idescsi_release,        /* release      */                      \
-       idescsi_info,           /* info         */                      \
-       NULL,                   /* command      */                      \
-       idescsi_queue,          /* queuecommand */                      \
-       idescsi_abort,          /* abort        */                      \
-       idescsi_reset,          /* reset        */                      \
-       NULL,                   /* slave_attach */                      \
-       idescsi_bios,           /* bios_param   */                      \
-       10,                     /* can_queue    */                      \
-       -1,                     /* this_id      */                      \
-       256,                    /* sg_tablesize */                      \
-       5,                      /* cmd_per_lun  */                      \
-       0,                      /* present      */                      \
-       0,                      /* isa_dma      */                      \
-       DISABLE_CLUSTERING      /* clustering   */                      \
+#define IDESCSI  {                                                             \
+       name:            "idescsi",             /* name         */              \
+       detect:          idescsi_detect,        /* detect       */              \
+       release:         idescsi_release,       /* release      */              \
+       info:            idescsi_info,          /* info         */              \
+       queuecommand:    idescsi_queue,         /* queuecommand */              \
+       abort:           idescsi_abort,         /* abort        */              \
+       reset:           idescsi_reset,         /* reset        */              \
+       bios_param:      idescsi_bios,          /* bios_param   */              \
+       can_queue:       10,                    /* can_queue    */              \
+       this_id:         -1,                    /* this_id      */              \
+       sg_tablesize:    256,                   /* sg_tablesize */              \
+       cmd_per_lun:     5,                     /* cmd_per_lun  */              \
+       use_clustering:  DISABLE_CLUSTERING     /* clustering   */              \
 }
 
 #endif /* IDESCSI_H */
index bb75a08c58672e258b677edbe5b5b2150d924de2..557ca60e857f930d7d2e9821c9069718240d428d 100644 (file)
@@ -392,28 +392,21 @@ int in2000_reset(Scsi_Cmnd *, unsigned int);
 #define IN2000_CPL      2
 #define IN2000_HOST_ID  7
 
-#define IN2000 {  NULL,                /* link pointer for modules */ \
-                  NULL,                /* usage_count for modules */ \
-                  &proc_scsi_in2000,   /* pointer to /proc/scsi directory entry */ \
-                  in2000_proc_info,    /* pointer to proc info function */ \
-                  "Always IN2000",     /* device name */ \
-                  in2000_detect,       /* returns number of in2000's found */ \
-                  NULL,                /* optional unload function for modules */ \
-                  NULL,                /* optional misc info function */ \
-                  NULL,                /* send scsi command, wait for completion */ \
-                  in2000_queuecommand, /* queue scsi command, don't wait */ \
-                  in2000_abort,        /* abort current command */ \
-                  in2000_reset,        /* reset scsi bus */ \
-                  NULL,                /* slave_attach - unused */ \
-                  in2000_biosparam,    /* figures out BIOS parameters for lilo, etc */ \
-                  IN2000_CAN_Q,        /* max commands we can queue up */ \
-                  IN2000_HOST_ID,      /* host-adapter scsi id */ \
-                  IN2000_SG,           /* scatter-gather table size */ \
-                  IN2000_CPL,          /* commands per lun */ \
-                  0,                   /* board counter */ \
-                  0,                   /* unchecked dma */ \
-                  DISABLE_CLUSTERING \
-               }
+#define IN2000 {  proc_dir:        &proc_scsi_in2000,   /* pointer to /proc/scsi directory entry */ \
+                  proc_info:       in2000_proc_info,    /* pointer to proc info function */ \
+                  name:            "Always IN2000",     /* device name */ \
+                  detect:          in2000_detect,       /* returns number of in2000's found */ \
+                  queuecommand:    in2000_queuecommand, /* queue scsi command, don't wait */ \
+                  abort:           in2000_abort,        /* abort current command */ \
+                  reset:           in2000_reset,        /* reset scsi bus */ \
+                  bios_param:      in2000_biosparam,    /* figures out BIOS parameters for lilo, etc */ \
+                  can_queue:       IN2000_CAN_Q,        /* max commands we can queue up */ \
+                  this_id:         IN2000_HOST_ID,      /* host-adapter scsi id */ \
+                  sg_tablesize:    IN2000_SG,           /* scatter-gather table size */ \
+                  cmd_per_lun:     IN2000_CPL,          /* commands per lun */ \
+                  use_clustering:  DISABLE_CLUSTERING, \
+                 use_new_eh_code: 0                    /* Enable new error code */ \
+                }
 
 
 #endif /* IN2000_H */
index b423b0c9fc663e9ef065008b18d2136145ccbad0..914e89cf9b61f39af25005f5b9471f54feb93e15 100644 (file)
@@ -16,27 +16,18 @@ int mac53c94_abort(Scsi_Cmnd *);
 int mac53c94_reset(Scsi_Cmnd *, unsigned int);
 
 #define SCSI_MAC53C94 {                                        \
-       NULL,                   /* next */              \
-       NULL,                   /* usage_count */       \
-       &proc_scsi_mac53c94,    /* proc_dir */          \
-       NULL,                   /* proc_info */         \
-       "53C94",                /* name */              \
-       mac53c94_detect,        /* detect */            \
-       NULL,                   /* release */           \
-       NULL,                   /* info */              \
-       mac53c94_command,       /* command */           \
-       mac53c94_queue,         /* queuecommand */      \
-       mac53c94_abort,         /* abort */             \
-       mac53c94_reset,         /* reset */             \
-       NULL,                   /* slave_attach */      \
-       NULL,                   /* bios_param */        \
-       1,                      /* can_queue */         \
-       7,                      /* this_id */           \
-       SG_ALL,                 /* sg_tablesize */      \
-       1,                      /* cmd_per_lun */       \
-       0,                      /* present */           \
-       0,                      /* unchecked_isa_dma */ \
-       DISABLE_CLUSTERING,     /* use_clustering */    \
+       proc_dir:       &proc_scsi_mac53c94,            \
+       name:           "53C94",                        \
+       detect:         mac53c94_detect,                \
+       command:        mac53c94_command,               \
+       queuecommand:   mac53c94_queue,                 \
+       abort:          mac53c94_abort,                 \
+       reset:          mac53c94_reset,                 \
+       can_queue:      1,                              \
+       this_id:        7,                              \
+       sg_tablesize:   SG_ALL,                         \
+       cmd_per_lun:    1,                              \
+       use_clustering: DISABLE_CLUSTERING,             \
 }
 
 /*
index c808cc58a009906bdb5ef18f9e75abee930cfa6d..6627de4bd16a2730c6c5aa46a23c38e881a62f55 100644 (file)
@@ -16,27 +16,18 @@ int mesh_abort(Scsi_Cmnd *);
 int mesh_reset(Scsi_Cmnd *, unsigned int);
 
 #define SCSI_MESH {                                    \
-       NULL,                   /* next */              \
-       NULL,                   /* usage_count */       \
-       &proc_scsi_mesh,        /* proc_dir */          \
-       NULL,                   /* proc_info */         \
-       "MESH",                 /* name */              \
-       mesh_detect,            /* detect */            \
-       NULL,                   /* release */           \
-       NULL,                   /* info */              \
-       mesh_command,           /* command */           \
-       mesh_queue,             /* queuecommand */      \
-       mesh_abort,             /* abort */             \
-       mesh_reset,             /* reset */             \
-       NULL,                   /* slave_attach */      \
-       NULL,                   /* bios_param */        \
-       20,                     /* can_queue */         \
-       7,                      /* this_id */           \
-       SG_ALL,                 /* sg_tablesize */      \
-       2,                      /* cmd_per_lun */       \
-       0,                      /* present */           \
-       0,                      /* unchecked_isa_dma */ \
-       DISABLE_CLUSTERING,     /* use_clustering */    \
+       proc_dir:       &proc_scsi_mesh,                \
+       name:           "MESH",                         \
+       detect:         mesh_detect,                    \
+       command:        mesh_command,                   \
+       queuecommand:   mesh_queue,                     \
+       abort:          mesh_abort,                     \
+       reset:          mesh_reset,                     \
+       can_queue:      20,                             \
+       this_id:        7,                              \
+       sg_tablesize:   SG_ALL,                         \
+       cmd_per_lun:    2,                              \
+       use_clustering: DISABLE_CLUSTERING,             \
 }
 
 /*
index 0f8cb78764527cac74ceef94544108bbeb75e5e3..ef7321b2af9d6de3e0eb8e55ecbebdc54f9d12e5 100644 (file)
@@ -290,28 +290,19 @@ int ncr53c8xx_release(struct Scsi_Host *);
 #define ncr53c8xx_release NULL
 #endif
 
-#if    LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-
-#define NCR53C8XX {NULL,NULL,NULL,NULL,SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect,\
-       ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL,             \
-       ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset,      \
-        NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\
-       /* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN,             \
-        /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
-
-
-#else
-
-
-#define NCR53C8XX {NULL, NULL, SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect,\
-       ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL,             \
-       ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset,      \
-        NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\
-       /* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN,             \
-        /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
-
-#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) */
-
+#define NCR53C8XX {     name:           SCSI_NCR_DRIVER_NAME,  \
+                       detect:         ncr53c8xx_detect,       \
+                       release:        ncr53c8xx_release,      \
+                       queuecommand:   ncr53c8xx_queue_command,\
+                       abort:          ncr53c8xx_abort,        \
+                       reset:          ncr53c8xx_reset,        \
+                       bios_param:     scsicam_bios_param,     \
+                       can_queue:      SCSI_NCR_CAN_QUEUE,     \
+                       this_id:        7,                      \
+                       sg_tablesize:   SCSI_NCR_SG_TABLESIZE,  \
+                       cmd_per_lun:    SCSI_NCR_CMD_PER_LUN,   \
+                       use_clustering: DISABLE_CLUSTERING} 
+  
 #endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
 
index a1bda1fa60178db4d291eaeede490ed178e895f5..308f2647353c2733a89f0db9c525761512b4bd9e 100644 (file)
@@ -142,13 +142,18 @@ int pas16_proc_info (char *buffer ,char **start, off_t offset,
 
 #if defined(HOSTS_C) || defined(MODULE)
 
-#define MV_PAS16 {NULL, NULL, NULL, NULL, \
-       "Pro Audio Spectrum-16 SCSI",           \
-       pas16_detect, NULL, NULL,                                       \
-       NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL,      \
-       pas16_biosparam,                                                \
-       /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,                  \
-       /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+#define MV_PAS16 {                                     \
+       name:           "Pro Audio Spectrum-16 SCSI",   \
+       detect:         pas16_detect,                   \
+       queuecommand:   pas16_queue_command,            \
+       abort:          pas16_abort,                    \
+       reset:          pas16_reset,                    \
+       bios_param:     pas16_biosparam,                \
+       can_queue:      CAN_QUEUE,                      \
+       this_id:        7,                              \
+       sg_tablesize:   SG_ALL,                         \
+       cmd_per_lun:    CMD_PER_LUN ,                   \
+       use_clustering: DISABLE_CLUSTERING}
 
 #endif
 #ifndef HOSTS_C
index ded993958ec5c58552fd136d0b072e6336e78b68..415cc8794141d1d1099e4f4f4fdcc7cd99b0d63b 100644 (file)
@@ -202,25 +202,18 @@ int Pci2000_BiosParam             (Disk *disk, kdev_t dev, int geom[]);
 
 extern struct proc_dir_entry Proc_Scsi_Pci2000;
 
-#define PCI2000 { NULL, NULL,                                                  \
-                       &Proc_Scsi_Pci2000,/* proc_dir_entry */         \
-                       NULL,                                                           \
-                       "PCI-2000 SCSI Intelligent Disk Controller",\
-                       Pci2000_Detect,                                                         \
-                       NULL,                                                                           \
-                       NULL,                                                                           \
-                       Pci2000_Command,                                                        \
-                       Pci2000_QueueCommand,                                           \
-                       Pci2000_Abort,                                                          \
-                       Pci2000_Reset,                                                          \
-                       NULL,                                                                           \
-                       Pci2000_BiosParam,                                      \
-                       16,                                                                             \
-                       -1,                                                                             \
-                       16,                                                                                     \
-                       1,                                                                                      \
-                       0,                                                                                      \
-                       0,                                                                                      \
-                       DISABLE_CLUSTERING }
+#define PCI2000 { proc_dir:       &Proc_Scsi_Pci2000,/* proc_dir_entry */ \
+                 name:           "PCI-2000 SCSI Intelligent Disk Controller",\
+                 detect:         Pci2000_Detect,                       \
+                 command:        Pci2000_Command,                      \
+                 queuecommand:   Pci2000_QueueCommand,                 \
+                 abort:          Pci2000_Abort,                        \
+                 reset:          Pci2000_Reset,                        \
+                 biosparam:      Pci2000_BiosParam,                    \
+                 can_queue:      16,                                   \
+                 this_id:        -1,                                   \
+                 sg_tablesize:   16,                                   \
+                 cmd_per_lun:    1,                                    \
+                 use_clustering: DISABLE_CLUSTERING }
 
 #endif
index 0fafc26489ac6f4398038c9fb46cd13de4b6888c..1658135be1a736dc8f63a788201bf3a5b8a1d216 100644 (file)
@@ -321,25 +321,18 @@ int Pci2220i_BiosParam            (Disk *disk, kdev_t dev, int geom[]);
 
 extern struct proc_dir_entry Proc_Scsi_Pci2220i;
 
-#define PCI2220I { NULL, NULL,                                         \
-                       &Proc_Scsi_Pci2220i,/* proc_dir_entry */        \
-                       NULL,                                                   \
-                       "PCI-2220I EIDE Disk Controller",               \
-                       Pci2220i_Detect,                                                        \
-                       NULL,                                                                   \
-                       NULL,                                                                   \
-                       Pci2220i_Command,                                               \
-                       Pci2220i_QueueCommand,                                  \
-                       Pci2220i_Abort,                                                 \
-                       Pci2220i_Reset,                                                 \
-                       NULL,                                                                   \
-                       Pci2220i_BiosParam,                             \
-                       1,                                                                              \
-                       -1,                                                                     \
-                       SG_NONE,                                                                \
-                       1,                                                                              \
-                       0,                                                                              \
-                       0,                                                                              \
-                       DISABLE_CLUSTERING }
+#define PCI2220I { proc_dir:       &Proc_Scsi_Pci2220i,/* proc_dir_entry */ \
+                 name:           "PCI-2220I EIDE Disk Controller",\
+                 detect:         Pci2220i_Detect,                      \
+                 command:        Pci2220i_Command,                     \
+                 queuecommand:   Pci2220i_QueueCommand,                \
+                 abort:          Pci2220i_Abort,                       \
+                 reset:          Pci2220i_Reset,                       \
+                 biosparam:      Pci2220i_BiosParam,                   \
+                 can_queue:      1,                                    \
+                 this_id:        -1,                                   \
+                 sg_tablesize:   SG_NONE,                              \
+                 cmd_per_lun:    1,                                    \
+                 use_clustering: DISABLE_CLUSTERING }
 
 #endif
index ea86dd17ed592657f83e323e3951e7adbb6ffae9..e71228a7653ea7e73985bdbebdad0910003438d4 100644 (file)
@@ -152,26 +152,19 @@ int ppa_reset(Scsi_Cmnd *, unsigned int);
 int ppa_proc_info(char *, char **, off_t, int, int, int);
 int ppa_biosparam(Disk *, kdev_t, int *);
 
-#define PPA {  /* next */              0, \
-               /* usage_count */       0, \
-               /* proc_dir */          &proc_scsi_ppa, \
-               /* proc_info */         ppa_proc_info, \
-               /* name */              "Iomega parport ZIP drive", \
-               /* detect */            ppa_detect, \
-               /* release */           ppa_release, \
-               /* info */              0, \
-               /* command */           ppa_command, \
-               /* queuecommand */      ppa_queuecommand, \
-               /* abort */             ppa_abort, \
-               /* reset */             ppa_reset, \
-               /* slave_attach */      0, \
-               /* bios_param */        ppa_biosparam, \
-               /* can_queue */         0, \
-               /* this_id */           -1, \
-               /* sg_tablesize */      SG_ALL, \
-               /* cmd_per_lun */       1, \
-               /* present */           0, \
-               /* unchecked_isa_dma */ 0, \
-               /* use_clustering */    ENABLE_CLUSTERING \
+#define PPA {  proc_dir:               &proc_scsi_ppa,                 \
+               proc_info:              ppa_proc_info,                  \
+               name:                   "Iomega parport ZIP drive",     \
+               detect:                 ppa_detect,                     \
+               release:                ppa_release,                    \
+               command:                ppa_command,                    \
+               queuecommand:           ppa_queuecommand,               \
+               abort:                  ppa_abort,                      \
+               reset:                  ppa_reset,                      \
+               bios_param:             ppa_biosparam,                  \
+               this_id:                -1,                             \
+               sg_tablesize:           SG_ALL,                         \
+               cmd_per_lun:            1,                              \
+               use_clustering:         ENABLE_CLUSTERING               \
 }
 #endif                         /* _PPA_H */
index 282ee1bb0f0db4e6531cb0fa6858d4980695c683..0580c758cdebec229eed4ac85cb57913990696b8 100644 (file)
@@ -320,25 +320,18 @@ int Psi240i_BiosParam             (Disk *disk, kdev_t dev, int geom[]);
 
 extern struct proc_dir_entry Proc_Scsi_Psi240i;
 
-#define PSI240I { NULL, NULL,                                          \
-                       &Proc_Scsi_Psi240i,/* proc_dir_entry */ \
-                       NULL,                                                   \
-                       "PSI-240I EIDE Disk Controller",                \
-                       Psi240i_Detect,                                                 \
-                       NULL,                                                                   \
-                       NULL,                                                                   \
-                       Psi240i_Command,                                                \
-                       Psi240i_QueueCommand,                                   \
-                       Psi240i_Abort,                                                  \
-                       Psi240i_Reset,                                                  \
-                       NULL,                                                                   \
-                       Psi240i_BiosParam,                              \
-                       1,                                                                              \
-                       -1,                                                                     \
-                       SG_NONE,                                                                \
-                       1,                                                                              \
-                       0,                                                                              \
-                       0,                                                                              \
-                       DISABLE_CLUSTERING }
+#define PSI240I { proc_dir:       &Proc_Scsi_Psi240i,/* proc_dir_entry */ \
+                 name:           "PSI-240I EIDE Disk Controller",\
+                 detect:         Psi240i_Detect,                       \
+                 command:        Psi240i_Command,                      \
+                 queuecommand:   Psi240i_QueueCommand,         \
+                 abort:          Psi240i_Abort,                        \
+                 reset:          Psi240i_Reset,                        \
+                 biosparam:      Psi240i_BiosParam,                    \
+                 can_queue:      1,                                    \
+                 this_id:        -1,                                   \
+                 sg_tablesize:   SG_NONE,                              \
+                 cmd_per_lun:    1,                                    \
+                 use_clustering: DISABLE_CLUSTERING }
 
 #endif
index 4dc16df097c70761be4482725617cb3893488a6b..233408c2449322837273362669ccf445d0f11eb8 100644 (file)
@@ -14,27 +14,18 @@ int qlogicfas_biosparam(Disk *, kdev_t, int[]);
 #endif
 
 #define QLOGICFAS {            \
-       NULL,                   \
-       NULL,                   \
-       NULL,                   \
-       NULL,                   \
-       NULL,                   \
-       qlogicfas_detect,       \
-       NULL,                   \
-       qlogicfas_info,         \
-       qlogicfas_command,      \
-       qlogicfas_queuecommand, \
-       qlogicfas_abort,        \
-       qlogicfas_reset,        \
-       NULL,                   \
-       qlogicfas_biosparam,    \
-       0,                      \
-       -1,                     \
-       SG_ALL,                 \
-       1,                      \
-       0,                      \
-       0,                      \
-       DISABLE_CLUSTERING      \
+       detect:         qlogicfas_detect,       \
+       info:           qlogicfas_info,         \
+       command:        qlogicfas_command,      \
+       queuecommand:   qlogicfas_queuecommand, \
+       abort:          qlogicfas_abort,        \
+       reset:          qlogicfas_reset,        \
+       bios_param:     qlogicfas_biosparam,    \
+       can_queue:      0,                      \
+       this_id:        -1,                     \
+       sg_tablesize:   SG_ALL,                 \
+       cmd_per_lun:    1,                      \
+       use_clustering: DISABLE_CLUSTERING      \
 }
 
 #endif /* _QLOGICFAS_H */
index 7bc9ef26b00ee58a2f9a608d98f766172aa5867a..aaba51fe0015b2d90efb5937c01415db0e0ad19a 100644 (file)
@@ -73,27 +73,20 @@ int isp1020_biosparam(Disk *, kdev_t, int[]);
 extern struct proc_dir_entry proc_scsi_isp1020;
 
 #define QLOGICISP {                                                       \
-       /* next */              NULL,                                      \
-       /* module */            NULL,                                      \
-       /* proc dir */          NULL,                                      \
-       /* procfs info */       NULL,                                      \
-       /* name */              NULL,                                      \
-       /* detect */            isp1020_detect,                            \
-       /* release */           isp1020_release,                           \
-       /* info */              isp1020_info,                              \
-       /* command */           NULL,                                      \
-       /* queuecommand */      isp1020_queuecommand,                      \
-       /* abort */             isp1020_abort,                             \
-       /* reset */             isp1020_reset,                             \
-       /* slave_attach */      NULL,                                      \
-       /* bios_param */        isp1020_biosparam,                         \
-       /* can_queue */         QLOGICISP_REQ_QUEUE_LEN,                   \
-       /* this_id */           -1,                                        \
-       /* sg_tablesize */      QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
-       /* cmd_per_lun */       1,                                         \
-       /* present */           0,                                         \
-       /* unchecked_isa_dma */ 0,                                         \
-       /* use_clustering */    DISABLE_CLUSTERING                         \
+       detect:                 isp1020_detect,                            \
+       release:                isp1020_release,                           \
+       info:                   isp1020_info,                              \
+       queuecommand:           isp1020_queuecommand,                      \
+       abort:                  isp1020_abort,                             \
+       reset:                  isp1020_reset,                             \
+       bios_param:             isp1020_biosparam,                         \
+       can_queue:              QLOGICISP_REQ_QUEUE_LEN,                   \
+       this_id:                -1,                                        \
+       sg_tablesize:           QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
+       cmd_per_lun:            1,                                         \
+       present:                0,                                         \
+       unchecked_isa_dma:      0,                                         \
+       use_clustering:         DISABLE_CLUSTERING                         \
 }
 
 #endif /* _QLOGICISP_H */
index dc60c4be400f49328f6e40f73f406ac9576d4b01..d35f4edb09e0675c798c9c860e2e00d82e8f6407 100644 (file)
@@ -718,28 +718,18 @@ struct qlogicpti {
 #define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
 #define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
 
-#define QLOGICPTI {                                                       \
-       /* next */              NULL,                                      \
-       /* module */            NULL,                                      \
-       /* proc dir */          NULL,                                      \
-       /* procfs info */       NULL,                                      \
-       /* name */              NULL,                                      \
-       /* detect */            qlogicpti_detect,                          \
-       /* release */           qlogicpti_release,                         \
-       /* info */              qlogicpti_info,                            \
-       /* command */           NULL,                                      \
-       /* queuecommand */      qlogicpti_queuecommand,                    \
-       /* abort */             qlogicpti_abort,                           \
-       /* reset */             qlogicpti_reset,                           \
-       /* slave_attach */      NULL,                                      \
-       /* bios_param */        NULL,                                      \
-       /* can_queue */         QLOGICISP_REQ_QUEUE_LEN,                   \
-       /* this_id */           7,                                         \
-       /* sg_tablesize */      QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
-       /* cmd_per_lun */       1,                                         \
-       /* present */           0,                                         \
-       /* unchecked_isa_dma */ 0,                                         \
-       /* use_clustering */    DISABLE_CLUSTERING                         \
+#define QLOGICPTI {                                               \
+       detect:         qlogicpti_detect,                          \
+       release:        qlogicpti_release,                         \
+       info:           qlogicpti_info,                            \
+       queuecommand:   qlogicpti_queuecommand,                    \
+       abort:          qlogicpti_abort,                           \
+       reset:          qlogicpti_reset,                           \
+       can_queue:      QLOGICISP_REQ_QUEUE_LEN,                   \
+       this_id:        7,                                         \
+       sg_tablesize:   QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
+       cmd_per_lun:    1,                                         \
+       use_clustering: DISABLE_CLUSTERING                         \
 }
 
 /* For our interrupt engine. */
index 0958798f48fb39112c142e71e0367cb3e1c465f8..0b0c3f5fcdbfa483ae4af9132aa4fd5c293bbb24 100644 (file)
@@ -12,9 +12,8 @@
  *      Rik Faith <faith@cs.unc.edu>
  *      Tommy Thorn <tthorn>
  *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
- *      Andrea Arcangeli <arcangeli@mbox.queen.it>
  *
- *  Modified by Eric Youngdale eric@aib.com to
+ *  Modified by Eric Youngdale eric@andante.jic.com or ericy@gnu.ai.mit.edu to
  *  add scatter-gather, multiple outstanding request, and other
  *  enhancements.
  *
  *  Leonard N. Zubkoff <lnz@dandelion.com>
  */
 
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
-
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/delay.h>
 #include <linux/init.h>
 
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
 static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
 */
 
-
-/* Command groups 3 and 4 are reserved and should never be used.  */
-const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };
-
+/*
+ * Definitions and constants.
+ */
 #define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
 
 /*
@@ -90,27 +86,71 @@ const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };
 # error You lose.
 #endif
 
-static void scsi_done (Scsi_Cmnd *SCpnt);
-int update_timeout (Scsi_Cmnd *, int);
-static void print_inquiry(unsigned char *data);
-static void scsi_times_out (Scsi_Cmnd * SCpnt);
-static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
-                 int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
-                 struct Scsi_Host *shpnt, char * scsi_result);
-void scsi_build_commandblocks(Scsi_Device * SDpnt);
+#define MAX_SCSI_DEVICE_CODE 10
+
+#ifdef DEBUG
+    #define SCSI_TIMEOUT (5*HZ)
+#else
+    #define SCSI_TIMEOUT (2*HZ)
+#endif
+
+#define MIN_RESET_DELAY (2*HZ)
+
+/* Do not call reset on error if we just did a reset within 15 sec. */
+#define MIN_RESET_PERIOD (15*HZ)
+
+/* The following devices are known not to tolerate a lun != 0 scan for
+ * one reason or another.  Some will respond to all luns, others will
+ * lock up.
+ */
+
+#define BLIST_NOLUN     0x01
+#define BLIST_FORCELUN  0x02
+#define BLIST_BORKEN    0x04
+#define BLIST_KEY       0x08
+#define BLIST_SINGLELUN 0x10
+#define BLIST_NOTQ     0x20
+#define BLIST_SPARSELUN 0x40
 
+/*
+ * Data declarations.
+ */
+unsigned long             scsi_pid = 0;
+Scsi_Cmnd               * last_cmnd = NULL;
+/* Command groups 3 and 4 are reserved and should never be used.  */
+const unsigned char       scsi_command_size[8] = { 6, 10, 10, 12, 
+                                                   12, 12, 10, 10 };
+static unsigned long      serial_number = 0;
+static Scsi_Cmnd        * scsi_bh_queue_head = NULL;
 static FreeSectorBitmap * dma_malloc_freelist = NULL;
-static int scsi_need_isa_bounce_buffers;
-static unsigned int dma_sectors = 0;
-unsigned int dma_free_sectors = 0;
-unsigned int need_isa_buffer = 0;
-static unsigned char ** dma_malloc_pages = NULL;
-
-static int time_start;
-static int time_elapsed;
+static int                need_isa_bounce_buffers;
+static unsigned int       dma_sectors = 0;
+unsigned int              scsi_dma_free_sectors = 0;
+unsigned int              scsi_need_isa_buffer = 0;
+static unsigned char   ** dma_malloc_pages = NULL;
+
+/*
+ * Note - the initial logging level can be set here to log events at boot time.
+ * After the system is up, you may enable logging via the /proc interface.
+ */
+unsigned int              scsi_logging_level = 0;
+
 static volatile struct Scsi_Host * host_active = NULL;
-#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
-                         || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
+
+#if CONFIG_PROC_FS
+/* 
+ * This is the pointer to the /proc/scsi code.
+ * It is only initialized to !=0 if the scsi code is present
+ */
+struct proc_dir_entry proc_scsi_scsi = {
+    PROC_SCSI_SCSI, 4, "scsi",
+    S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
+    NULL,
+    NULL, NULL,
+    NULL, NULL, NULL
+};
+#endif
+
 
 const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
 {
@@ -126,92 +166,49 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
     "Communications   "
 };
 
-
-/*
- * global variables :
- * scsi_devices an array of these specifying the address for each
- * (host, id, LUN)
+/* 
+ * Function prototypes.
  */
-
-Scsi_Device * scsi_devices = NULL;
-
-/* Process ID of SCSI commands */
-unsigned long scsi_pid = 0;
-
-static unsigned long serial_number = 0;
-
-static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
 static void resize_dma_pool(void);
+static void print_inquiry(unsigned char *data);
+extern void scsi_times_out (Scsi_Cmnd * SCpnt);
+static int  scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
+                 int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
+                 struct Scsi_Host *shpnt, char * scsi_result);
+void        scsi_build_commandblocks(Scsi_Device * SDpnt);
 
-/* This variable is merely a hook so that we can debug the kernel with gdb. */
-Scsi_Cmnd * last_cmnd = NULL;
-
-/* This is the pointer to the /proc/scsi code.
- * It is only initialized to !=0 if the scsi code is present
+/*
+ * These are the interface to the old error handling code.  It should go away
+ * someday soon.
  */
+extern void scsi_old_done (Scsi_Cmnd *SCpnt);
+extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
+
 #if CONFIG_PROC_FS
 extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start,
                                      off_t offset, int length, int inout);
 extern int dispatch_scsi_info(int ino, char *buffer, char **start,
                              off_t offset, int length, int inout);
-
-struct proc_dir_entry proc_scsi_scsi = {
-    PROC_SCSI_SCSI, 4, "scsi",
-    S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
-    NULL,
-    NULL, NULL,
-    NULL, NULL, NULL
-};
 #endif
 
+#define SCSI_BLOCK(DEVICE, HOST)                                                \
+                ((HOST->block && host_active && HOST != host_active)            \
+                 || ((HOST)->can_queue && HOST->host_busy >= HOST->can_queue)    \
+                  || ((HOST)->host_blocked)                                       \
+                  || ((DEVICE) != NULL && (DEVICE)->device_blocked) )
+
+static void scsi_dump_status(int level);
+
+
 /*
  *  This is the number  of clock ticks we should wait before we time out
  *  and abort the command.  This is for  where the scsi.c module generates
  *  the command, not where it originates from a higher level, in which
  *  case the timeout is specified there.
  *
- *  ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
- *  respectively.
  */
 
-#ifdef DEBUG_TIMEOUT
-static void scsi_dump_status(void);
-#endif
-
-
-#ifdef DEBUG
-    #define SCSI_TIMEOUT (5*HZ)
-#else
-    #define SCSI_TIMEOUT (2*HZ)
-#endif
-
-#ifdef DEBUG
-    #define SENSE_TIMEOUT SCSI_TIMEOUT
-    #define ABORT_TIMEOUT SCSI_TIMEOUT
-    #define RESET_TIMEOUT SCSI_TIMEOUT
-#else
-    #define SENSE_TIMEOUT (5*HZ/10)
-    #define RESET_TIMEOUT (5*HZ/10)
-    #define ABORT_TIMEOUT (5*HZ/10)
-#endif
-
-#define MIN_RESET_DELAY (2*HZ)
-
-/* Do not call reset on error if we just did a reset within 15 sec. */
-#define MIN_RESET_PERIOD (15*HZ)
-
-/* The following devices are known not to tolerate a lun != 0 scan for
- * one reason or another.  Some will respond to all luns, others will
- * lock up.
- */
 
-#define BLIST_NOLUN     0x01
-#define BLIST_FORCELUN  0x02
-#define BLIST_BORKEN    0x04
-#define BLIST_KEY       0x08
-#define BLIST_SINGLELUN 0x10
-#define BLIST_NOTQ     0x20
-#define BLIST_SPARSELUN 0x40
 
 struct dev_info{
     const char * vendor;
@@ -284,6 +281,7 @@ static struct dev_info device_list[] =
 {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"EMULEX","MD21/S2     ESDI","*", BLIST_SINGLELUN},
 {"CANON","IPUBJD","*", BLIST_SPARSELUN},
+{"nCipher","Fastness Crypto","*", BLIST_FORCELUN},
 {"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"YAMAHA","CDR100","1.00", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
 {"YAMAHA","CDR102","1.00", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
@@ -311,7 +309,31 @@ static int get_device_flags(unsigned char * response_data){
     return 0;
 }
 
-void scsi_make_blocked_list(void)  {
+/*
+ * Function:    scsi_make_blocked_list
+ *
+ * Purpose:     Build linked list of hosts that require blocking.
+ *
+ * Arguments:   None.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       Blocking is sort of a hack that is used to prevent more than one
+ *              host adapter from being active at one time.  This is used in cases
+ *              where the ISA bus becomes unreliable if you have more than one
+ *              host adapter really pumping data through.
+ *
+ *              We spent a lot of time examining the problem, and I *believe* that
+ *              the problem is bus related as opposed to being a driver bug.
+ *
+ *              The blocked list is used as part of the synchronization object
+ *              that we use to ensure that only one host is active at one time.
+ *              I (ERY) would like to make this go away someday, but this would
+ *              require that we have a recursive mutex object.
+ */
+void 
+scsi_make_blocked_list(void)  
+{
     int block_count = 0, index;
     unsigned long flags;
     struct Scsi_Host * sh[128], * shpnt;
@@ -373,22 +395,31 @@ void scsi_make_blocked_list(void)  {
 static void scan_scsis_done (Scsi_Cmnd * SCpnt)
 {
 
-#ifdef DEBUG
-    printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
-#endif
+    SCSI_LOG_MLCOMPLETE(1,printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result));
     SCpnt->request.rq_status = RQ_SCSI_DONE;
 
     if (SCpnt->request.sem != NULL)
        up(SCpnt->request.sem);
 }
 
+void scsi_logging_setup(char *str, int *ints) 
+{
+    if (ints[0] != 1) {
+       printk("scsi_logging_setup : usage scsi_logging_level=n "
+               "(n should be 0 or non-zero)\n");
+    } else {
+       scsi_logging_level = (ints[1])? ~0 : 0;
+    }
+}
+
 #ifdef CONFIG_SCSI_MULTI_LUN
 static int max_scsi_luns = 8;
 #else
 static int max_scsi_luns = 1;
 #endif
 
-void scsi_luns_setup(char *str, int *ints) {
+void scsi_luns_setup(char *str, int *ints) 
+{
     if (ints[0] != 1)
        printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
     else
@@ -402,37 +433,72 @@ void scsi_luns_setup(char *str, int *ints) {
  *  lun address of all sequential devices to the tape driver, all random
  *  devices to the disk driver.
  */
-static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
-                 unchar hchannel, unchar hid, unchar hlun)
+static void scan_scsis (struct Scsi_Host *shpnt, 
+                        unchar hardcoded,
+                        unchar hchannel, 
+                        unchar hid, 
+                        unchar hlun)
 {
-  int dev, lun, channel;
-  unsigned char scsi_result0[256];
-  unsigned char *scsi_result;
-  Scsi_Device *SDpnt;
-  int max_dev_lun, sparse_lun;
-  Scsi_Cmnd *SCpnt;
+  int             channel;
+  int             dev;
+  int             lun;
+  int             max_dev_lun;
+  Scsi_Cmnd     * SCpnt;
+  unsigned char * scsi_result;
+  unsigned char   scsi_result0[256];
+  Scsi_Device   * SDpnt;
+  Scsi_Device   * SDtail;
+  int             sparse_lun;
 
   SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
-  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
   memset (SCpnt, 0, sizeof (Scsi_Cmnd));
 
+  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
+  memset (SDpnt, 0, sizeof (Scsi_Device));
+
 
   /* Make sure we have something that is valid for DMA purposes */
   scsi_result = ( ( !shpnt->unchecked_isa_dma )
                  ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
 
-  if (scsi_result == NULL) {
-    printk ("Unable to obtain scsi_result buffer\n");
-    goto leave;
+  if (scsi_result == NULL) 
+  {
+      printk ("Unable to obtain scsi_result buffer\n");
+      goto leave;
   }
 
-  /* We must chain ourself in the host_queue, so commands can time out */
-  if(shpnt->host_queue)
-      shpnt->host_queue->prev = SCpnt;
-  SCpnt->next = shpnt->host_queue;
-  SCpnt->prev = NULL;
-  shpnt->host_queue = SCpnt;
+  /*
+   * We must chain ourself in the host_queue, so commands can time out 
+   */
+  SCpnt->next = NULL;
+  SDpnt->device_queue = SCpnt;
+  SDpnt->host = shpnt;
+  SDpnt->online = TRUE;
+
+  /*
+   * Next, hook the device to the host in question.
+   */
+  SDpnt->prev = NULL;
+  SDpnt->next = NULL;
+  if( shpnt->host_queue != NULL )
+  {
+      SDtail = shpnt->host_queue;
+      while( SDtail->next != NULL )
+          SDtail = SDtail->next;
+
+      SDtail->next = SDpnt;
+      SDpnt->prev = SDtail;
+  }
+  else
+  {
+      shpnt->host_queue = SDpnt;
+  }
 
+  /*
+   * We need to increment the counter for this one device so we can track when
+   * things are quiet.
+   */
+  atomic_inc(&shpnt->host_active); 
 
   if (hardcoded == 1) {
     Scsi_Device *oldSDpnt=SDpnt;
@@ -490,20 +556,30 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
     }                           /* for channel ends */
   }                            /* if/else hardcoded */
 
+  /*
+   * We need to decrement the counter for this one device
+   * so we know when everything is quiet.
+   */
+  atomic_dec(&shpnt->host_active); 
+
   leave:
 
   {/* Unchain SCpnt from host_queue */
-    Scsi_Cmnd *prev, *next, *hqptr;
-    for(hqptr = shpnt->host_queue; hqptr != SCpnt; hqptr = hqptr->next) ;
-    if(hqptr) {
-      prev = hqptr->prev;
-      next = hqptr->next;
-      if(prev)
-       prev->next = next;
-      else
-       shpnt->host_queue = next;
-      if(next) next->prev = prev;
-    }
+      Scsi_Device *prev, *next;
+      Scsi_Device * dqptr;
+      
+      for(dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next) 
+          continue;
+      if(dqptr) 
+      {
+          prev = dqptr->prev;
+          next = dqptr->next;
+          if(prev)
+              prev->next = next;
+          else
+              shpnt->host_queue = next;
+          if(next) next->prev = prev;
+      }
   }
 
      /* Last device block does not exist.  Free memory. */
@@ -515,8 +591,25 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
 
     /* If we allocated a buffer so we could do DMA, free it now */
     if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
-      scsi_init_free (scsi_result, 512);
+    {
+        scsi_init_free (scsi_result, 512);
+    }
+
+    {
+        Scsi_Device * sdev;
+        Scsi_Cmnd   * scmd;
 
+        SCSI_LOG_SCAN_BUS(4,printk("Host status for host %p:\n", shpnt));
+        for(sdev = shpnt->host_queue; sdev; sdev = sdev->next)
+        {
+            SCSI_LOG_SCAN_BUS(4,printk("Device %d %p: ", sdev->id, sdev));
+            for(scmd=sdev->device_queue; scmd; scmd = scmd->next)
+            {
+                SCSI_LOG_SCAN_BUS(4,printk("%p ", scmd));
+            }
+                SCSI_LOG_SCAN_BUS(4,printk("\n", scmd));
+        }
+    }
 }
 
 /*
@@ -533,16 +626,11 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
   Scsi_Device * SDtail, *SDpnt=*SDpnt2;
   int bflags, type=-1;
 
-  SDtail = scsi_devices;
-  if (scsi_devices)
-    while (SDtail->next)
-      SDtail = SDtail->next;
-
-  memset (SDpnt, 0, sizeof (Scsi_Device));
   SDpnt->host = shpnt;
   SDpnt->id = dev;
   SDpnt->lun = lun;
   SDpnt->channel = channel;
+  SDpnt->online = TRUE;
 
   /* Some low level driver could use device->type (DB) */
   SDpnt->type = -1;
@@ -572,14 +660,14 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
                  (void *) scsi_result,
                  256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
     down (&sem);
+    SCpnt->request.sem = NULL;
   }
 
-#if defined(DEBUG) || defined(DEBUG_INIT)
-  printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
-          dev, lun, SCpnt->result);
-  print_driverbyte(SCpnt->result); print_hostbyte(SCpnt->result);
-  printk("\n");
-#endif
+  SCSI_LOG_SCAN_BUS(3,  printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
+          dev, lun, SCpnt->result));
+  SCSI_LOG_SCAN_BUS(3,print_driverbyte(SCpnt->result));
+  SCSI_LOG_SCAN_BUS(3,print_hostbyte(SCpnt->result));
+  SCSI_LOG_SCAN_BUS(3,printk("\n"));
 
   if (SCpnt->result) {
     if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
@@ -594,9 +682,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
       return 0;
   }
 
-#if defined (DEBUG) || defined(DEBUG_INIT)
-  printk ("scsi: performing INQUIRY\n");
-#endif
+  SCSI_LOG_SCAN_BUS(3,printk ("scsi: performing INQUIRY\n"));
   /*
    * Build an INQUIRY command block.
    */
@@ -615,12 +701,11 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
                  (void *) scsi_result,
                  256, scan_scsis_done, SCSI_TIMEOUT, 3);
     down (&sem);
+    SCpnt->request.sem = NULL;
   }
 
-#if defined(DEBUG) || defined(DEBUG_INIT)
-  printk ("scsi: INQUIRY %s with code 0x%x\n",
-          SCpnt->result ? "failed" : "successful", SCpnt->result);
-#endif
+  SCSI_LOG_SCAN_BUS(3,printk ("scsi: INQUIRY %s with code 0x%x\n",
+                              SCpnt->result ? "failed" : "successful", SCpnt->result));
 
   if (SCpnt->result)
     return 0;     /* assume no peripheral if any sort of error */
@@ -649,6 +734,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
   memcpy (SDpnt->rev, scsi_result + 32, 4);
 
   SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+  SDpnt->online = TRUE;
   SDpnt->lockable = SDpnt->removable;
   SDpnt->changed = 0;
   SDpnt->access_count = 0;
@@ -675,6 +761,8 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
     printk ("scsi: unknown type %d\n", type);
   }
 
+  SDpnt->device_blocked = FALSE;
+  SDpnt->device_busy = 0;
   SDpnt->single_lun = 0;
   SDpnt->soft_reset =
     (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
@@ -727,6 +815,13 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
   if ((bflags & BLIST_BORKEN) == 0)
     SDpnt->borken = 0;
 
+  /*
+   * If we want to only allow I/O to one of the luns attached to this device
+   * at a time, then we set this flag.
+   */
+  if (bflags & BLIST_SINGLELUN)
+    SDpnt->single_lun = 1;
+
   /*
    * These devices need this "key" to unlock the devices so we can use it
    */
@@ -748,33 +843,61 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
                    (void *) scsi_result, 0x2a,
                    scan_scsis_done, SCSI_TIMEOUT, 3);
       down (&sem);
+      SCpnt->request.sem = NULL;
     }
   }
-  /* Add this device to the linked list at the end */
-  if (SDtail)
-    SDtail->next = SDpnt;
-  else
-    scsi_devices = SDpnt;
-  SDtail = SDpnt;
 
+  /*
+   * Detach the command from the device. It was just a temporary to be used while
+   * scanning the bus - the real ones will be allocated later.
+   */
+  SDpnt->device_queue = NULL;
+
+  /*
+   * This device was already hooked up to the host in question,
+   * so at this point we just let go of it and it should be fine.  We do need to
+   * allocate a new one and attach it to the host so that we can further scan the bus.
+   */
   SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
   *SDpnt2=SDpnt;
   if (!SDpnt)
-    printk ("scsi: scan_scsis_single: Cannot malloc\n");
+  {
+      printk ("scsi: scan_scsis_single: Cannot malloc\n");
+      return 0;
+  }
 
+  memset (SDpnt, 0, sizeof (Scsi_Device));
 
   /*
-   * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+   * And hook up our command block to the new device we will be testing
+   * for.
    */
-  if (bflags & BLIST_NOLUN)
-    return 0;                   /* break; */
+  SDpnt->device_queue = SCpnt;
+  SDpnt->online = TRUE;
 
   /*
-   * If we want to only allow I/O to one of the luns attached to this device
-   * at a time, then we set this flag.
+   * Since we just found one device, there had damn well better be one in the list
+   * already.
    */
-  if (bflags & BLIST_SINGLELUN)
-    SDpnt->single_lun = 1;
+  if( shpnt->host_queue == NULL )
+      panic("scan_scsis_single: Host queue == NULL\n");
+
+  SDtail = shpnt->host_queue;
+  while (SDtail->next)
+  {
+      SDtail = SDtail->next;
+  }
+
+  /* Add this device to the linked list at the end */
+  SDtail->next = SDpnt;
+  SDpnt->prev = SDtail;
+  SDpnt->next = NULL;
+
+  /*
+   * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+   */
+  if (bflags & BLIST_NOLUN)
+    return 0;                   /* break; */
 
   /*
    * If this device is known to support sparse multiple units, override the
@@ -816,68 +939,6 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
 #define IN_RESET2 4
 #define IN_RESET3 8
 
-/*
- * This is our time out function, called when the timer expires for a
- * given host adapter.  It will attempt to abort the currently executing
- * command, that failing perform a kernel panic.
- */
-
-static void scsi_times_out (Scsi_Cmnd * SCpnt)
-{
-
-    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
-    {
-    case NORMAL_TIMEOUT:
-       {
-#ifdef DEBUG_TIMEOUT
-           scsi_dump_status();
-#endif
-       }
-
-       if (!scsi_abort (SCpnt, DID_TIME_OUT))
-           return;
-    case IN_ABORT:
-       printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
-              SCpnt->host->host_no, SCpnt->pid);
-       if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
-           return;
-    case IN_RESET:
-    case (IN_ABORT | IN_RESET):
-       /* This might be controversial, but if there is a bus hang,
-        * you might conceivably want the machine up and running
-        * esp if you have an ide disk.
-        */
-       printk("SCSI host %d channel %d reset (pid %ld) timed out - "
-               "trying harder\n",
-              SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
-       SCpnt->internal_timeout &= ~IN_RESET;
-       SCpnt->internal_timeout |= IN_RESET2;
-        scsi_reset (SCpnt,
-                   SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
-        return;
-    case (IN_ABORT | IN_RESET | IN_RESET2):
-       /* Obviously the bus reset didn't work.
-        * Let's try even harder and call for an HBA reset.
-         * Maybe the HBA itself crashed and this will shake it loose.
-        */
-       printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
-              SCpnt->host->host_no, SCpnt->pid);
-       SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
-       SCpnt->internal_timeout |= IN_RESET3;
-        scsi_reset (SCpnt,
-                   SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
-       return;
-
-    default:
-       printk("SCSI host %d reset (pid %ld) timed out again -\n",
-              SCpnt->host->host_no, SCpnt->pid);
-       printk("probably an unrecoverable SCSI bus or device hang.\n");
-       return;
-
-    }
-
-}
-
 
 /* This function takes a quick look at a request, and decides if it
  * can be queued now, or if there would be a stall while waiting for
@@ -886,7 +947,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt)
  * of the calling code to ensure that this is the case.
  */
 
-Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
+Scsi_Cmnd * scsi_request_queueable (struct request * req, Scsi_Device * device)
 {
     Scsi_Cmnd * SCpnt = NULL;
     int tablesize;
@@ -894,10 +955,10 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
     struct buffer_head * bh, *bhp;
 
     if (!device)
-       panic ("No device passed to request_queueable().\n");
+       panic ("No device passed to scsi_request_queueable().\n");
 
     if (req && req->rq_status == RQ_INACTIVE)
-       panic("Inactive in request_queueable");
+       panic("Inactive in scsi_request_queueable");
 
     /*
      * Look for a free command block.  If we have been instructed not to queue
@@ -909,10 +970,10 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
        SCpnt = device->device_queue;
        while(SCpnt){
            if(SCpnt->request.rq_status == RQ_INACTIVE) break;
-           SCpnt = SCpnt->device_next;
+           SCpnt = SCpnt->next;
        }
     } else {
-       SCpnt = device->host->host_queue;
+       SCpnt = device->device_queue;
        while(SCpnt){
            if(SCpnt->channel == device->channel
                 && SCpnt->target == device->id) {
@@ -939,7 +1000,7 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
 
     if (!SCpnt) return NULL;
 
-    if (SCSI_BLOCK(device->host)) return NULL;
+    if (SCSI_BLOCK(device, device->host)) return NULL;
 
     if (req) {
        memcpy(&SCpnt->request, req, sizeof(struct request));
@@ -979,6 +1040,9 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
                                      * either */
     }
 
+    atomic_inc(&SCpnt->host->host_active); 
+    SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target,
+                               atomic_read(&SCpnt->host->host_active)));
     SCpnt->use_sg = 0;               /* Reset the scatter-gather flag */
     SCpnt->old_use_sg  = 0;
     SCpnt->transfersize = 0;
@@ -991,6 +1055,8 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
     SCpnt->channel = device->channel;
     SCpnt->lun = device->lun;
     SCpnt->target = device->id;
+    SCpnt->state = SCSI_STATE_INITIALIZING;
+    SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
 
     return SCpnt;
 }
@@ -1001,11 +1067,11 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
  * not to return a descriptor if the host is unable to accept any more
  * commands for the time being.  We need to keep in mind that there is no
  * guarantee that the host remain not busy.  Keep in mind the
- * request_queueable function also knows the internal allocation scheme
+ * scsi_request_queueable function also knows the internal allocation scheme
  * of the packets for each device
  */
 
-Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
+Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
                             int wait)
 {
     kdev_t dev;
@@ -1019,7 +1085,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
     Scsi_Cmnd * found = NULL;
 
     if (!device)
-       panic ("No device passed to allocate_device().\n");
+       panic ("No device passed to scsi_allocate_device().\n");
 
     if (reqp) req = *reqp;
 
@@ -1032,7 +1098,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
 
     host = device->host;
 
-    if (in_interrupt() && SCSI_BLOCK(host)) return NULL;
+    if (in_interrupt() && SCSI_BLOCK(device, host)) return NULL;
 
     while (1==1){
        if (!device->single_lun) {
@@ -1040,10 +1106,10 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
            while(SCpnt){
                SCwait = SCpnt;
                if(SCpnt->request.rq_status == RQ_INACTIVE) break;
-               SCpnt = SCpnt->device_next;
+               SCpnt = SCpnt->next;
            }
        } else {
-           SCpnt = device->host->host_queue;
+           SCpnt = device->device_queue;
            while(SCpnt){
                if(SCpnt->channel == device->channel
                    && SCpnt->target == device->id) {
@@ -1080,7 +1146,6 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
        }
        if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE)  /* Might have changed */
        {
-#if 1  /* NEW CODE */
                if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){
                        sleep_on(&device->device_wait);
                        restore_flags(flags);
@@ -1091,21 +1156,9 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
                                printk("Attempt to allocate device channel %d,"
                                        " target %d, lun %d\n", device->channel,
                                        device->id, device->lun);
-                               panic("No device found in allocate_device\n");
+                               panic("No device found in scsi_allocate_device\n");
                        }
                }
-#else  /* ORIGINAL CODE */
-                   restore_flags(flags);
-                   if(!wait) return NULL;
-                   if (!SCwait) {
-                       printk("Attempt to allocate device channel %d, target"
-                               " %d, lun %d\n", device->channel, device->id,
-                               device->lun);
-                       panic("No device found in allocate_device\n");
-                   }
-                   SCSI_SLEEP(&device->device_wait,
-                              (SCwait->request.rq_status != RQ_INACTIVE));
-#endif
        } else {
            if (req) {
                memcpy(&SCpnt->request, req, sizeof(struct request));
@@ -1146,7 +1199,11 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
                SCpnt->request.sem = NULL;   /* And no one is waiting for this
                                              * to complete */
            }
+            atomic_inc(&SCpnt->host->host_active); 
            restore_flags(flags);
+            SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", 
+                                       SCpnt->target,
+                                       atomic_read(&SCpnt->host->host_active)));
            break;
        }
     }
@@ -1160,25 +1217,74 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
 
     /* Since not everyone seems to set the device info correctly
      * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+     * FIXME(eric) This doesn't make any sense.
      */
     SCpnt->channel = device->channel;
     SCpnt->lun = device->lun;
     SCpnt->target = device->id;
+    SCpnt->state = SCSI_STATE_INITIALIZING;
+    SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
 
     return SCpnt;
 }
 
+/*
+ * Function:    scsi_release_command
+ *
+ * Purpose:     Release a command block.
+ *
+ * Arguments:   SCpnt - command block we are releasing.
+ *
+ * Notes:       The command block can no longer be used by the caller once
+ *              this funciton is called.  This is in effect the inverse
+ *              of scsi_allocate_device/scsi_request_queueable.
+ */
+void
+scsi_release_command(Scsi_Cmnd * SCpnt)
+{
+  SCpnt->request.rq_status = RQ_INACTIVE;
+  SCpnt->state = SCSI_STATE_UNUSED;
+  SCpnt->owner = SCSI_OWNER_NOBODY;
+  atomic_dec(&SCpnt->host->host_active); 
+
+  SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n", 
+                             SCpnt->target,
+                             atomic_read(&SCpnt->host->host_active),
+                             SCpnt->host->host_failed));
+  if( SCpnt->host->host_failed != 0 )
+    {
+      SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n", 
+                                 SCpnt->host->in_recovery,
+                                 SCpnt->host->eh_active));
+    }
+
+  /*
+   * If the host is having troubles, then look to see if this was the last
+   * command that might have failed.  If so, wake up the error handler.
+   */
+  if( SCpnt->host->in_recovery
+      && !SCpnt->host->eh_active
+      && atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+  {
+      SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
+                                 atomic_read(&SCpnt->host->eh_wait->count)));
+      up(SCpnt->host->eh_wait);
+  }
+}
+
 /*
  * This is inline because we have stack problemes if we recurse to deeply.
  */
 
-inline void internal_cmnd (Scsi_Cmnd * SCpnt)
+inline int internal_cmnd (Scsi_Cmnd * SCpnt)
 {
-    unsigned long flags, timeout;
-    struct Scsi_Host * host;
 #ifdef DEBUG_DELAY
     unsigned long clock;
 #endif
+    unsigned long        flags;
+    struct Scsi_Host   * host;
+    int                  rtn = 0;
+    unsigned long        timeout;
 
 #if DEBUG
     unsigned long *ret = 0;
@@ -1219,25 +1325,31 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
     }
     restore_flags(flags);
 
-    update_timeout(SCpnt, SCpnt->timeout_per_command);
+    if( host->hostt->use_new_eh_code )
+      {
+        scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out);
+      }
+    else
+      {
+        scsi_add_timer(SCpnt, SCpnt->timeout_per_command, 
+                            scsi_old_times_out);
+      }
 
     /*
      * We will use a queued command if possible, otherwise we will emulate the
      * queuing and calling of completion function ourselves.
      */
-#ifdef DEBUG
-    printk("internal_cmnd (host = %d, channel = %d, target = %d, "
+    SCSI_LOG_MLQUEUE(3,printk("internal_cmnd (host = %d, channel = %d, target = %d, "
           "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
           SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
-          SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
-#endif
+          SCpnt->buffer, SCpnt->bufflen, SCpnt->done));
 
+    SCpnt->state = SCSI_STATE_QUEUED;
+    SCpnt->owner = SCSI_OWNER_LOWLEVEL;
     if (host->can_queue)
     {
-#ifdef DEBUG
-       printk("queuecommand : routine at %p\n",
-              host->hostt->queuecommand);
-#endif
+       SCSI_LOG_MLQUEUE(3,printk("queuecommand : routine at %p\n",
+                                  host->hostt->queuecommand));
        /* This locking tries to prevent all sorts of races between
         * queuecommand and the interrupt code.  In effect,
         * we are only allowed to be in queuecommand once at
@@ -1250,7 +1362,23 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
        if(!in_interrupt() && SCpnt->host->irq)
            disable_irq(SCpnt->host->irq);
 
-       host->hostt->queuecommand (SCpnt, scsi_done);
+        /*
+         * Use the old error handling code if we haven't converted the driver
+         * to use the new one yet.  Note - only the new queuecommand variant
+         * passes a meaningful return value.
+         */
+        if( host->hostt->use_new_eh_code )
+          {
+            rtn = host->hostt->queuecommand (SCpnt, scsi_done);
+            if( rtn != 0 )
+            {
+                scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
+            }
+          }
+        else
+          {
+            host->hostt->queuecommand (SCpnt, scsi_old_done);
+          }
 
        if(!in_interrupt() && SCpnt->host->irq)
            enable_irq(SCpnt->host->irq);
@@ -1259,9 +1387,7 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
     {
        int temp;
 
-#ifdef DEBUG
-       printk("command() :  routine at %p\n", host->hostt->command);
-#endif
+       SCSI_LOG_MLQUEUE(3,printk("command() :  routine at %p\n", host->hostt->command));
        temp = host->hostt->command (SCpnt);
        SCpnt->result = temp;
 #ifdef DEBUG_DELAY
@@ -1270,39 +1396,19 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
        printk("done(host = %d, result = %04x) : routine at %p\n",
               host->host_no, temp, host->hostt->command);
 #endif
-       scsi_done(SCpnt);
+        if( host->hostt->use_new_eh_code )
+          {
+            scsi_done(SCpnt);
+          }
+        else
+          {
+            scsi_old_done(SCpnt);
+          }
     }
-#ifdef DEBUG
-    printk("leaving internal_cmnd()\n");
-#endif
-}
-
-static void scsi_request_sense (Scsi_Cmnd * SCpnt)
-{
-    unsigned long flags;
-
-    save_flags(flags);
-    cli();
-    SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
-    update_timeout(SCpnt, SENSE_TIMEOUT);
-    restore_flags(flags);
-
-
-    memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
-           sizeof(generic_sense));
-
-    SCpnt->cmnd[1] = SCpnt->lun << 5;
-    SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
-
-    SCpnt->request_buffer = &SCpnt->sense_buffer;
-    SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
-    SCpnt->use_sg = 0;
-    SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-    internal_cmnd (SCpnt);
+    SCSI_LOG_MLQUEUE(3,printk("leaving internal_cmnd()\n"));
+    return rtn;
 }
 
-
-
 /*
  * scsi_do_cmd sends all the commands out to the low-level driver.  It
  * handles the specifics required for each low level driver - ie queued
@@ -1316,8 +1422,11 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
 {
     unsigned long flags;
     struct Scsi_Host * host = SCpnt->host;
+    Scsi_Device      * device = SCpnt->device;
 
-#ifdef DEBUG
+    SCpnt->owner = SCSI_OWNER_MIDLEVEL;
+
+SCSI_LOG_MLQUEUE(4,
     {
        int i;
        int target = SCpnt->target;
@@ -1329,8 +1438,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
        for (i = 0; i < 10; ++i)
            printk ("%02x  ", ((unsigned char *) cmnd)[i]);
        printk("\n");
-    }
-#endif
+    });
 
     if (!host)
     {
@@ -1350,15 +1458,16 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
     cli();
     SCpnt->pid = scsi_pid++;
 
-    while (SCSI_BLOCK(host)) {
+    while (SCSI_BLOCK((Scsi_Device *) NULL, host)) {
        restore_flags(flags);
-       SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
+       SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host));
        cli();
     }
 
     if (host->block) host_active = host;
 
     host->host_busy++;
+    device->device_busy++;
     restore_flags(flags);
 
     /*
@@ -1369,12 +1478,6 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
      */
 
     memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12);
-#if 0
-    SCpnt->host = host;
-    SCpnt->channel = channel;
-    SCpnt->target = target;
-    SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
-#endif
     SCpnt->reset_chain = NULL;
     SCpnt->serial_number = 0;
     SCpnt->bufflen = bufflen;
@@ -1403,967 +1506,321 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
     SCpnt->abort_reason = 0;
     internal_cmnd (SCpnt);
 
-#ifdef DEBUG
-    printk ("Leaving scsi_do_cmd()\n");
-#endif
-}
-
-static int check_sense (Scsi_Cmnd * SCpnt)
-{
-    /* If there is no sense information, request it.  If we have already
-     * requested it, there is no point in asking again - the firmware must
-     * be confused.
-     */
-    if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
-       if(!(SCpnt->flags & ASKED_FOR_SENSE))
-           return SUGGEST_SENSE;
-       else
-           return SUGGEST_RETRY;
-    }
-
-    SCpnt->flags &= ~ASKED_FOR_SENSE;
-
-#ifdef DEBUG_INIT
-    printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
-    print_sense("", SCpnt);
-    printk("\n");
-#endif
-    if (SCpnt->sense_buffer[2] & 0xe0)
-       return SUGGEST_ABORT;
-
-    switch (SCpnt->sense_buffer[2] & 0xf)
-    {
-    case NO_SENSE:
-       return 0;
-    case RECOVERED_ERROR:
-       return SUGGEST_IS_OK;
-
-    case ABORTED_COMMAND:
-       return SUGGEST_RETRY;
-    case NOT_READY:
-    case UNIT_ATTENTION:
-        /*
-         * If we are expecting a CC/UA because of a bus reset that we
-         * performed, treat this just as a retry.  Otherwise this is
-         * information that we should pass up to the upper-level driver
-         * so that we can deal with it there.
-         */
-        if( SCpnt->device->expecting_cc_ua )
-        {
-            SCpnt->device->expecting_cc_ua = 0;
-            return SUGGEST_RETRY;
-        }
-       return SUGGEST_ABORT;
-
-    /* these three are not supported */
-    case COPY_ABORTED:
-    case VOLUME_OVERFLOW:
-    case MISCOMPARE:
-
-    case MEDIUM_ERROR:
-       return SUGGEST_REMAP;
-    case BLANK_CHECK:
-    case DATA_PROTECT:
-    case HARDWARE_ERROR:
-    case ILLEGAL_REQUEST:
-    default:
-       return SUGGEST_ABORT;
-    }
+    SCSI_LOG_MLQUEUE(3,printk ("Leaving scsi_do_cmd()\n"));
 }
 
 /* This function is the mid-level interrupt routine, which decides how
  *  to handle error conditions.  Each invocation of this function must
  *  do one and *only* one of the following:
  *
- *  (1) Call last_cmnd[host].done.  This is done for fatal errors and
- *      normal completion, and indicates that the handling for this
- *      request is complete.
- *  (2) Call internal_cmnd to requeue the command.  This will result in
- *      scsi_done being called again when the retry is complete.
- *  (3) Call scsi_request_sense.  This asks the host adapter/drive for
- *      more information about the error condition.  When the information
- *      is available, scsi_done will be called again.
- *  (4) Call reset().  This is sort of a last resort, and the idea is that
- *      this may kick things loose and get the drive working again.  reset()
- *      automatically calls scsi_request_sense, and thus scsi_done will be
- *      called again once the reset is complete.
+ *      1) Insert command in BH queue.
+ *      2) Activate error handler for host.
+ *
+ * FIXME(eric) - I am concerned about stack overflow (still).  An interrupt could
+ * come while we are processing the bottom queue, which would cause another command
+ * to be stuffed onto the bottom queue, and it would in turn be processed as that
+ * interrupt handler is returning.  Given a sufficiently steady rate of returning
+ * commands, this could cause the stack to overflow.  I am not sure what is the most
+ * appropriate solution here - we should probably keep a depth count, and not process
+ * any commands while we still have a bottom handler active higher in the stack.
  *
- *      If none of the above actions are taken, the drive in question
- *      will hang. If more than one of the above actions are taken by
- *      scsi_done, then unpredictable behavior will result.
+ * There is currently code in the bottom half handler to monitor recursion in the bottom
+ * handler and report if it ever happens.  If this becomes a problem, it won't be hard to
+ * engineer something to deal with it so that only the outer layer ever does any real
+ * processing.
  */
-static void scsi_done (Scsi_Cmnd * SCpnt)
+void
+scsi_done (Scsi_Cmnd * SCpnt)
 {
-    int status=0;
-    int exit=0;
-    int checked;
-    int oldto;
-    struct Scsi_Host * host = SCpnt->host;
-    int result = SCpnt->result;
-    SCpnt->serial_number = 0;
-    oldto = update_timeout(SCpnt, 0);
-
-#ifdef DEBUG_TIMEOUT
-    if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
-                     result, SCpnt->target, SCpnt->lun);
-#endif
-
-    /* If we requested an abort, (and we got it) then fix up the return
-     *  status to say why
-     */
-    if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
-       SCpnt->result = result = (result & 0xff00ffff) |
-           (SCpnt->abort_reason << 16);
-
-
-#define FINISHED 0
-#define MAYREDO  1
-#define REDO     3
-#define PENDING  4
-
-#ifdef DEBUG
-    printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
-#endif
-
-    if(SCpnt->flags & WAS_SENSE)
-    {
-       SCpnt->use_sg = SCpnt->old_use_sg;
-       SCpnt->cmd_len = SCpnt->old_cmd_len;
-    }
-
-    switch (host_byte(result))
-    {
-    case DID_OK:
-       if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
-           /* Failed to obtain sense information */
-       {
-           SCpnt->flags &= ~WAS_SENSE;
-#if 0  /* This cannot possibly be correct. */
-           SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-#endif
-
-           if (!(SCpnt->flags & WAS_RESET))
-           {
-               printk("scsi%d : channel %d target %d lun %d request sense"
-                      " failed, performing reset.\n",
-                      SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
-                      SCpnt->lun);
-               scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
-               return;
-           }
-           else
-           {
-               exit = (DRIVER_HARD | SUGGEST_ABORT);
-               status = FINISHED;
-           }
-       }
-       else switch(msg_byte(result))
-       {
-       case COMMAND_COMPLETE:
-           switch (status_byte(result))
-           {
-           case GOOD:
-               if (SCpnt->flags & WAS_SENSE)
-               {
-#ifdef DEBUG
-                   printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
-                            "parsing sense information.\n");
-#endif
-                   SCpnt->flags &= ~WAS_SENSE;
-#if 0  /* This cannot possibly be correct. */
-                   SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-#endif
-
-                   switch (checked = check_sense(SCpnt))
-                   {
-                   case SUGGEST_SENSE:
-                   case 0:
-#ifdef DEBUG
-                       printk("NO SENSE.  status = REDO\n");
-#endif
-                       update_timeout(SCpnt, oldto);
-                       status = REDO;
-                       break;
-                   case SUGGEST_IS_OK:
-                       break;
-                   case SUGGEST_REMAP:
-#ifdef DEBUG
-                       printk("SENSE SUGGEST REMAP - status = FINISHED\n");
-#endif
-                       status = FINISHED;
-                       exit = DRIVER_SENSE | SUGGEST_ABORT;
-                       break;
-                   case SUGGEST_RETRY:
-#ifdef DEBUG
-                       printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
-#endif
-                       status = MAYREDO;
-                       exit = DRIVER_SENSE | SUGGEST_RETRY;
-                       break;
-                   case SUGGEST_ABORT:
-#ifdef DEBUG
-                       printk("SENSE SUGGEST ABORT - status = FINISHED");
-#endif
-                       status = FINISHED;
-                       exit =  DRIVER_SENSE | SUGGEST_ABORT;
-                       break;
-                   default:
-                       printk ("Internal error %s %d \n", __FILE__,
-                               __LINE__);
-                   }
-               } /* end WAS_SENSE */
-               else
-               {
-#ifdef DEBUG
-                   printk("COMMAND COMPLETE message returned, "
-                           "status = FINISHED. \n");
-#endif
-                   exit =  DRIVER_OK;
-                   status = FINISHED;
-               }
-               break;
-
-           case CHECK_CONDITION:
-           case COMMAND_TERMINATED:
-               switch (check_sense(SCpnt))
-               {
-               case 0:
-                   update_timeout(SCpnt, oldto);
-                   status = REDO;
-                   break;
-               case SUGGEST_REMAP:
-                   status = FINISHED;
-                   exit =  DRIVER_SENSE | SUGGEST_ABORT;
-                   break;
-               case SUGGEST_RETRY:
-                   status = MAYREDO;
-                   exit = DRIVER_SENSE | SUGGEST_RETRY;
-                   break;
-               case SUGGEST_ABORT:
-                   status = FINISHED;
-                   exit =  DRIVER_SENSE | SUGGEST_ABORT;
-                   break;
-               case SUGGEST_SENSE:
-                   scsi_request_sense (SCpnt);
-                   status = PENDING;
-                   break;
-               }
-               break;
-
-           case CONDITION_GOOD:
-           case INTERMEDIATE_GOOD:
-           case INTERMEDIATE_C_GOOD:
-               break;
-
-           case BUSY:
-           case QUEUE_FULL:
-               update_timeout(SCpnt, oldto);
-               status = REDO;
-               break;
-
-           case RESERVATION_CONFLICT:
-               printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
-                      " reset.\n", SCpnt->host->host_no, SCpnt->channel);
-               scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
-               return;
-#if 0
-               exit = DRIVER_SOFT | SUGGEST_ABORT;
-               status = MAYREDO;
-               break;
-#endif
-           default:
-               printk ("Internal error %s %d \n"
-                       "status byte = %d \n", __FILE__,
-                       __LINE__, status_byte(result));
-
-           }
-           break;
-       default:
-           panic("scsi: unsupported message byte %d received\n",
-                 msg_byte(result));
-       }
-       break;
-    case DID_TIME_OUT:
-#ifdef DEBUG
-       printk("Host returned DID_TIME_OUT - ");
-#endif
+  unsigned long      flags;
+  Scsi_Cmnd        * SCswap;
 
-       if (SCpnt->flags & WAS_TIMEDOUT)
-       {
-#ifdef DEBUG
-           printk("Aborting\n");
-#endif
-           /*
-             Allow TEST_UNIT_READY and INQUIRY commands to timeout early
-             without causing resets.  All other commands should be retried.
-           */
-           if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
-               SCpnt->cmnd[0] != INQUIRY)
-                   status = MAYREDO;
-           exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
-       }
-       else
-       {
-#ifdef DEBUG
-           printk ("Retrying.\n");
-#endif
-           SCpnt->flags  |= WAS_TIMEDOUT;
-           SCpnt->internal_timeout &= ~IN_ABORT;
-           status = REDO;
-       }
-       break;
-    case DID_BUS_BUSY:
-    case DID_PARITY:
-       status = REDO;
-       break;
-    case DID_NO_CONNECT:
-#ifdef DEBUG
-       printk("Couldn't connect.\n");
-#endif
-       exit  = (DRIVER_HARD | SUGGEST_ABORT);
-       break;
-    case DID_ERROR:
-       status = MAYREDO;
-       exit = (DRIVER_HARD | SUGGEST_ABORT);
-       break;
-    case DID_BAD_TARGET:
-    case DID_ABORT:
-       exit = (DRIVER_INVALID | SUGGEST_ABORT);
-       break;
-    case DID_RESET:
-       if (SCpnt->flags & IS_RESETTING)
-       {
-           SCpnt->flags &= ~IS_RESETTING;
-           status = REDO;
-           break;
-       }
-
-       if(msg_byte(result) == GOOD &&
-          status_byte(result) == CHECK_CONDITION) {
-           switch (check_sense(SCpnt)) {
-           case 0:
-               update_timeout(SCpnt, oldto);
-               status = REDO;
-               break;
-           case SUGGEST_REMAP:
-           case SUGGEST_RETRY:
-               status = MAYREDO;
-               exit = DRIVER_SENSE | SUGGEST_RETRY;
-               break;
-           case SUGGEST_ABORT:
-               status = FINISHED;
-               exit =  DRIVER_SENSE | SUGGEST_ABORT;
-               break;
-           case SUGGEST_SENSE:
-               scsi_request_sense (SCpnt);
-               status = PENDING;
-               break;
-           }
-       } else {
-           status=REDO;
-           exit = SUGGEST_RETRY;
-       }
-       break;
-    default :
-       exit = (DRIVER_ERROR | SUGGEST_DIE);
-    }
+  /*
+   * We don't have to worry about this one timing out any more.
+   */
+  scsi_delete_timer(SCpnt);
 
-    switch (status)
+  /*
+   * First, see whether this command already timed out.  If so, we ignore
+   * the response.  We treat it as if the command never finished.
+   */
+  if( SCpnt->state == SCSI_STATE_TIMEOUT )
     {
-    case FINISHED:
-    case PENDING:
-       break;
-    case MAYREDO:
-#ifdef DEBUG
-       printk("In MAYREDO, allowing %d retries, have %d\n",
-              SCpnt->allowed, SCpnt->retries);
-#endif
-       if ((++SCpnt->retries) < SCpnt->allowed)
-       {
-           if ((SCpnt->retries >= (SCpnt->allowed >> 1))
-               && !(SCpnt->host->last_reset > 0 &&
-                    jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
-               && !(SCpnt->flags & WAS_RESET))
-           {
-               printk("scsi%d channel %d : resetting for second half of retries.\n",
-                      SCpnt->host->host_no, SCpnt->channel);
-               scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
-               break;
-           }
-
-       }
-       else
-       {
-           status = FINISHED;
-           break;
-       }
-       /* fall through to REDO */
-
-    case REDO:
-
-       if (SCpnt->flags & WAS_SENSE)
-           scsi_request_sense(SCpnt);
-       else
-       {
-           memcpy ((void *) SCpnt->cmnd,
-                   (void*) SCpnt->data_cmnd,
-                   sizeof(SCpnt->data_cmnd));
-           SCpnt->request_buffer = SCpnt->buffer;
-           SCpnt->request_bufflen = SCpnt->bufflen;
-           SCpnt->use_sg = SCpnt->old_use_sg;
-           SCpnt->cmd_len = SCpnt->old_cmd_len;
-           internal_cmnd (SCpnt);
-       }
-       break;
-    default:
-       INTERNAL_ERROR;
+      SCSI_LOG_MLCOMPLETE(1,printk("Ignoring completion of %p due to timeout status", SCpnt));
+      return;
     }
 
-    if (status == FINISHED) {
-#ifdef DEBUG
-       printk("Calling done function - at address %p\n", SCpnt->done);
-#endif
-       host->host_busy--; /* Indicate that we are free */
-
-       if (host->block && host->host_busy == 0) {
-           host_active = NULL;
-
-           /* For block devices "wake_up" is done in end_scsi_request */
-           if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
-               MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
-               struct Scsi_Host * next;
-
-               for (next = host->block; next != host; next = next->block)
-                   wake_up(&next->host_wait);
-           }
-
-       }
+  SCpnt->state = SCSI_STATE_BHQUEUE;
+  SCpnt->owner = SCSI_OWNER_BH_HANDLER;
+  SCpnt->bh_next = NULL;
 
-       wake_up(&host->host_wait);
-       SCpnt->result = result | ((exit & 0xff) << 24);
-       SCpnt->use_sg = SCpnt->old_use_sg;
-       SCpnt->cmd_len = SCpnt->old_cmd_len;
-       SCpnt->done (SCpnt);
-    }
+  /*
+   * Next, put this command in the BH queue.  All processing of the command
+   * past this point will take place with interrupts turned on.
+   * We start by atomicly swapping the pointer into the queue head slot.
+   * If it was NULL before, then everything is fine, and we are done
+   * (this is the normal case).  If it was not NULL, then we block interrupts,
+   * and link them together.
+   */
+  
+  SCswap = (Scsi_Cmnd *) xchg(&scsi_bh_queue_head, SCpnt);
+  if( SCswap != NULL )
+  {
+      /*
+       * If we assume that the interrupt handler doesn't dawdle, then it is safe to
+       * say that we should come in here extremely rarely.  Under very heavy load,
+       * the requests might not be removed from the list fast enough so that we
+       * *do* end up stacking them, and that would be bad.
+       */
+      save_flags(flags);
+      cli();
+      
+      /*
+       * See if the pointer is NULL - it might have been serviced already
+       */
+      if( scsi_bh_queue_head == NULL )
+      {
+          scsi_bh_queue_head = SCswap;
+      }
+      else
+      {
+          SCswap->bh_next = scsi_bh_queue_head;
+          scsi_bh_queue_head = SCswap;
+      }
+      
+      restore_flags(flags);
+  }
 
-#undef FINISHED
-#undef REDO
-#undef MAYREDO
-#undef PENDING
+  /*
+   * Mark the bottom half handler to be run.
+   */
+  mark_bh(SCSI_BH);
 }
 
 /*
- * The scsi_abort function interfaces with the abort() function of the host
- * we are aborting, and causes the current command to not complete.  The
- * caller should deal with any error messages or status returned on the
- * next call.
+ * Procedure:   scsi_bottom_half_handler
  *
- * This will not be called reentrantly for a given host.
- */
-
-/*
- * Since we're nice guys and specified that abort() and reset()
- * can be non-reentrant.  The internal_timeout flags are used for
- * this.
+ * Purpose:     Called after we have finished processing interrupts, it
+ *              performs post-interrupt handling for commands that may
+ *              have completed.
+ *
+ * Notes:       This is called with all interrupts enabled.  This should reduce
+ *              interrupt latency, stack depth, and reentrancy of the low-level
+ *              drivers.
  */
-
-
-int scsi_abort (Scsi_Cmnd * SCpnt, int why)
+void scsi_bottom_half_handler(void)
 {
-    int oldto;
-    unsigned long flags;
-    struct Scsi_Host * host = SCpnt->host;
+  Scsi_Cmnd        * SCpnt;
+  Scsi_Cmnd        * SCnext;
+  static atomic_t    recursion_depth;
 
-    while(1)
-    {
-       save_flags(flags);
-       cli();
-
-       /*
-        * Protect against races here.  If the command is done, or we are
-        * on a different command forget it.
-        */
-       if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
-           restore_flags(flags);
-           return 0;
-       }
-
-       if (SCpnt->internal_timeout & IN_ABORT)
-       {
-           restore_flags(flags);
-           while (SCpnt->internal_timeout & IN_ABORT)
-               barrier();
-       }
-       else
-       {
-           SCpnt->internal_timeout |= IN_ABORT;
-           oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
-
-           if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
-               /* OK, this command must have died when we did the
-                *  reset.  The device itself must have lied.
-                */
-               printk("Stale command on %d %d:%d appears to have died when"
-                      " the bus was reset\n",
-                      SCpnt->channel, SCpnt->target, SCpnt->lun);
-           }
-
-           restore_flags(flags);
-           if (!host->host_busy) {
-               SCpnt->internal_timeout &= ~IN_ABORT;
-               update_timeout(SCpnt, oldto);
-               return 0;
-           }
-           printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
-                  " channel %d, id %d, lun %d ",
-                  SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
-                  (int) SCpnt->target, (int) SCpnt->lun);
-           print_command (SCpnt->cmnd);
-           if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
-               return 0;
-           SCpnt->abort_reason = why;
-           switch(host->hostt->abort(SCpnt)) {
-               /* We do not know how to abort.  Try waiting another
-                * time increment and see if this helps. Set the
-                * WAS_TIMEDOUT flag set so we do not try this twice
-                */
-           case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
-                                  * this is too severe
-                                  */
-           case SCSI_ABORT_SNOOZE:
-               if(why == DID_TIME_OUT) {
-                   save_flags(flags);
-                   cli();
-                   SCpnt->internal_timeout &= ~IN_ABORT;
-                   if(SCpnt->flags & WAS_TIMEDOUT) {
-                       restore_flags(flags);
-                       return 1; /* Indicate we cannot handle this.
-                                  * We drop down into the reset handler
-                                  * and try again
-                                  */
-                   } else {
-                       SCpnt->flags |= WAS_TIMEDOUT;
-                       oldto = SCpnt->timeout_per_command;
-                       update_timeout(SCpnt, oldto);
-                   }
-                   restore_flags(flags);
-               }
-               return 0;
-           case SCSI_ABORT_PENDING:
-               if(why != DID_TIME_OUT) {
-                   save_flags(flags);
-                   cli();
-                   update_timeout(SCpnt, oldto);
-                   restore_flags(flags);
-               }
-               return 0;
-           case SCSI_ABORT_SUCCESS:
-               /* We should have already aborted this one.  No
-                * need to adjust timeout
-                */
-                 SCpnt->internal_timeout &= ~IN_ABORT;
-                 return 0;
-           case SCSI_ABORT_NOT_RUNNING:
-               SCpnt->internal_timeout &= ~IN_ABORT;
-               update_timeout(SCpnt, 0);
-               return 0;
-           case SCSI_ABORT_ERROR:
-           default:
-               SCpnt->internal_timeout &= ~IN_ABORT;
-               return 1;
-           }
-       }
-    }
-}
-
-
-/* Mark a single SCSI Device as having been reset. */
-
-static inline void scsi_mark_device_reset(Scsi_Device *Device)
-{
-  Device->was_reset = 1;
-  Device->expecting_cc_ua = 1;
-}
-
-
-/* Mark all SCSI Devices on a specific Host as having been reset. */
-
-void scsi_mark_host_reset(struct Scsi_Host *Host)
-{
-  Scsi_Cmnd *SCpnt;
-  for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
-      scsi_mark_device_reset(SCpnt->device);
-}
-
-
-/* Mark all SCSI Devices on a specific Host Bus as having been reset. */
-
-void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
-{
-  Scsi_Cmnd *SCpnt;
-  for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
-      if (SCpnt->channel == channel)
-         scsi_mark_device_reset(SCpnt->device);
-}
-
-
-int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
-{
-    int temp;
-    unsigned long flags;
-    Scsi_Cmnd * SCpnt1;
-    struct Scsi_Host * host = SCpnt->host;
-
-    printk("SCSI bus is being reset for host %d channel %d.\n",
-          host->host_no, SCpnt->channel);
-
-#if 0
-    /*
-     * First of all, we need to make a recommendation to the low-level
-     * driver as to whether a BUS_DEVICE_RESET should be performed,
-     * or whether we should do a full BUS_RESET.  There is no simple
-     * algorithm here - we basically use a series of heuristics
-     * to determine what we should do.
-     */
-    SCpnt->host->suggest_bus_reset = FALSE;
-
-    /*
-     * First see if all of the active devices on the bus have
-     * been jammed up so that we are attempting resets.  If so,
-     * then suggest a bus reset.  Forcing a bus reset could
-     * result in some race conditions, but no more than
-     * you would usually get with timeouts.  We will cross
-     * that bridge when we come to it.
-     *
-     * This is actually a pretty bad idea, since a sequence of
-     * commands will often timeout together and this will cause a
-     * Bus Device Reset followed immediately by a SCSI Bus Reset.
-     * If all of the active devices really are jammed up, the
-     * Bus Device Reset will quickly timeout and scsi_times_out
-     * will follow up with a SCSI Bus Reset anyway.
-     */
-    SCpnt1 = host->host_queue;
-    while(SCpnt1) {
-       if( SCpnt1->request.rq_status != RQ_INACTIVE
-           && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
-               break;
-        SCpnt1 = SCpnt1->next;
-       }
-    if( SCpnt1 == NULL ) {
-        reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
-    }
-
-    /*
-     * If the code that called us is suggesting a hard reset, then
-     * definitely request it.  This usually occurs because a
-     * BUS_DEVICE_RESET times out.
-     *
-     * Passing reset_flags along takes care of this automatically.
-     */
-    if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
-        SCpnt->host->suggest_bus_reset = TRUE;
-    }
-#endif
-
-    while (1) {
-       save_flags(flags);
-       cli();
-
-       /*
-        * Protect against races here.  If the command is done, or we are
-        * on a different command forget it.
-        */
-       if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
-         if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
-           restore_flags(flags);
-           return 0;
-         }
-
-       if (SCpnt->internal_timeout & IN_RESET)
-       {
-           restore_flags(flags);
-           while (SCpnt->internal_timeout & IN_RESET)
-               barrier();
-       }
-       else
-       {
-           SCpnt->internal_timeout |= IN_RESET;
-           update_timeout(SCpnt, RESET_TIMEOUT);
-
-           if (host->host_busy)
-           {
-               restore_flags(flags);
-               SCpnt1 = host->host_queue;
-               while(SCpnt1) {
-                   if (SCpnt1->request.rq_status != RQ_INACTIVE) {
-#if 0
-                       if (!(SCpnt1->flags & IS_RESETTING) &&
-                           !(SCpnt1->internal_timeout & IN_ABORT))
-                           scsi_abort(SCpnt1, DID_RESET);
-#endif
-                       SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
-                   }
-                   SCpnt1 = SCpnt1->next;
-               }
-
-               host->last_reset = jiffies;
-               temp = host->hostt->reset(SCpnt, reset_flags);
-               /*
-                 This test allows the driver to introduce an additional bus
-                 settle time delay by setting last_reset up to 20 seconds in
-                 the future.  In the normal case where the driver does not
-                 modify last_reset, it must be assumed that the actual bus
-                 reset occurred immediately prior to the return to this code,
-                 and so last_reset must be updated to the current time, so
-                 that the delay in internal_cmnd will guarantee at least a
-                 MIN_RESET_DELAY bus settle time.
-               */
-               if (host->last_reset - jiffies > 20UL * HZ)
-                 host->last_reset = jiffies;
-           }
-           else
-           {
-               if (!host->block) host->host_busy++;
-               restore_flags(flags);
-               host->last_reset = jiffies;
-               SCpnt->flags |= (WAS_RESET | IS_RESETTING);
-               temp = host->hostt->reset(SCpnt, reset_flags);
-               if ((host->last_reset < jiffies) ||
-                   (host->last_reset > (jiffies + 20 * HZ)))
-                 host->last_reset = jiffies;
-               if (!host->block) host->host_busy--;
-           }
-
-#ifdef DEBUG
-           printk("scsi reset function returned %d\n", temp);
-#endif
-
-            /*
-             * Now figure out what we need to do, based upon
-             * what the low level driver said that it did.
-            * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
-            * or SCSI_RESET_WAKEUP, then the low level driver did a
-            * bus device reset or bus reset, so we should go through
-            * and mark one or all of the devices on that bus
-            * as having been reset.
-             */
-            switch(temp & SCSI_RESET_ACTION) {
-           case SCSI_RESET_SUCCESS:
-               if (temp & SCSI_RESET_HOST_RESET)
-                 scsi_mark_host_reset(host);
-               else if (temp & SCSI_RESET_BUS_RESET)
-                 scsi_mark_bus_reset(host, SCpnt->channel);
-               else scsi_mark_device_reset(SCpnt->device);
-               save_flags(flags);
-               cli();
-               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-               restore_flags(flags);
-               return 0;
-           case SCSI_RESET_PENDING:
-               if (temp & SCSI_RESET_HOST_RESET)
-                 scsi_mark_host_reset(host);
-               else if (temp & SCSI_RESET_BUS_RESET)
-                 scsi_mark_bus_reset(host, SCpnt->channel);
-               else scsi_mark_device_reset(SCpnt->device);
-           case SCSI_RESET_NOT_RUNNING:
-               return 0;
-           case SCSI_RESET_PUNT:
-               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-                scsi_request_sense (SCpnt);
-                return 0;
-           case SCSI_RESET_WAKEUP:
-               if (temp & SCSI_RESET_HOST_RESET)
-                 scsi_mark_host_reset(host);
-               else if (temp & SCSI_RESET_BUS_RESET)
-                 scsi_mark_bus_reset(host, SCpnt->channel);
-               else scsi_mark_device_reset(SCpnt->device);
-               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-               scsi_request_sense (SCpnt);
-                /*
-                 * If a bus reset was performed, we
-                 * need to wake up each and every command
-                 * that was active on the bus or if it was a HBA
-                 * reset all active commands on all channels
-                 */
-                if( temp & SCSI_RESET_HOST_RESET )
-                {
-                   SCpnt1 = host->host_queue;
-                   while(SCpnt1) {
-                       if (SCpnt1->request.rq_status != RQ_INACTIVE
-                           && SCpnt1 != SCpnt)
-                           scsi_request_sense (SCpnt1);
-                       SCpnt1 = SCpnt1->next;
-                    }
-                } else if( temp & SCSI_RESET_BUS_RESET ) {
-                    SCpnt1 = host->host_queue;
-                    while(SCpnt1) {
-                        if(SCpnt1->request.rq_status != RQ_INACTIVE
-                           && SCpnt1 != SCpnt
-                           && SCpnt1->channel == SCpnt->channel)
-                            scsi_request_sense (SCpnt);
-                        SCpnt1 = SCpnt1->next;
-                    }
-                }
-               return 0;
-           case SCSI_RESET_SNOOZE:
-               /* In this case, we set the timeout field to 0
-                * so that this command does not time out any more,
-                * and we return 1 so that we get a message on the
-                * screen.
-                */
-               save_flags(flags);
-               cli();
-               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-               update_timeout(SCpnt, 0);
-               restore_flags(flags);
-               /* If you snooze, you lose... */
-           case SCSI_RESET_ERROR:
-           default:
-               return 1;
-           }
+  
+  while(1==1)
+  {
+      /*
+       * If the counter is > 0, that means that there is another interrupt handler
+       * out there somewhere processing commands.  We don't want to get these guys
+       * nested as this can lead to stack overflow problems, and there isn't any
+       * real sense in it anyways.
+       */
+      if( atomic_read(&recursion_depth) > 0 )
+      {
+          printk("SCSI bottom half recursion depth = %d \n", atomic_read(&recursion_depth));
+          SCSI_LOG_MLCOMPLETE(1,printk("SCSI bottom half recursion depth = %d \n", 
+                                       atomic_read(&recursion_depth)));
+          break;
+      }
+      
+      /*
+       * This is an atomic operation - swap the pointer with a NULL pointer
+       * We will process everything we find in the list here.
+       */
+      SCpnt = xchg(&scsi_bh_queue_head, NULL);
+      
+      if( SCpnt == NULL )
+      {
+          return;
+      }
+      
+      atomic_inc(&recursion_depth);
+      
+      SCnext = SCpnt->bh_next;
+      
+      for(; SCpnt; SCpnt = SCnext)
+      {
+          SCnext = SCpnt->bh_next;
+          
+          switch( scsi_decide_disposition(SCpnt) )
+          {
+          case SUCCESS:
+              /*
+               * Add to BH queue.
+               */
+              SCSI_LOG_MLCOMPLETE(3,printk("Command finished %d %d 0x%x\n", SCpnt->host->host_busy,
+                     SCpnt->host->host_failed,
+                     SCpnt->result));
+              
+              scsi_finish_command(SCpnt);
+              break;
+          case NEEDS_RETRY:
+              /*
+               * We only come in here if we want to retry a command.  The
+               * test to see whether the command should be retried should be
+               * keeping track of the number of tries, so we don't end up looping,
+               * of course.
+               */
+              SCSI_LOG_MLCOMPLETE(3,printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy,
+                     SCpnt->host->host_failed, SCpnt->result));
+              
+              scsi_retry_command(SCpnt);
+              break;
+          case ADD_TO_MLQUEUE:
+              /* 
+               * This typically happens for a QUEUE_FULL message -
+               * typically only when the queue depth is only
+               * approximate for a given device.  Adding a command
+               * to the queue for the device will prevent further commands
+               * from being sent to the device, so we shouldn't end up
+               * with tons of things being sent down that shouldn't be.
+               */
+              scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY);
+              break;
+          default:
+              /*
+               * Here we have a fatal error of some sort.  Turn it over to
+               * the error handler.
+               */
+              SCSI_LOG_MLCOMPLETE(3,printk("Command failed %p %x active=%d busy=%d failed=%d\n", 
+                                           SCpnt, SCpnt->result,
+                                           atomic_read(&SCpnt->host->host_active),
+                                           SCpnt->host->host_busy,
+                                           SCpnt->host->host_failed));
+              
+              /*
+               * Dump the sense information too.
+               */
+              if ((status_byte (SCpnt->result) & CHECK_CONDITION) != 0)
+              {
+                  SCSI_LOG_MLCOMPLETE(3,print_sense("bh",SCpnt));
+              }
+
+
+              if( SCpnt->host->eh_wait != NULL )
+              {
+                  SCpnt->host->host_failed++;
+                  SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+                  SCpnt->state = SCSI_STATE_FAILED;
+                  SCpnt->host->in_recovery = 1;
+                  /*
+                   * If the host is having troubles, then look to see if this was the last
+                   * command that might have failed.  If so, wake up the error handler.
+                   */
+                  if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+                  {
+                    SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
+                                                      atomic_read(&SCpnt->host->eh_wait->count)));
+                      up(SCpnt->host->eh_wait);
+                  }
+              }
+              else
+              {
+                  /*
+                   * We only get here if the error recovery thread has died.
+                   */
+                  scsi_finish_command(SCpnt);
+              }
+          }
+      } /* for(; SCpnt...) */
+
+      atomic_dec(&recursion_depth);
+
+  } /* while(1==1) */
 
-           return temp;
-       }
-    }
 }
 
-
-static void scsi_main_timeout(void)
+/*
+ * Function:    scsi_retry_command
+ *
+ * Purpose:     Send a command back to the low level to be retried.
+ *
+ * Notes:       This command is always executed in the context of the
+ *              bottom half handler, or the error handler thread. Low
+ *              level drivers should not become re-entrant as a result of
+ *              this.
+ */
+int
+scsi_retry_command(Scsi_Cmnd * SCpnt)
 {
-    /*
-     * We must not enter update_timeout with a timeout condition still pending.
-     */
-
-    int timed_out;
-    unsigned long flags;
-    struct Scsi_Host * host;
-    Scsi_Cmnd * SCpnt = NULL;
-
-    save_flags(flags);
-    cli();
-
-    update_timeout(NULL, 0);
-
-    /*
-     * Find all timers such that they have 0 or negative (shouldn't happen)
-     * time remaining on them.
-     */
-    timed_out = 0;
-    for (host = scsi_hostlist; host; host = host->next) {
-       for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
-           if (SCpnt->timeout == -1)
-             {
-               SCpnt->timeout = 0;
-               SCpnt->serial_number_at_timeout = SCpnt->serial_number;
-               ++timed_out;
-             }
-    }
-    if (timed_out > 0) {
-       for (host = scsi_hostlist; host; host = host->next) {
-           for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
-               if (SCpnt->serial_number_at_timeout > 0 &&
-                   SCpnt->serial_number_at_timeout == SCpnt->serial_number)
-                 {
-                   restore_flags(flags);
-                   scsi_times_out(SCpnt);
-                   SCpnt->serial_number_at_timeout = 0;
-                   cli();
-                 }
-         }
-    }
-    restore_flags(flags);
+  memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
+          sizeof(SCpnt->data_cmnd));
+  SCpnt->request_buffer = SCpnt->buffer;
+  SCpnt->request_bufflen = SCpnt->bufflen;
+  SCpnt->use_sg = SCpnt->old_use_sg;
+  SCpnt->cmd_len = SCpnt->old_cmd_len;
+  return internal_cmnd (SCpnt);
 }
 
 /*
- * The strategy is to cause the timer code to call scsi_times_out()
- * when the soonest timeout is pending.
- * The arguments are used when we are queueing a new command, because
- * we do not want to subtract the time used from this time, but when we
- * set the timer, we want to take this value into account.
+ * Function:    scsi_finish_command
+ *
+ * Purpose:     Pass command off to upper layer for finishing of I/O
+ *              request, waking processes that are waiting on results,
+ *              etc.
  */
-
-int update_timeout(Scsi_Cmnd * SCset, int timeout)
+void
+scsi_finish_command(Scsi_Cmnd * SCpnt)
 {
-    unsigned int least, used;
-    unsigned int oldto;
-    unsigned long flags;
     struct Scsi_Host * host;
-    Scsi_Cmnd * SCpnt = NULL;
-
-    save_flags(flags);
-    cli();
+    Scsi_Device * device;
 
-    oldto = 0;
-
-    /*
-     * This routine can be a performance bottleneck under high loads, since
-     * it is called twice per SCSI operation: once when internal_cmnd is
-     * called, and again when scsi_done completes the command.  To limit
-     * the load this routine can cause, we shortcut processing if no clock
-     * ticks have occurred since the last time it was called.
-     */
+    host = SCpnt->host;
+    device = SCpnt->device;
 
-    if (jiffies == time_start && timer_table[SCSI_TIMER].expires > 0) {
-       if(SCset){
-           oldto = SCset->timeout;
-           SCset->timeout = timeout;
-           if (timeout > 0 &&
-               jiffies + timeout < timer_table[SCSI_TIMER].expires)
-                   timer_table[SCSI_TIMER].expires = jiffies + timeout;
-       }
-       restore_flags(flags);
-       return oldto;
+    host->host_busy--; /* Indicate that we are free */
+    device->device_busy--; /* Decrement device usage counter. */
+  
+    if (host->block && host->host_busy == 0) 
+    {
+        host_active = NULL;
+        
+        /* For block devices "wake_up" is done in end_scsi_request */
+        if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
+            MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
+            struct Scsi_Host * next;
+            
+            for (next = host->block; next != host; next = next->block)
+                wake_up(&next->host_wait);
+        }
+        
     }
-
-    /*
-     * Figure out how much time has passed since the last time the timeouts
-     * were updated
-     */
-    used = (time_start) ? (jiffies - time_start) : 0;
-
+  
     /*
-     * Find out what is due to timeout soonest, and adjust all timeouts for
-     * the amount of time that has passed since the last time we called
-     * update_timeout.
+     * Now try and drain the mid-level queue if any commands have been
+     * inserted.  Check to see whether the queue even has anything in
+     * it first, as otherwise this is useless overhead.
      */
-
-    oldto = 0;
-
-    if(SCset){
-       oldto = SCset->timeout - used;
-       SCset->timeout = timeout;
+    if( SCpnt->host->pending_commands != NULL )
+    {
+        scsi_mlqueue_finish(SCpnt->host, SCpnt->device);
     }
 
-    least = 0xffffffff;
-
-    for(host = scsi_hostlist; host; host = host->next)
-       for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
-           if (SCpnt->timeout > 0) {
-               if (SCpnt != SCset)
-                   SCpnt->timeout -= used;
-               if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
-               if(SCpnt->timeout > 0 && SCpnt->timeout < least)
-                   least = SCpnt->timeout;
-           }
-
+    wake_up(&host->host_wait);
+    
     /*
-     * If something is due to timeout again, then we will set the next timeout
-     * interrupt to occur.  Otherwise, timeouts are disabled.
+     * If we have valid sense information, then some kind of recovery
+     * must have taken place.  Make a note of this.
      */
-
-    if (least != 0xffffffff)
-    {
-       time_start = jiffies;
-       timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
-       timer_active |= 1 << SCSI_TIMER;
-    }
-    else
+    if( scsi_sense_valid(SCpnt) )
     {
-       timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
-       timer_active &= ~(1 << SCSI_TIMER);
+        SCpnt->result |= (DRIVER_SENSE << 24);
     }
-    restore_flags(flags);
-    return oldto;
+    
+    SCSI_LOG_MLCOMPLETE(3,printk("Notifying upper driver of completion for device %d %x\n",
+                                     SCpnt->device->id, SCpnt->result));
+    
+    SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
+    SCpnt->state = SCSI_STATE_FINISHED;
+    SCpnt->done (SCpnt);
 }
 
 #ifdef CONFIG_MODULES
@@ -2389,9 +1846,10 @@ void *scsi_malloc(unsigned int len)
            if ((dma_malloc_freelist[i] & (mask << j)) == 0){
                dma_malloc_freelist[i] |= (mask << j);
                restore_flags(flags);
-               dma_free_sectors -= nbits;
+               scsi_dma_free_sectors -= nbits;
 #ifdef DEBUG
-               printk("SMalloc: %d %p\n",len, dma_malloc_pages[i] + (j << 9));
+                SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9)));
+               printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9));
 #endif
                return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
            }
@@ -2414,6 +1872,7 @@ int scsi_free(void *obj, unsigned int len)
    ret = __builtin_return_address(0);
 #endif
     printk("scsi_free %p %d\n",obj, len);
+    SCSI_LOG_MLQUEUE(3,printk("SFree: %p %d\n",obj, len));
 #endif
 
     for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
@@ -2439,7 +1898,7 @@ int scsi_free(void *obj, unsigned int len)
 #endif
                 panic("scsi_free:Trying to free unused memory");
             }
-            dma_free_sectors += nbits;
+            scsi_dma_free_sectors += nbits;
             dma_malloc_freelist[page] &= ~(mask << sector);
             restore_flags(flags);
             return 0;
@@ -2508,37 +1967,37 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
               scsi_init_malloc(sizeof(Scsi_Cmnd),
                                GFP_ATOMIC |
                                (host->unchecked_isa_dma ? GFP_DMA : 0));
-       SCpnt->host = host;
-       SCpnt->device = SDpnt;
-       SCpnt->target = SDpnt->id;
-       SCpnt->lun = SDpnt->lun;
-       SCpnt->channel = SDpnt->channel;
-       SCpnt->request.rq_status = RQ_INACTIVE;
-       SCpnt->use_sg = 0;
-       SCpnt->old_use_sg = 0;
-       SCpnt->old_cmd_len = 0;
-       SCpnt->timeout = 0;
-       SCpnt->underflow = 0;
-       SCpnt->transfersize = 0;
-       SCpnt->serial_number = 0;
-       SCpnt->serial_number_at_timeout = 0;
-       SCpnt->host_scribble = NULL;
-       if(host->host_queue)
-           host->host_queue->prev = SCpnt;
-       SCpnt->next = host->host_queue;
-       SCpnt->prev = NULL;
-       host->host_queue = SCpnt;
-       SCpnt->device_next = SDpnt->device_queue;
-       SDpnt->device_queue = SCpnt;
+        memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
+       SCpnt->host                      = host;
+       SCpnt->device                    = SDpnt;
+       SCpnt->target                    = SDpnt->id;
+       SCpnt->lun                       = SDpnt->lun;
+       SCpnt->channel                   = SDpnt->channel;
+       SCpnt->request.rq_status         = RQ_INACTIVE;
+        SCpnt->host_wait                 = FALSE;
+        SCpnt->device_wait               = FALSE;
+       SCpnt->use_sg                    = 0;
+       SCpnt->old_use_sg                = 0;
+       SCpnt->old_cmd_len               = 0;
+       SCpnt->underflow                 = 0;
+       SCpnt->transfersize              = 0;
+       SCpnt->serial_number             = 0;
+       SCpnt->serial_number_at_timeout  = 0;
+       SCpnt->host_scribble             = NULL;
+       SCpnt->next                      = SDpnt->device_queue;
+       SDpnt->device_queue              = SCpnt;
+        SCpnt->state                     = SCSI_STATE_UNUSED;
+        SCpnt->owner                     = SCSI_OWNER_NOBODY;
     }
     SDpnt->has_cmdblocks = 1;
 }
 
+#ifndef MODULE /* { */
 /*
  * scsi_dev_init() is our initialization routine, which in turn calls host
  * initialization, bus scanning, and sd/st initialization routines.
+ * This is only used at boot time.
  */
-
 __initfunc(int scsi_dev_init(void))
 {
     Scsi_Device * SDpnt;
@@ -2556,9 +2015,6 @@ __initfunc(int scsi_dev_init(void))
     /* Init a few things so we can "malloc" memory. */
     scsi_loadable_module_flag = 0;
 
-    timer_table[SCSI_TIMER].fn = scsi_main_timeout;
-    timer_table[SCSI_TIMER].expires = 0;
-
     /* Register the /proc/scsi/scsi entry */
 #if CONFIG_PROC_FS
     proc_scsi_register(0, &proc_scsi_scsi);
@@ -2567,12 +2023,17 @@ __initfunc(int scsi_dev_init(void))
     /* initialize all hosts */
     scsi_init();
 
-    scsi_devices = (Scsi_Device *) NULL;
+    /*
+     * This is where the processing takes place for most everything
+     * when commands are completed.  Until we do this, we will not be able
+     * to queue any commands.
+     */
+    init_bh(SCSI_BH, scsi_bottom_half_handler);
 
     for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
        scan_scsis(shpnt,0,0,0,0);           /* scan for scsi devices */
        if (shpnt->select_queue_depths != NULL)
-           (shpnt->select_queue_depths)(shpnt, scsi_devices);
+           (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
     }
 
     printk("scsi : detected ");
@@ -2585,14 +2046,17 @@ __initfunc(int scsi_dev_init(void))
     for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
        if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
 
-    for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
-       SDpnt->scsi_request_fn = NULL;
-       for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-           if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-       if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+        for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) 
+        {
+            /* SDpnt->scsi_request_fn = NULL; */
+            for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+                if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+            if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+        }
     }
-
-
+    
     /*
      * This should build the DMA pool.
      */
@@ -2610,6 +2074,7 @@ __initfunc(int scsi_dev_init(void))
 
     return 0;
 }
+#endif /* MODULE */   /* } */
 
 static void print_inquiry(unsigned char *data)
 {
@@ -2662,7 +2127,7 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
 {
     Scsi_Cmnd *SCpnt;
     struct Scsi_Device_Template *SDTpnt;
-    Scsi_Device *scd, *scd_h = NULL;
+    Scsi_Device *scd;
     struct Scsi_Host *HBA_ptr;
     char *p;
     int   host, channel, id, lun;
@@ -2670,37 +2135,41 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
     off_t begin = 0;
     off_t pos = 0;
 
-    scd = scsi_devices;
-    HBA_ptr = scsi_hostlist;
-
     if(inout == 0) {
-       size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+        /*
+         * First, see if there are any attached devices or not.
+         */
+       for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+        {
+            if( HBA_ptr->host_queue != NULL )
+            {
+                break;
+            }
+        }
+       size = sprintf(buffer+len,"Attached devices: %s\n", (HBA_ptr)?"":"none");
        len += size;
        pos = begin + len;
-       while (HBA_ptr) {
+       for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+        {
 #if 0
            size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no,
                            HBA_ptr->hostt->procname);
            len += size;
            pos = begin + len;
 #endif
-           scd = scsi_devices;
-           while (scd) {
-               if (scd->host == HBA_ptr) {
-                   proc_print_scsidevice(scd, buffer, &size, len);
-                   len += size;
-                   pos = begin + len;
-
-                   if (pos < offset) {
-                       len = 0;
-                       begin = pos;
-                   }
-                   if (pos > offset + length)
-                       goto stop_output;
-               }
-               scd = scd->next;
+           for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
+            {
+                proc_print_scsidevice(scd, buffer, &size, len);
+                len += size;
+                pos = begin + len;
+                
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
            }
-           HBA_ptr = HBA_ptr->next;
        }
 
     stop_output:
@@ -2711,8 +2180,124 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
        return (len);
     }
 
-    if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
-       return(-EINVAL);
+    if(!buffer || length < 11 || strncmp("scsi", buffer, 4))
+       return(-EINVAL);
+
+    /*
+     * Usage: echo "scsi dump #N" > /proc/scsi/scsi
+     * to dump status of all scsi commands.  The number is used to specify the level
+     * of detail in the dump.
+     */
+    if(!strncmp("dump", buffer + 5, 4)) 
+    {
+        unsigned int level;
+
+       p = buffer + 10;
+
+        if( *p == '\0' )
+            return (-EINVAL);
+
+        level = simple_strtoul(p, NULL, 0);
+        scsi_dump_status(level);
+    }
+    /*
+     * Usage: echo "scsi log token #N" > /proc/scsi/scsi
+     * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
+     * llcomplete,hlqueue,hlcomplete]
+     */
+#if CONFIG_SCSI_LOGGING /* { */
+
+    if(!strncmp("log", buffer + 5, 3)) 
+    {
+        char * token;
+        unsigned int level;
+
+       p = buffer + 9;
+        token = p;
+        while(*p != ' ' && *p != '\t' && *p != '\0')
+        {
+            p++;
+        }
+
+        if( *p == '\0' )
+        {
+            if( strncmp(token, "all", 3) == 0 )
+            {
+                /*
+                 * Turn on absolutely everything.
+                 */
+                scsi_logging_level = ~0;
+            }
+            else if( strncmp(token, "none", 4) == 0 )
+            {
+                /*
+                 * Turn off absolutely everything.
+                 */
+                scsi_logging_level = 0;
+            }
+            else
+            {
+                return (-EINVAL);
+            }
+        }
+        else
+        {
+            *p++ = '\0';
+            
+            level = simple_strtoul(p, NULL, 0);
+            
+            /*
+             * Now figure out what to do with it.
+             */
+            if( strcmp(token, "error") == 0 )
+            {
+                SCSI_SET_ERROR_RECOVERY_LOGGING(level);
+            }
+            else if( strcmp(token, "timeout") == 0 )
+            {
+                SCSI_SET_TIMEOUT_LOGGING(level);
+            }
+            else if( strcmp(token, "scan") == 0 )
+            {
+                SCSI_SET_SCAN_BUS_LOGGING(level);
+            }
+            else if( strcmp(token, "mlqueue") == 0 )
+            {
+                SCSI_SET_MLQUEUE_LOGGING(level);
+            }
+            else if( strcmp(token, "mlcomplete") == 0 )
+            {
+                SCSI_SET_MLCOMPLETE_LOGGING(level);
+            }
+            else if( strcmp(token, "llqueue") == 0 )
+            {
+                SCSI_SET_LLQUEUE_LOGGING(level);
+            }
+            else if( strcmp(token, "llcomplete") == 0 )
+            {
+                SCSI_SET_LLCOMPLETE_LOGGING(level);
+            }
+            else if( strcmp(token, "hlqueue") == 0 )
+            {
+                SCSI_SET_HLQUEUE_LOGGING(level);
+            }
+            else if( strcmp(token, "hlcomplete") == 0 )
+            {
+                SCSI_SET_HLCOMPLETE_LOGGING(level);
+            }
+            else if( strcmp(token, "ioctl") == 0 )
+            {
+                SCSI_SET_IOCTL_LOGGING(level);
+            }
+            else
+            {
+                return (-EINVAL);
+            }
+        }
+
+        printk("scsi logging level set to 0x%8.8x\n", scsi_logging_level);
+    }
+#endif /* CONFIG_SCSI_LOGGING */ /* } */
 
     /*
      * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
@@ -2736,20 +2321,29 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
        printk("scsi singledevice %d %d %d %d\n", host, channel,
                        id, lun);
 
-       while(scd && (scd->host->host_no != host
-             || scd->channel != channel
-             || scd->id != id
-             || scd->lun != lun)) {
-           scd = scd->next;
-       }
-       if(scd)
-           return(-ENOSYS);  /* We do not yet support unplugging */
-       while(HBA_ptr && HBA_ptr->host_no != host)
-           HBA_ptr = HBA_ptr->next;
-
+        for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+        {
+            if( HBA_ptr->host_no == host )
+            {
+                break;
+            }
+        }
        if(!HBA_ptr)
            return(-ENXIO);
 
+        for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
+        {
+            if((scd->channel == channel
+                && scd->id == id
+                && scd->lun == lun))
+            {
+                break;
+            }
+        }
+
+       if(scd)
+           return(-ENOSYS);  /* We do not yet support unplugging */
+
        scan_scsis (HBA_ptr, 1, channel, id, lun);
        return(length);
 
@@ -2774,15 +2368,25 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
         id      = simple_strtoul(p+1, &p, 0);
         lun     = simple_strtoul(p+1, &p, 0);
 
-        while(scd != NULL) {
-            if(scd->host->host_no == host
-               && scd->channel == channel
-               && scd->id == id
-               && scd->lun == lun){
+
+        for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+        {
+            if( HBA_ptr->host_no == host )
+            {
+                break;
+            }
+        }
+       if(!HBA_ptr)
+           return(-ENODEV);
+
+        for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
+        {
+            if((scd->channel == channel
+                && scd->id == id
+                && scd->lun == lun))
+            {
                 break;
             }
-            scd_h = scd;
-            scd = scd->next;
         }
 
         if(scd == NULL)
@@ -2802,24 +2406,23 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
              * Nobody is using this device any more.
              * Free all of the command structures.
              */
-            for(SCpnt=scd->host->host_queue; SCpnt; SCpnt = SCpnt->next){
-                if(SCpnt->device == scd) {
-                    if(SCpnt->prev != NULL)
-                        SCpnt->prev->next = SCpnt->next;
-                    if(SCpnt->next != NULL)
-                        SCpnt->next->prev = SCpnt->prev;
-                    if(SCpnt == scd->host->host_queue)
-                        scd->host->host_queue = SCpnt->next;
-                    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
-                }
+            for(SCpnt=scd->device_queue; SCpnt; SCpnt = SCpnt->next)
+            {
+                scd->device_queue = SCpnt->next;
+                scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
             }
             /* Now we can remove the device structure */
-            if(scd_h != NULL) {
-                scd_h->next = scd->next;
-            } else if (scsi_devices == scd) {
-                /* We had a hit on the first entry of the device list */
-                scsi_devices = scd->next;
+            if( scd->next != NULL )
+                scd->next->prev = scd->prev;
+
+            if( scd->prev != NULL )
+                scd->prev->next = scd->next;
+
+            if( HBA_ptr->host_queue == scd )
+            {
+                HBA_ptr->host_queue = scd->next;
             }
+
             scsi_init_free((char *) scd, sizeof(Scsi_Device));
         } else {
             return(-EBUSY);
@@ -2847,13 +2450,13 @@ static void resize_dma_pool(void)
     unsigned int new_need_isa_buffer = 0;
     unsigned char ** new_dma_malloc_pages = NULL;
 
-    if( !scsi_devices )
+    if( !scsi_hostlist )
     {
        /*
         * Free up the DMA pool.
         */
-       if( dma_free_sectors != dma_sectors )
-           panic("SCSI DMA pool memory leak %d %d\n",dma_free_sectors,dma_sectors);
+       if( scsi_dma_free_sectors != dma_sectors )
+           panic("SCSI DMA pool memory leak %d %d\n",scsi_dma_free_sectors,dma_sectors);
 
        for(i=0; i < dma_sectors / SECTORS_PER_PAGE; i++)
            scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
@@ -2866,7 +2469,7 @@ static void resize_dma_pool(void)
                            (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_freelist));
        dma_malloc_freelist = NULL;
        dma_sectors = 0;
-       dma_free_sectors = 0;
+       scsi_dma_free_sectors = 0;
        return;
     }
     /* Next, check to see if we need to extend the DMA buffer pool */
@@ -2874,52 +2477,54 @@ static void resize_dma_pool(void)
     new_dma_sectors = 2*SECTORS_PER_PAGE;              /* Base value we use */
 
     if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD)
-       scsi_need_isa_bounce_buffers = 1;
+       need_isa_bounce_buffers = 1;
     else
-       scsi_need_isa_bounce_buffers = 0;
+       need_isa_bounce_buffers = 0;
 
     if (scsi_devicelist)
        for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
            new_dma_sectors += SECTORS_PER_PAGE;        /* Increment for each host */
 
-    for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
-       host = SDpnt->host;
-
-       /*
-        * sd and sr drivers allocate scatterlists.
-        * sr drivers may allocate for each command 1x2048 or 2x1024 extra
-        * buffers for 2k sector size and 1k fs.
-        * sg driver allocates buffers < 4k.
-        * st driver does not need buffers from the dma pool.
-        * estimate 4k buffer/command for devices of unknown type (should panic).
-        */
-       if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
-           SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
-           new_dma_sectors += ((host->sg_tablesize *
-                                sizeof(struct scatterlist) + 511) >> 9) *
-                              SDpnt->queue_depth;
-           if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
-               new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
-       }
-       else if (SDpnt->type == TYPE_SCANNER ||
-                SDpnt->type == TYPE_PROCESSOR ||
-                SDpnt->type == TYPE_MEDIUM_CHANGER) {
-           new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
-       }
-       else {
-           if (SDpnt->type != TYPE_TAPE) {
-               printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
-               new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
-           }
+    for (host = scsi_hostlist; host; host = host->next)
+    {
+        for (SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) 
+        {
+            /*
+             * sd and sr drivers allocate scatterlists.
+             * sr drivers may allocate for each command 1x2048 or 2x1024 extra
+             * buffers for 2k sector size and 1k fs.
+             * sg driver allocates buffers < 4k.
+             * st driver does not need buffers from the dma pool.
+             * estimate 4k buffer/command for devices of unknown type (should panic).
+             */
+            if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
+                SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
+                new_dma_sectors += ((host->sg_tablesize *
+                                     sizeof(struct scatterlist) + 511) >> 9) *
+                    SDpnt->queue_depth;
+                if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
+                    new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
+            }
+            else if (SDpnt->type == TYPE_SCANNER ||
+                     SDpnt->type == TYPE_PROCESSOR ||
+                     SDpnt->type == TYPE_MEDIUM_CHANGER) {
+                new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
+            }
+            else {
+                if (SDpnt->type != TYPE_TAPE) {
+                    printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
+                    new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
+                }
+            }
+            
+            if(host->unchecked_isa_dma &&
+               need_isa_bounce_buffers &&
+               SDpnt->type != TYPE_TAPE) {
+                new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
+                    SDpnt->queue_depth;
+                new_need_isa_buffer++;
+            }
         }
-
-       if(host->unchecked_isa_dma &&
-          scsi_need_isa_bounce_buffers &&
-          SDpnt->type != TYPE_TAPE) {
-           new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-                                                 SDpnt->queue_depth;
-           new_need_isa_buffer++;
-       }
     }
 
 #ifdef DEBUG_INIT
@@ -2977,16 +2582,16 @@ static void resize_dma_pool(void)
        scsi_init_free((char *) dma_malloc_pages, size);
     }
 
-    dma_free_sectors += new_dma_sectors - dma_sectors;
+    scsi_dma_free_sectors += new_dma_sectors - dma_sectors;
     dma_malloc_pages = new_dma_malloc_pages;
     dma_sectors = new_dma_sectors;
-    need_isa_buffer = new_need_isa_buffer;
+    scsi_need_isa_buffer = new_need_isa_buffer;
     restore_flags(flags);
 
 #ifdef DEBUG_INIT
-    printk("resize_dma_pool: dma free sectors   = %d\n", dma_free_sectors);
+    printk("resize_dma_pool: dma free sectors   = %d\n", scsi_dma_free_sectors);
     printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
-    printk("resize_dma_pool: need isa buffers   = %d\n", need_isa_buffer);
+    printk("resize_dma_pool: need isa buffers   = %d\n", scsi_need_isa_buffer);
 #endif
 }
 
@@ -3010,13 +2615,16 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
     pcount = next_scsi_host;
     if ((tpnt->present = tpnt->detect(tpnt)))
     {
-       if(pcount == next_scsi_host) {
-           if(tpnt->present > 1) {
+       if(pcount == next_scsi_host) 
+        {
+           if(tpnt->present > 1) 
+            {
                printk("Failure to register low-level scsi driver");
                scsi_unregister_host(tpnt);
                return 1;
            }
-           /* The low-level driver failed to register a driver.  We
+           /* 
+             * The low-level driver failed to register a driver.  We
             *  can do this now.
             */
            scsi_register(tpnt,0);
@@ -3029,16 +2637,46 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
        build_proc_dir_entries(tpnt);
 #endif
 
+
+        /*
+         * Add the kernel threads for each host adapter that will
+         * handle error correction.
+         */
+        for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+        {
+            if( shpnt->hostt == tpnt && shpnt->hostt->use_new_eh_code )
+            {
+                struct semaphore sem = MUTEX_LOCKED;
+                
+                shpnt->eh_notify = &sem;
+                kernel_thread((int (*)(void *))scsi_error_handler, 
+                              (void *) shpnt, 0);
+                
+                /*
+                 * Now wait for the kernel error thread to initialize itself
+                 * as it might be needed when we scan the bus.
+                 */
+                down (&sem);
+                shpnt->eh_notify = NULL;
+            }
+        }
+        
        for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+        {
            if(shpnt->hostt == tpnt)
            {
                if(tpnt->info)
+                {
                    name = tpnt->info(shpnt);
+                }
                else
+                {
                    name = tpnt->name;
+                }
                printk ("scsi%d : %s\n", /* And print a little message */
                        shpnt->host_no, name);
            }
+        }
 
        printk ("scsi : %d host%s.\n", next_scsi_host,
                (next_scsi_host == 1) ? "" : "s");
@@ -3048,26 +2686,36 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
        /* The next step is to call scan_scsis here.  This generates the
         * Scsi_Devices entries
         */
-
        for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-           if(shpnt->hostt == tpnt) {
-             scan_scsis(shpnt,0,0,0,0);
-             if (shpnt->select_queue_depths != NULL)
-                 (shpnt->select_queue_depths)(shpnt, scsi_devices);
+        {
+           if(shpnt->hostt == tpnt) 
+            {
+                scan_scsis(shpnt,0,0,0,0);
+                if (shpnt->select_queue_depths != NULL)
+                {
+                    (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
+                }
            }
+        }
 
        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+        {
            if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+        }
 
-       /* Next we create the Scsi_Cmnd structures for this host */
-
-       for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
-           if(SDpnt->host->hostt == tpnt)
-           {
-               for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-                   if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-               if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
-           }
+       /*
+         * Next we create the Scsi_Cmnd structures for this host 
+         */
+        for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+        {
+            for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
+                if(SDpnt->host->hostt == tpnt)
+                {
+                    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+                        if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+                    if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+                }
+        }
 
        /*
         * Now that we have all of the devices, resize the DMA pool,
@@ -3077,8 +2725,12 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
 
        /* This does any final handling that is required. */
        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+        {
            if(sdtpnt->finish && sdtpnt->nr_dev)
+            {
                (*sdtpnt->finish)();
+            }
+        }
     }
 
 #if defined(USE_STATIC_SCSI_MEMORY)
@@ -3095,90 +2747,187 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
 /*
  * Similarly, this entry point should be called by a loadable module if it
  * is trying to remove a low level scsi driver from the system.
+ *
+ * Note - there is a fatal flaw in the deregister module function.
+ * There is no way to return a code that says 'I cannot be unloaded now'.
+ * The system relies entirely upon usage counts that are maintained,
+ * and the assumption is that if the usage count is 0, then the module
+ * can be unloaded.
  */
 static void scsi_unregister_host(Scsi_Host_Template * tpnt)
 {
-    Scsi_Host_Template * SHT, *SHTp;
-    Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
-    Scsi_Cmnd * SCpnt;
-    unsigned long flags;
+    unsigned long                 flags;
+    int                           online_status;
+    int                           pcount;
+    Scsi_Cmnd                   * SCpnt;
+    Scsi_Device                 * SDpnt;
+    Scsi_Device                 * SDpnt1;
     struct Scsi_Device_Template * sdtpnt;
-    struct Scsi_Host * shpnt, *sh1;
-    int pcount;
+    struct Scsi_Host            * sh1;
+    struct Scsi_Host            * shpnt;
+    Scsi_Host_Template          * SHT;
+    Scsi_Host_Template          * SHTp;
+
+    /*
+     * First verify that this host adapter is completely free with no pending
+     * commands 
+     */
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+        for(SDpnt = shpnt->host_queue; SDpnt; 
+            SDpnt = SDpnt->next)
+        {
+            if(SDpnt->host->hostt == tpnt 
+               && SDpnt->host->hostt->module
+               && SDpnt->host->hostt->module->usecount) return;
+            /* 
+             * FIXME(eric) - We need to find a way to notify the
+             * low level driver that we are shutting down - via the
+             * special device entry that still needs to get added. 
+             *
+             * Is detach interface below good enough for this?
+             */
+        }
+    }
 
-    /* First verify that this host adapter is completely free with no pending
-     * commands */
+    /*
+     * FIXME(eric) put a spinlock on this.  We force all of the devices offline
+     * to help prevent race conditions where other hosts/processors could try and
+     * get in and queue a command.
+     */
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+        for(SDpnt = shpnt->host_queue; SDpnt; 
+            SDpnt = SDpnt->next)
+        {
+            if(SDpnt->host->hostt == tpnt )
+                SDpnt->online = FALSE;
 
-    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
-       if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->module
-          && sdpnt->host->hostt->module->usecount) return;
+        }
+    }
 
     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
     {
-       if (shpnt->hostt != tpnt) continue;
-       for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
-       {
-           save_flags(flags);
-           cli();
-           if(SCpnt->request.rq_status != RQ_INACTIVE) {
-               restore_flags(flags);
-               for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
-                   if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
-                       SCpnt->request.rq_status = RQ_INACTIVE;
-               printk("Device busy???\n");
-               return;
+       if (shpnt->hostt != tpnt)
+        {
+            continue;
+        }
+
+        for(SDpnt = shpnt->host_queue; SDpnt; 
+            SDpnt = SDpnt->next)
+        {
+            /*
+             * Loop over all of the commands associated with the device.  If any of
+             * them are busy, then set the state back to inactive and bail.
+             */
+            for(SCpnt = SDpnt->device_queue; SCpnt; 
+                SCpnt = SCpnt->next)
+           {
+                online_status = SDpnt->online;
+                SDpnt->online = FALSE;
+               save_flags(flags);
+               cli();
+               if(SCpnt->request.rq_status != RQ_INACTIVE) 
+                {
+                   restore_flags(flags);
+                    printk("SCSI device not inactive - state=%d, id=%d\n",
+                           SCpnt->request.rq_status, SCpnt->target);
+                    for(SDpnt1 = shpnt->host_queue; SDpnt1; 
+                        SDpnt1 = SDpnt1->next)
+                      {
+                        for(SCpnt = SDpnt1->device_queue; SCpnt; 
+                            SCpnt = SCpnt->next)
+                          if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
+                           SCpnt->request.rq_status = RQ_INACTIVE;
+                      }
+                    SDpnt->online = online_status;
+                   printk("Device busy???\n");
+                   return;
+               }
+                /*
+                 * No, this device is really free.  Mark it as such, and
+                 * continue on.
+                 */
+                SCpnt->state = SCSI_STATE_DISCONNECTING;
+               SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING;  /* Mark as busy */
+               restore_flags(flags);
            }
-           SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING;  /* Mark as busy */
-           restore_flags(flags);
-       }
+        }
     }
     /* Next we detach the high level drivers from the Scsi_Device structures */
 
-    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
-       if(sdpnt->host->hostt == tpnt)
-       {
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+        if(shpnt->hostt != tpnt)
+        {
+            continue;
+        }
+
+        for(SDpnt = shpnt->host_queue; SDpnt; 
+            SDpnt = SDpnt->next)
+        {
            for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-               if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt);
-           /* If something still attached, punt */
-           if (sdpnt->attached) {
-               printk("Attached usage count = %d\n", sdpnt->attached);
-               return;
-           }
+              if(sdtpnt->detach) (*sdtpnt->detach)(SDpnt);
+
+            /* If something still attached, punt */
+            if (SDpnt->attached) 
+            {
+                printk("Attached usage count = %d\n", SDpnt->attached);
+                return;
+            }
        }
+    }
+
+    /*
+     * Next, kill the kernel error recovery thread for this host.
+     */
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+        if(   shpnt->hostt == tpnt 
+              && shpnt->hostt->use_new_eh_code
+              && shpnt->ehandler != NULL )
+        {
+            struct semaphore sem = MUTEX_LOCKED;
+            
+            shpnt->eh_notify = &sem;
+            send_sig(SIGKILL, shpnt->ehandler, 1);
+            down(&sem);
+            shpnt->eh_notify = NULL;
+        }
+    }
 
     /* Next we free up the Scsi_Cmnd structures for this host */
 
-    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
-       if(sdpnt->host->hostt == tpnt)
-           while (sdpnt->host->host_queue) {
-               SCpnt = sdpnt->host->host_queue->next;
-               scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
-               sdpnt->host->host_queue = SCpnt;
-               if (SCpnt) SCpnt->prev = NULL;
-               sdpnt->has_cmdblocks = 0;
-           }
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+       if(shpnt->hostt != tpnt)
+        {
+            continue;
+        }
+
+        for(SDpnt = shpnt->host_queue; SDpnt; 
+            SDpnt = shpnt->host_queue)
+        {
+            while (SDpnt->device_queue)
+            {
+                SCpnt = SDpnt->device_queue->next;
+                scsi_init_free((char *) SDpnt->device_queue, sizeof(Scsi_Cmnd));
+                SDpnt->device_queue = SCpnt;
+            }
+            SDpnt->has_cmdblocks = 0;
 
-    /* Next free up the Scsi_Device structures for this host */
+            /* Next free up the Scsi_Device structures for this host */
+            shpnt->host_queue = SDpnt->next;
+           scsi_init_free((char *) SDpnt, sizeof (Scsi_Device));
 
-    sdppnt = NULL;
-    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
-    {
-       sdpnt1 = sdpnt->next;
-       if (sdpnt->host->hostt == tpnt) {
-           if (sdppnt)
-               sdppnt->next = sdpnt->next;
-           else
-               scsi_devices = sdpnt->next;
-           scsi_init_free((char *) sdpnt, sizeof (Scsi_Device));
-       } else
-           sdppnt = sdpnt;
+        }
     }
 
     /* Next we go through and remove the instances of the individual hosts
      * that were detected */
 
-    shpnt = scsi_hostlist;
-    while(shpnt) {
+    for(shpnt = scsi_hostlist; shpnt; shpnt = sh1) 
+    {
        sh1 = shpnt->next;
        if(shpnt->hostt == tpnt) {
            if(shpnt->loaded_as_module) {
@@ -3204,7 +2953,6 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
                tpnt->present--;
            }
        }
-       shpnt = sh1;
     }
 
     /*
@@ -3212,7 +2960,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
      * to completely nuke the DMA pool.  The resize operation will
      * do the right thing and free everything.
      */
-    if( !scsi_devices )
+    if( !scsi_hosts )
        resize_dma_pool();
 
     printk ("scsi : %d host%s.\n", next_scsi_host,
@@ -3256,7 +3004,8 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
  */
 static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
 {
-    Scsi_Device * SDpnt;
+    Scsi_Device      * SDpnt;
+    struct Scsi_Host * shpnt;
 
     if (tpnt->next) return 1;
 
@@ -3265,8 +3014,14 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
      * First scan the devices that we know about, and see if we notice them.
      */
 
-    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
-       if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+        for(SDpnt = shpnt->host_queue; SDpnt; 
+            SDpnt = SDpnt->next)
+        {
+            if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
+        }
+    }
 
     /*
      * If any of the devices would match this driver, then perform the
@@ -3278,15 +3033,22 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
     /*
      * Now actually connect the devices to the new driver.
      */
-    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
     {
-       if(tpnt->attach)  (*tpnt->attach)(SDpnt);
-       /*
-        * If this driver attached to the device, and we no longer
-        * have anything attached, release the scsi command blocks.
-        */
-       if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
-           scsi_build_commandblocks(SDpnt);
+        for(SDpnt = shpnt->host_queue; SDpnt; 
+            SDpnt = SDpnt->next)
+        {
+            if(tpnt->attach)  (*tpnt->attach)(SDpnt);
+            /*
+             * If this driver attached to the device, and don't have any
+             * command blocks for this device, allocate some.
+             */
+            if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
+            {
+                SDpnt->online = TRUE;
+                scsi_build_commandblocks(SDpnt);
+            }
+        }
     }
 
     /*
@@ -3302,6 +3064,7 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
 {
     Scsi_Device * SDpnt;
     Scsi_Cmnd * SCpnt;
+    struct Scsi_Host * shpnt;
     struct Scsi_Device_Template * spnt;
     struct Scsi_Device_Template * prev_spnt;
 
@@ -3314,30 +3077,30 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
      * Next, detach the devices from the driver.
      */
 
-    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
     {
-       if(tpnt->detach) (*tpnt->detach)(SDpnt);
-       if(SDpnt->attached == 0)
-       {
-           /*
-            * Nobody is using this device any more.  Free all of the
-            * command structures.
-            */
-           for(SCpnt = SDpnt->host->host_queue; SCpnt; SCpnt = SCpnt->next)
+        for(SDpnt = shpnt->host_queue; SDpnt; 
+            SDpnt = SDpnt->next)
+        {
+            if(tpnt->detach) (*tpnt->detach)(SDpnt);
+           if(SDpnt->attached == 0)
            {
-               if(SCpnt->device == SDpnt)
-               {
-                   if(SCpnt->prev != NULL)
-                       SCpnt->prev->next = SCpnt->next;
-                   if(SCpnt->next != NULL)
-                       SCpnt->next->prev = SCpnt->prev;
-                   if(SCpnt == SDpnt->host->host_queue)
-                       SDpnt->host->host_queue = SCpnt->next;
+                SDpnt->online = FALSE;
+
+                /*
+                * Nobody is using this device any more.  Free all of the
+                * command structures.
+                */
+               for(SCpnt = SDpnt->device_queue; SCpnt; 
+                    SCpnt = SCpnt->next)
+               {
+                   if(SCpnt == SDpnt->device_queue)
+                       SDpnt->device_queue = SCpnt->next;
                    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
-               }
+               }
+               SDpnt->has_cmdblocks = 0;
            }
-           SDpnt->has_cmdblocks = 0;
-       }
+        }
     }
     /*
      * Extract the template from the linked list.
@@ -3365,26 +3128,27 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
 
 int scsi_register_module(int module_type, void * ptr)
 {
-    switch(module_type){
+    switch(module_type)
+    {
     case MODULE_SCSI_HA:
        return scsi_register_host((Scsi_Host_Template *) ptr);
-
+        
        /* Load upper level device handler of some kind */
     case MODULE_SCSI_DEV:
 #ifdef CONFIG_KERNELD
        if (scsi_hosts == NULL)
-               request_module("scsi_hostadapter");
+            request_module("scsi_hostadapter");
 #endif
        return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
        /* The rest of these are not yet implemented */
-
+        
        /* Load constants.o */
     case MODULE_SCSI_CONST:
-
+        
        /* Load specialized ioctl handler for some device.  Intended for
         * cdroms that have non-SCSI2 audio command sets. */
     case MODULE_SCSI_IOCTL:
-
+        
     default:
        return 1;
     }
@@ -3392,7 +3156,8 @@ int scsi_register_module(int module_type, void * ptr)
 
 void scsi_unregister_module(int module_type, void * ptr)
 {
-    switch(module_type) {
+    switch(module_type) 
+    {
     case MODULE_SCSI_HA:
        scsi_unregister_host((Scsi_Host_Template *) ptr);
        break;
@@ -3410,65 +3175,123 @@ void scsi_unregister_module(int module_type, void * ptr)
 
 #endif         /* CONFIG_MODULES */
 
-#ifdef DEBUG_TIMEOUT
+/*
+ * Function:    scsi_dump_status
+ *
+ * Purpose:     Brain dump of scsi system, used for problem solving.
+ *
+ * Arguments:   level - used to indicate level of detail.
+ *
+ * Notes:       The level isn't used at all yet, but we need to find some way
+ *              of sensibly logging varying degrees of information.  A quick one-line
+ *              display of each command, plus the status would be most useful.
+ *
+ *              This does depend upon CONFIG_SCSI_LOGGING - I do want some way of turning
+ *              it all off if the user wants a lean and mean kernel.  It would probably
+ *              also be useful to allow the user to specify one single host to be dumped.
+ *              A second argument to the function would be useful for that purpose.
+ *
+ *              FIXME - some formatting of the output into tables would be very handy.
+ */
 static void
-scsi_dump_status(void)
+scsi_dump_status(int level)
 {
+#if CONFIG_PROC_FS
+#if CONFIG_SCSI_LOGGING /* { */
     int i;
     struct Scsi_Host * shpnt;
     Scsi_Cmnd * SCpnt;
-    printk("Dump of scsi parameters:\n");
+    Scsi_Device * SDpnt;
+    printk("Dump of scsi host parameters:\n");
     i = 0;
     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-       for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
+    {
+        printk(" %d %d %d : %d %p\n",
+               shpnt->host_failed,
+               shpnt->host_busy,
+               shpnt->host_active,
+               shpnt->host_blocked,
+               shpnt->pending_commands);
+
+    }
+
+    printk("\n\n");
+    printk("Dump of scsi command parameters:\n");
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+        printk("h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
+       for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
        {
-           /*  (0) 0:0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x      */
-           printk("(%d) %d:%d:%d:%d (%s %ld %ld %ld %d) (%d %d %x) (%d %d %d) %x %x %x\n",
-                  i++, SCpnt->host->host_no,
-                  SCpnt->channel,
-                  SCpnt->target,
-                  SCpnt->lun,
-                  kdevname(SCpnt->request.rq_dev),
-                  SCpnt->request.sector,
-                  SCpnt->request.nr_sectors,
-                  SCpnt->request.current_nr_sectors,
-                  SCpnt->use_sg,
-                  SCpnt->retries,
-                  SCpnt->allowed,
-                  SCpnt->flags,
-                  SCpnt->timeout_per_command,
-                  SCpnt->timeout,
-                  SCpnt->internal_timeout,
-                  SCpnt->cmnd[0],
-                  SCpnt->sense_buffer[2],
-                  SCpnt->result);
-       }
-    printk("wait_for_request = %p\n", wait_for_request);
-    /* Now dump the request lists for each block device */
-    printk("Dump of pending block device requests\n");
-    for(i=0; i<MAX_BLKDEV; i++)
-       if(blk_dev[i].current_request)
+            for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+            {
+                /*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x      */
+                printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
+                       i++, 
+
+                       SCpnt->host->host_no,
+                       SCpnt->channel,
+                       SCpnt->target,
+                       SCpnt->lun,
+
+                       kdevname(SCpnt->request.rq_dev),
+                       SCpnt->request.sector,
+                       SCpnt->request.nr_sectors,
+                       SCpnt->request.current_nr_sectors,
+                       SCpnt->request.rq_status,
+                       SCpnt->use_sg,
+
+                       SCpnt->retries,
+                       SCpnt->allowed,
+                       SCpnt->flags,
+
+                       SCpnt->timeout_per_command,
+                       SCpnt->timeout,
+                       SCpnt->internal_timeout,
+
+                       SCpnt->cmnd[0],
+                       SCpnt->sense_buffer[2],
+                       SCpnt->result);
+            }
+        }
+    }
+
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+       for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
        {
-           struct request * req;
-           printk("%d: ", i);
-           req = blk_dev[i].current_request;
-           while(req) {
-               printk("(%s %d %ld %ld %ld) ",
-                      kdevname(req->rq_dev),
-                      req->cmd,
-                      req->sector,
-                      req->nr_sectors,
-                      req->current_nr_sectors);
-               req = req->next;
-           }
-           printk("\n");
-       }
+            /* Now dump the request lists for each block device */
+            printk("Dump of pending block device requests\n");
+            for(i=0; i<MAX_BLKDEV; i++)
+            {
+                if(blk_dev[i].current_request)
+                {
+                    struct request * req;
+                    printk("%d: ", i);
+                    req = blk_dev[i].current_request;
+                    while(req) 
+                    {
+                        printk("(%s %d %ld %ld %ld) ",
+                               kdevname(req->rq_dev),
+                               req->cmd,
+                               req->sector,
+                               req->nr_sectors,
+                               req->current_nr_sectors);
+                        req = req->next;
+                    }
+                    printk("\n");
+                }
+            }
+        }
+    }
+    printk("wait_for_request = %p\n", wait_for_request);
+#endif /* CONFIG_SCSI_LOGGING */ /* } */
+#endif /* CONFIG_PROC_FS */
 }
-#endif
 
 #ifdef MODULE
 
-int init_module(void) {
+int init_module(void) 
+{
     unsigned long size;
 
     /*
@@ -3478,8 +3301,6 @@ int init_module(void) {
     dispatch_scsi_info_ptr = dispatch_scsi_info;
 #endif
 
-    timer_table[SCSI_TIMER].fn = scsi_main_timeout;
-    timer_table[SCSI_TIMER].expires = 0;
     scsi_loadable_module_flag = 1;
 
     /* Register the /proc/scsi/scsi entry */
@@ -3489,7 +3310,7 @@ int init_module(void) {
 
 
     dma_sectors = PAGE_SIZE / SECTOR_SIZE;
-    dma_free_sectors= dma_sectors;
+    scsi_dma_free_sectors= dma_sectors;
     /*
      * Set up a minimal DMA buffer list - this will be used during scan_scsis
      * in some cases.
@@ -3505,12 +3326,20 @@ int init_module(void) {
        scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC);
     dma_malloc_pages[0] = (unsigned char *)
        scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+
+    /*
+     * This is where the processing takes place for most everything
+     * when commands are completed.
+     */
+    init_bh(SCSI_BH, scsi_bottom_half_handler);
+
     return 0;
 }
 
 void cleanup_module( void)
 {
-    timer_active &= ~(1 << SCSI_TIMER);
+    remove_bh(SCSI_BH);
+
 #if CONFIG_PROC_FS
     proc_scsi_unregister(0, PROC_SCSI_SCSI);
 
@@ -3523,8 +3352,6 @@ void cleanup_module( void)
      */
     resize_dma_pool();
 
-    timer_table[SCSI_TIMER].fn = NULL;
-    timer_table[SCSI_TIMER].expires = 0;
 }
 #endif /* MODULE */
 
index dd0f18fa1edb9c6f246c751f6512d3b1ad96b570..808410dcec5b52192b6b4dfded3e1dc54888560c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/random.h>
 
 #include <asm/hardirq.h>
+#include <asm/scatterlist.h>
 #include <asm/io.h>
 
 /*
 #define MAX_SCSI_DEVICE_CODE 10
 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 
-extern void scsi_make_blocked_list(void);
-extern volatile int in_scan_scsis;
-extern const unsigned char scsi_command_size[8];
+/*
+ *  Use these to separate status msg and our bytes
+ *
+ *  These are set by:
+ *
+ *      status byte = set from target device
+ *      msg_byte    = return status from host adapter itself.
+ *      host_byte   = set by low-level driver to indicate status.
+ *      driver_byte = set by mid-level.
+ */
+#define status_byte(result) (((result) >> 1) & 0x1f)
+#define msg_byte(result)    (((result) >> 8) & 0xff)
+#define host_byte(result)   (((result) >> 16) & 0xff)
+#define driver_byte(result) (((result) >> 24) & 0xff)
+#define suggestion(result)  (driver_byte(result) & SUGGEST_MASK)
+
+#define sense_class(sense)  (((sense) >> 4) & 0x7)
+#define sense_error(sense)  ((sense) & 0xf)
+#define sense_valid(sense)  ((sense) & 0x80);
+
+#define NEEDS_RETRY     0x2001
+#define SUCCESS         0x2002
+#define FAILED          0x2003
+#define QUEUED          0x2004
+#define SOFT_ERROR      0x2005
+#define ADD_TO_MLQUEUE  0x2006
+
+/*
+ * These are the values that scsi_cmd->state can take.
+ */
+#define SCSI_STATE_TIMEOUT         0x1000
+#define SCSI_STATE_FINISHED        0x1001
+#define SCSI_STATE_FAILED          0x1002
+#define SCSI_STATE_QUEUED          0x1003
+#define SCSI_STATE_UNUSED          0x1006
+#define SCSI_STATE_DISCONNECTING   0x1008
+#define SCSI_STATE_INITIALIZING    0x1009
+#define SCSI_STATE_BHQUEUE         0x100a
+#define SCSI_STATE_MLQUEUE         0x100b
+
+/*
+ * These are the values that the owner field can take.
+ * They are used as an indication of who the command belongs to.
+ */
+#define SCSI_OWNER_HIGHLEVEL      0x100
+#define SCSI_OWNER_MIDLEVEL       0x101
+#define SCSI_OWNER_LOWLEVEL       0x102
+#define SCSI_OWNER_ERROR_HANDLER  0x103
+#define SCSI_OWNER_BH_HANDLER     0x104
+#define SCSI_OWNER_NOBODY         0x105
+
 #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
 
 #define IDENTIFY_BASE       0x80
@@ -50,6 +99,126 @@ extern const unsigned char scsi_command_size[8];
                     ((lun) & 0x07)) 
 
                 
+/*
+ * This defines the scsi logging feature.  It is a means by which the
+ * user can select how much information they get about various goings on,
+ * and it can be really useful for fault tracing.  The logging word is divided
+ * into 8 nibbles, each of which describes a loglevel.  The division of things
+ * is somewhat arbitrary, and the division of the word could be changed if it
+ * were really needed for any reason.  The numbers below are the only place where these
+ * are specified.  For a first go-around, 3 bits is more than enough, since this
+ * gives 8 levels of logging (really 7, since 0 is always off).  Cutting to 2 bits
+ * might be wise at some point.
+ */
+
+#define SCSI_LOG_ERROR_SHIFT              0
+#define SCSI_LOG_TIMEOUT_SHIFT            3
+#define SCSI_LOG_SCAN_SHIFT               6
+#define SCSI_LOG_MLQUEUE_SHIFT            9
+#define SCSI_LOG_MLCOMPLETE_SHIFT         12
+#define SCSI_LOG_LLQUEUE_SHIFT            15
+#define SCSI_LOG_LLCOMPLETE_SHIFT         18
+#define SCSI_LOG_HLQUEUE_SHIFT            21
+#define SCSI_LOG_HLCOMPLETE_SHIFT         24
+#define SCSI_LOG_IOCTL_SHIFT              27
+
+#define SCSI_LOG_ERROR_BITS               3
+#define SCSI_LOG_TIMEOUT_BITS             3
+#define SCSI_LOG_SCAN_BITS                3
+#define SCSI_LOG_MLQUEUE_BITS             3
+#define SCSI_LOG_MLCOMPLETE_BITS          3
+#define SCSI_LOG_LLQUEUE_BITS             3
+#define SCSI_LOG_LLCOMPLETE_BITS          3
+#define SCSI_LOG_HLQUEUE_BITS             3
+#define SCSI_LOG_HLCOMPLETE_BITS          3
+#define SCSI_LOG_IOCTL_BITS               3
+
+#if CONFIG_SCSI_LOGGING
+
+#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)     \
+{                                                       \
+        unsigned int mask;                              \
+                                                        \
+        mask = (1 << (BITS)) - 1;                       \
+        if( ((scsi_logging_level >> (SHIFT)) & mask) > (LEVEL) ) \
+        {                                               \
+                (CMD);                                  \
+        }                                              \
+}
+
+#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)            \
+{                                                       \
+        unsigned int mask;                              \
+                                                        \
+        mask = ((1 << (BITS)) - 1) << SHIFT;            \
+        scsi_logging_level = ((scsi_logging_level & ~mask) \
+                              | ((LEVEL << SHIFT) & mask));     \
+}
+
+
+
+#else
+
+/*
+ * With no logging enabled, stub these out so they don't do anything.
+ */
+#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)
+
+#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)
+#endif
+
+/*
+ * These are the macros that are actually used throughout the code to
+ * log events.  If logging isn't enabled, they are no-ops and will be
+ * completely absent from the user's code.
+ *
+ * The 'set' versions of the macros are really intended to only be called
+ * from the /proc filesystem, and in production kernels this will be about
+ * all that is ever used.  It could be useful in a debugging environment to
+ * bump the logging level when certain strange events are detected, however.
+ */
+#define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD);
+#define SCSI_LOG_TIMEOUT(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL,CMD);
+#define SCSI_LOG_SCAN_BUS(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL,CMD);
+#define SCSI_LOG_MLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_MLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_LLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_LLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_HLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_HLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_IOCTL(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD);
+    
+
+#define SCSI_SET_ERROR_RECOVERY_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL);
+#define SCSI_SET_TIMEOUT_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL);
+#define SCSI_SET_SCAN_BUS_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL);
+#define SCSI_SET_MLQUEUE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL);
+#define SCSI_SET_MLCOMPLETE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_LLQUEUE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL);
+#define SCSI_SET_LLCOMPLETE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_HLQUEUE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL);
+#define SCSI_SET_HLCOMPLETE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_IOCTL_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL);
     
 /*
  *  the return of the status word will be in the following format :
@@ -81,6 +250,7 @@ extern const unsigned char scsi_command_size[8];
 #define DID_ERROR       0x07 /* Internal error                          */
 #define DID_RESET       0x08 /* Reset by somebody.                      */
 #define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */ 
+#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
 #define DRIVER_OK       0x00 /* Driver status                           */ 
 
 /*
@@ -139,14 +309,107 @@ extern const unsigned char scsi_command_size[8];
 #define IS_ABORTING     0x10
 #define ASKED_FOR_SENSE 0x20
 
+
+#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
+
+/*
+ * This is the crap from the old error handling code.  We have it in a special
+ * place so that we can more easily delete it later on.
+ */
+#include "scsi_obsolete.h"
+
+/*
+ * Add some typedefs so that we can prototyope a bunch of the functions.
+ */
+typedef struct scsi_device Scsi_Device;
+typedef struct scsi_cmnd   Scsi_Cmnd;
+
+/*
+ * Here is where we prototype most of the mid-layer.
+ */
+
+/*
+ *  Initializes all SCSI devices.  This scans all scsi busses.
+ */ 
+
+extern int scsi_dev_init (void);
+
+
+
+void *   scsi_malloc(unsigned int);
+int      scsi_free(void *, unsigned int);
+extern unsigned int scsi_logging_level; /* What do we log? */
+extern unsigned int scsi_dma_free_sectors;  /* How much room do we have left */
+extern unsigned int scsi_need_isa_buffer;   /* True if some devices need indirection
+                                       * buffers */
+extern void scsi_make_blocked_list(void);
+extern volatile int in_scan_scsis;
+extern const unsigned char scsi_command_size[8];
+
+/*
+ * These are the error handling functions defined in scsi_error.c
+ */
+extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, 
+                                void (*complete)(Scsi_Cmnd *));
+extern void scsi_done (Scsi_Cmnd *SCpnt);
+extern int  scsi_delete_timer(Scsi_Cmnd * SCset);
+extern void scsi_error_handler(void * host);
+extern int  scsi_retry_command(Scsi_Cmnd *);
+extern void scsi_finish_command(Scsi_Cmnd *);
+extern int  scsi_sense_valid(Scsi_Cmnd *);
+extern int  scsi_decide_disposition (Scsi_Cmnd * SCpnt);
+extern int  scsi_block_when_processing_errors(Scsi_Device *);
+extern void scsi_sleep(int);
+
+/*
+ *  scsi_abort aborts the current command that is executing on host host.
+ *  The error code, if non zero is returned in the host byte, otherwise 
+ *  DID_ABORT is returned in the hostbyte.
+ */
+
+extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
+                        void *buffer, unsigned bufflen, 
+                        void (*done)(struct scsi_cmnd *),
+                        int timeout, int retries);
+
+
+extern Scsi_Cmnd * scsi_allocate_device(struct request **, Scsi_Device *, int);
+
+extern Scsi_Cmnd * scsi_request_queueable(struct request *, Scsi_Device *);
+
+extern void scsi_release_command(Scsi_Cmnd *);
+
+extern int max_scsi_hosts;
+
+extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
+
+extern void print_command(unsigned char *);
+extern void print_sense(const char *, Scsi_Cmnd *);
+extern void print_driverbyte(int scsiresult);
+extern void print_hostbyte(int scsiresult);
+
 /*
  *  The scsi_device struct contains what we know about each given scsi
  *  device.
  */
 
-typedef struct scsi_device {
+struct scsi_device {
+/* private: */
+    /*
+     * This information is private to the scsi mid-layer.  Wrapping it in a
+     * struct private is a way of marking it in a sort of C++ type of way.
+     */
     struct scsi_device * next;      /* Used for linked list */
-
+    struct scsi_device * prev;      /* Used for linked list */
+    struct wait_queue  * device_wait;/* Used to wait if
+                                                      device is busy */
+    struct Scsi_Host   * host;
+    volatile unsigned short device_busy;   /* commands actually active on low-level */
+    void              (* scsi_request_fn)(void);  /* Used to jumpstart things after an 
+                                     * ioctl */
+    Scsi_Cmnd          * device_queue;    /* queue of SCSI Command structures */
+
+/* public: */
     unsigned char id, lun, channel;
 
     unsigned int manufacturer;      /* Manufacturer of device, for using 
@@ -154,11 +417,7 @@ typedef struct scsi_device {
     int attached;                   /* # of high level drivers attached to 
                                     * this */
     int access_count;               /* Count of open channels/mounts */
-    struct wait_queue * device_wait;/* Used to wait if device is busy */
-    struct Scsi_Host * host;
-    void (*scsi_request_fn)(void);  /* Used to jumpstart things after an 
-                                    * ioctl */
-    struct scsi_cmnd *device_queue; /* queue of SCSI Command structures */
+
     void *hostdata;                 /* available to low-level driver */
     char type;
     char scsi_level;
@@ -168,6 +427,7 @@ typedef struct scsi_device {
     unsigned char sync_max_offset;  /* Not greater than this offset */
     unsigned char queue_depth;     /* How deep a queue to use */
 
+    unsigned online:1;
     unsigned writeable:1;
     unsigned removable:1; 
     unsigned random:1;
@@ -190,35 +450,8 @@ typedef struct scsi_device {
                                      * this device */
     unsigned expecting_cc_ua:1;     /* Expecting a CHECK_CONDITION/UNIT_ATTN
                                      * because we did a bus reset. */
-} Scsi_Device;
-
-/*
- *  Use these to separate status msg and our bytes
- */
-
-#define status_byte(result) (((result) >> 1) & 0x1f)
-#define msg_byte(result)    (((result) >> 8) & 0xff)
-#define host_byte(result)   (((result) >> 16) & 0xff)
-#define driver_byte(result) (((result) >> 24) & 0xff)
-#define suggestion(result)  (driver_byte(result) & SUGGEST_MASK)
-
-#define sense_class(sense)  (((sense) >> 4) & 0x7)
-#define sense_error(sense)  ((sense) & 0xf)
-#define sense_valid(sense)  ((sense) & 0x80);
-
-/*
- *  These are the SCSI devices available on the system.
- */
-
-extern Scsi_Device * scsi_devices;
-
-/*
- *  Initializes all SCSI devices.  This scans all scsi busses.
- */ 
-
-extern int scsi_dev_init (void);
-
-#include <asm/scatterlist.h>
+    unsigned device_blocked:1;      /* Device returned QUEUE_FULL. */
+};
 
 #ifdef __mc68000__
 #include <asm/pgtable.h>
@@ -229,109 +462,6 @@ extern int scsi_dev_init (void);
 #endif
 
 
-/*
- * These are the return codes for the abort and reset functions.  The mid-level
- * code uses these to decide what to do next.  Each of the low level abort
- * and reset functions must correctly indicate what it has done.
- * The descriptions are written from the point of view of the mid-level code,
- * so that the return code is telling the mid-level drivers exactly what
- * the low level driver has already done, and what remains to be done.
- */
-
-/* We did not do anything.  
- * Wait some more for this command to complete, and if this does not work, 
- * try something more serious. */ 
-#define SCSI_ABORT_SNOOZE 0
-
-/* This means that we were able to abort the command.  We have already
- * called the mid-level done function, and do not expect an interrupt that 
- * will lead to another call to the mid-level done function for this command */
-#define SCSI_ABORT_SUCCESS 1
-
-/* We called for an abort of this command, and we should get an interrupt 
- * when this succeeds.  Thus we should not restore the timer for this
- * command in the mid-level abort function. */
-#define SCSI_ABORT_PENDING 2
-
-/* Unable to abort - command is currently on the bus.  Grin and bear it. */
-#define SCSI_ABORT_BUSY 3
-
-/* The command is not active in the low level code. Command probably
- * finished. */
-#define SCSI_ABORT_NOT_RUNNING 4
-
-/* Something went wrong.  The low level driver will indicate the correct
- * error condition when it calls scsi_done, so the mid-level abort function
- * can simply wait until this comes through */
-#define SCSI_ABORT_ERROR 5
-
-/* We do not know how to reset the bus, or we do not want to.  Bummer.
- * Anyway, just wait a little more for the command in question, and hope that
- * it eventually finishes.  If it never finishes, the SCSI device could
- * hang, so use this with caution. */
-#define SCSI_RESET_SNOOZE 0
-
-/* We do not know how to reset the bus, or we do not want to.  Bummer.
- * We have given up on this ever completing.  The mid-level code will
- * request sense information to decide how to proceed from here. */
-#define SCSI_RESET_PUNT 1
-
-/* This means that we were able to reset the bus.  We have restarted all of
- * the commands that should be restarted, and we should be able to continue
- * on normally from here.  We do not expect any interrupts that will return
- * DID_RESET to any of the other commands in the host_queue, and the mid-level
- * code does not need to do anything special to keep the commands alive. 
- * If a hard reset was performed then all outstanding commands on the
- * bus have been restarted. */
-#define SCSI_RESET_SUCCESS 2
-
-/* We called for a reset of this bus, and we should get an interrupt 
- * when this succeeds.  Each command should get its own status
- * passed up to scsi_done, but this has not happened yet. 
- * If a hard reset was performed, then we expect an interrupt
- * for *each* of the outstanding commands that will have the
- * effect of restarting the commands.
- */
-#define SCSI_RESET_PENDING 3
-
-/* We did a reset, but do not expect an interrupt to signal DID_RESET.
- * This tells the upper level code to request the sense info, and this
- * should keep the command alive. */
-#define SCSI_RESET_WAKEUP 4
-
-/* The command is not active in the low level code. Command probably
-   finished. */
-#define SCSI_RESET_NOT_RUNNING 5
-
-/* Something went wrong, and we do not know how to fix it. */
-#define SCSI_RESET_ERROR 6
-
-#define SCSI_RESET_SYNCHRONOUS         0x01
-#define SCSI_RESET_ASYNCHRONOUS                0x02
-#define SCSI_RESET_SUGGEST_BUS_RESET   0x04
-#define SCSI_RESET_SUGGEST_HOST_RESET  0x08
-/*
- * This is a bitmask that is ored with one of the above codes.
- * It tells the mid-level code that we did a hard reset.
- */
-#define SCSI_RESET_BUS_RESET 0x100
-/*
- * This is a bitmask that is ored with one of the above codes.
- * It tells the mid-level code that we did a host adapter reset.
- */
-#define SCSI_RESET_HOST_RESET 0x200
-/*
- * Used to mask off bits and to obtain the basic action that was
- * performed.  
- */
-#define SCSI_RESET_ACTION   0xff
-
-void *   scsi_malloc(unsigned int);
-int      scsi_free(void *, unsigned int);
-extern unsigned int dma_free_sectors;  /* How much room do we have left */
-extern unsigned int need_isa_buffer;   /* True if some devices need indirection
-                                       * buffers */
-
 /*
  * The Scsi_Cmnd structure is used by scsi.c internally, and for communication
  * with low level drivers that support multiple outstanding commands.
@@ -349,43 +479,22 @@ typedef struct scsi_pointer {
     volatile int phase;
 } Scsi_Pointer;
 
-typedef struct scsi_cmnd {
+
+struct scsi_cmnd {
+/* private: */
+    /*
+     * This information is private to the scsi mid-layer.  Wrapping it in a
+     * struct private is a way of marking it in a sort of C++ type of way.
+     */
     struct Scsi_Host * host;
-    Scsi_Device * device;
-    unsigned char target, lun, channel;
-    unsigned char cmd_len;
-    unsigned char old_cmd_len;
-    struct scsi_cmnd *next, *prev, *device_next, *reset_chain;
+    unsigned short     state;
+    unsigned short     owner;
+    Scsi_Device      * device;
+    struct scsi_cmnd * next;
+    struct scsi_cmnd * reset_chain;
     
-    /* These elements define the operation we are about to perform */
-    unsigned char cmnd[12];
-    unsigned request_bufflen;  /* Actual request size */
-    
-    void * request_buffer;     /* Actual requested buffer */
-    
-    /* These elements define the operation we ultimately want to perform */
-    unsigned char data_cmnd[12];
-    unsigned short old_use_sg; /* We save  use_sg here when requesting
-                                * sense info */
-    unsigned short use_sg;     /* Number of pieces of scatter-gather */
-    unsigned short sglist_len; /* size of malloc'd scatter-gather list */
-    unsigned short abort_reason;/* If the mid-level code requests an
-                                * abort, this is the reason. */
-    unsigned bufflen;          /* Size of data buffer */
-    void *buffer;              /* Data buffer */
-    
-    unsigned underflow;                /* Return error if less than this amount is 
-                                * transfered */
-    
-    unsigned transfersize;     /* How much we are guaranteed to transfer with
-                                * each SCSI transfer (ie, between disconnect /
-                                * reconnects.   Probably == sector size */
-    
-    
-    struct request request;    /* A copy of the command we are working on */
-
-    unsigned char sense_buffer[16];  /* Sense for this command, if needed */
-
+    int                 eh_state; /* Used for state tracking in error handlr */
+    void               (*done)(struct scsi_cmnd *);  /* Mid-level done function */
     /*
       A SCSI Command is assigned a nonzero serial_number when internal_cmnd
       passes it to the driver's queue command function.  The serial_number
@@ -398,41 +507,96 @@ typedef struct scsi_cmnd {
       completed and the SCSI Command structure has already being reused
       for another command, so that we can avoid incorrectly aborting or
       resetting the new command.
-    */
-
-    unsigned long serial_number;
-    unsigned long serial_number_at_timeout;
-
-    int retries;
-    int allowed;
-    int timeout_per_command, timeout_total, timeout;
-
+      */
+    
+    unsigned long      serial_number;
+    unsigned long      serial_number_at_timeout;
+    
+    int                retries;
+    int                allowed;
+    int                timeout_per_command;
+    int                timeout_total;
+    int                timeout;
+    
     /*
-     * We handle the timeout differently if it happens when a reset, 
-     * abort, etc are in process. 
+     * We handle the timeout differently if it happens when a reset, 
+     * abort, etc are in process. 
      */
     unsigned volatile char internal_timeout;
+    struct scsi_cmnd  * bh_next;  /* To enumerate the commands waiting 
+                                     to be processed. */
+    
+/* public: */
+
+    unsigned char      target;
+    unsigned char      lun;
+    unsigned char      channel;
+    unsigned char      cmd_len;
+    unsigned char      old_cmd_len;
+
+    /* These elements define the operation we are about to perform */
+    unsigned char      cmnd[12];
+    unsigned           request_bufflen;        /* Actual request size */
+    
+    struct timer_list  eh_timeout;         /* Used to time out the command. */
+    void             * request_buffer; /* Actual requested buffer */
     
-    unsigned flags;
+    /* These elements define the operation we ultimately want to perform */
+    unsigned char      data_cmnd[12];
+    unsigned short     old_use_sg;     /* We save  use_sg here when requesting
+                                         * sense info */
+    unsigned short     use_sg;          /* Number of pieces of scatter-gather */
+    unsigned short     sglist_len;     /* size of malloc'd scatter-gather list */
+    unsigned short     abort_reason;    /* If the mid-level code requests an
+                                         * abort, this is the reason. */
+    unsigned           bufflen;                /* Size of data buffer */
+    void             * buffer;         /* Data buffer */
+    
+    unsigned           underflow;      /* Return error if less than
+                                           this amount is transfered */
+    
+    unsigned           transfersize;   /* How much we are guaranteed to
+                                           transfer with each SCSI transfer
+                                           (ie, between disconnect / 
+                                           reconnects.  Probably == sector
+                                           size */
+    
+    
+    struct request     request;           /* A copy of the command we are
+                                             working on */
+
+    unsigned char      sense_buffer[16];  /* Sense for this command, 
+                                             needed */
     
+    unsigned           flags;
+    
+    /*
+     * These two flags are used to track commands that are in the
+     * mid-level queue.  The idea is that a command can be there for
+     * one of two reasons - either the host is busy or the device is
+     * busy.  Thus when a command on the host finishes, we only try
+     * and requeue commands that we might expect to be queueable.
+     */
+    unsigned           host_wait:1;
+    unsigned           device_wait:1;
+
     /* These variables are for the cdrom only. Once we have variable size 
      * buffers in the buffer cache, they will go away. */
-    int this_count; 
+    int                this_count; 
     /* End of special cdrom variables */
     
     /* Low-level done function - can be used by low-level driver to point
      * to completion function.  Not used by mid/upper level code. */
-    void (*scsi_done)(struct scsi_cmnd *);  
-    void (*done)(struct scsi_cmnd *);  /* Mid-level done function */
+    void               (*scsi_done)(struct scsi_cmnd *);  
     
     /*
      * The following fields can be written to by the host specific code. 
      * Everything else should be left alone. 
      */
     
-    Scsi_Pointer SCp;  /* Scratchpad used by some host adapters */
+    Scsi_Pointer       SCp;       /* Scratchpad used by some host adapters */
     
-    unsigned char * host_scribble; /* The host adapter is allowed to
+    unsigned char    * host_scribble; /* The host adapter is allowed to
                                    * call scsi_malloc and get some memory
                                    * and hang it here.  The host adapter
                                    * is also expected to call scsi_free
@@ -440,42 +604,22 @@ typedef struct scsi_cmnd {
                                    * obtained by scsi_malloc is guaranteed
                                    * to be at an address < 16Mb). */
     
-    int result;                           /* Status code from lower level driver */
+    int                result;    /* Status code from lower level driver */
     
-    unsigned char tag;            /* SCSI-II queued command tag */
-    unsigned long pid;            /* Process ID, starts at 0 */
-} Scsi_Cmnd;        
+    unsigned char      tag;       /* SCSI-II queued command tag */
+    unsigned long      pid;       /* Process ID, starts at 0 */
+};
+
 
 /*
- *  scsi_abort aborts the current command that is executing on host host.
- *  The error code, if non zero is returned in the host byte, otherwise 
- *  DID_ABORT is returned in the hostbyte.
+ * Definitions and prototypes used for scsi mid-level queue.
  */
+#define SCSI_MLQUEUE_HOST_BUSY   0x1055
+#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
 
-extern int scsi_abort (Scsi_Cmnd *, int code);
-
-extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
-                        void *buffer, unsigned bufflen, 
-                        void (*done)(struct scsi_cmnd *),
-                        int timeout, int retries);
-
-
-extern Scsi_Cmnd * allocate_device(struct request **, Scsi_Device *, int);
-
-extern Scsi_Cmnd * request_queueable(struct request *, Scsi_Device *);
-extern int scsi_reset (Scsi_Cmnd *, unsigned int);
-
-extern int max_scsi_hosts;
-
-extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
-
-extern void print_command(unsigned char *);
-extern void print_sense(const char *, Scsi_Cmnd *);
-extern void print_driverbyte(int scsiresult);
-extern void print_hostbyte(int scsiresult);
+extern scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason);
+extern scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device);
 
-extern void scsi_mark_host_reset(struct Scsi_Host *Host);
-extern void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel);
 
 #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
 #include "hosts.h"
@@ -527,9 +671,9 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
            wake_up(&next->host_wait);
     }
     
-    req->rq_status = RQ_INACTIVE;
     wake_up(&wait_for_request);
     wake_up(&SCpnt->device->device_wait);
+    scsi_release_command(SCpnt);
     return NULL;
 }
 
index b623ae1245262be5088b4269c4ee9db11d9f2884..58b19f72283fa98f23e7b5b23b503f38dceec1be 100644 (file)
@@ -43,9 +43,16 @@ struct proc_dir_entry proc_scsi_scsi_debug = {
 
 /* A few options that we want selected */
 
+#define NR_HOSTS_PRESENT 1
+#define NR_FAKE_DISKS   3
+#define N_HEAD          32
+#define N_SECTOR        64
+#define DISK_READONLY(TGT)      (1)
+#define DISK_REMOVEABLE(TGT)    (1)
+
 /* Do not attempt to use a timer to simulate a real disk with latency */
 /* Only use this in the actual kernel, not in the simulator. */
-#define IMMEDIATE
+/* #define IMMEDIATE */
 
 /* Skip some consistency checking.  Good for benchmarking */
 #define SPEEDY
@@ -58,12 +65,12 @@ static int NR_REAL=-1;
 #define MAJOR_NR 8
 #endif
 #define START_PARTITION 4
-#define SCSI_DEBUG_TIMER 20
+
 /* Number of jiffies to wait before completing a command */
 #define DISK_SPEED     10
 #define CAPACITY (0x80000)
 
-static int starts[] = {4, 1000, 50000, CAPACITY, 0};
+static int starts[] = {N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0};
 static int npart = 0;
 
 #include "scsi_debug.h"
@@ -74,8 +81,8 @@ static int npart = 0;
 #endif
 
 #ifdef SPEEDY
-#define VERIFY1_DEBUG(RW) 1
-#define VERIFY_DEBUG(RW) 1
+#define VERIFY1_DEBUG(RW) 
+#define VERIFY_DEBUG(RW) 
 #else
 
 #define VERIFY1_DEBUG(RW)                           \
@@ -111,12 +118,16 @@ static int npart = 0;
     };
 #endif
 
-static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };
-extern void scsi_debug_interrupt();
+typedef void (*done_fct_t)(Scsi_Cmnd *);
+
+static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL, };
+
+static void scsi_debug_intr_handle(unsigned long);
 
-volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
+static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
+
+Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
 static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
-static volatile unsigned int timeout[8] ={0,};
 
 /*
  * Semaphore used to simulate bus lockups.
@@ -137,11 +148,11 @@ static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
        sgpnt = (struct scatterlist *) SCpnt->buffer;
        for(i=0; i<SCpnt->use_sg; i++) {
            lpnt = (int *) sgpnt[i].alt_address;
-           printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+           printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
            if (lpnt) printk(" (Alt %x) ",lpnt[15]);
        };
     } else {
-       printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+       printk("nosg: %p %p %d\n",SCpnt->request.buffer, SCpnt->buffer,
               SCpnt->bufflen);
        lpnt = (int *) SCpnt->request.buffer;
        if (lpnt) printk(" (Alt %x) ",lpnt[15]);
@@ -167,14 +178,14 @@ static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
     };
     printk("\n");
 #endif
-    printk("DMA free %d sectors.\n", dma_free_sectors);
+    printk("DMA free %d sectors.\n", scsi_dma_free_sectors);
 }
 
 int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 {
     unchar *cmd = (unchar *) SCpnt->cmnd;
     struct partition * p;
-    int block, start;
+    int block;
     struct buffer_head * bh = NULL;
     unsigned char * buff;
     int nbytes, sgcount;
@@ -187,15 +198,28 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     sgcount = 0;
     sgpnt = NULL;
     
-    DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});
+    /*
+     * If we are being notified of the mid-level reposessing a command due to timeout,
+     * just return.
+     */
+    if( done == NULL )
+    {
+        return 0;
+    }
+
+    DEB(if (target >= NR_FAKE_DISKS) 
+        { 
+            SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;
+        });
     
     buff = (unsigned char *) SCpnt->request_buffer;
     
-    if(target>=1 || SCpnt->lun != 0) {
+    if(target>=NR_FAKE_DISKS || SCpnt->lun != 0) 
+    {
        SCpnt->result =  DID_NO_CONNECT << 16;
        done(SCpnt);
        return 0;
-    };
+    }
     
     if( SCrst[target] != 0 && !scsi_debug_lockup )
     {
@@ -208,11 +232,11 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     }
     switch(*cmd){
     case REQUEST_SENSE:
-       printk("Request sense...\n");
+       SCSI_LOG_LLQUEUE(3,printk("Request sense...\n"));
 #ifndef DEBUG
        { 
            int i;
-           printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
+           printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
            for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
            printk("\n");
        };
@@ -224,15 +248,21 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
        done(SCpnt); 
        return 0;
     case ALLOW_MEDIUM_REMOVAL:
-       if(cmd[4]) printk("Medium removal inhibited...");
-       else printk("Medium removal enabled...");
+       if(cmd[4]) 
+        {
+            SCSI_LOG_LLQUEUE(2,printk("Medium removal inhibited..."));
+        }
+       else
+        {
+            SCSI_LOG_LLQUEUE(2,printk("Medium removal enabled..."));
+        }
        scsi_debug_errsts = 0;
        break;
     case INQUIRY:
-       printk("Inquiry...(%x %d)\n", buff, bufflen);
+       SCSI_LOG_LLQUEUE(3,printk("Inquiry...(%p %d)\n", buff, bufflen));
        memset(buff, 0, bufflen);
        buff[0] = TYPE_DISK;
-       buff[1] = 0x80;  /* Removable disk */
+       buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;  /* Removable disk */
        buff[2] = 1;
        buff[4] = 33 - 5;
        memcpy(&buff[8],"Foo Inc",7);
@@ -241,13 +271,13 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
        scsi_debug_errsts = 0;
        break;
     case TEST_UNIT_READY:
-       printk("Test unit ready(%x %d)\n", buff, bufflen);
+       SCSI_LOG_LLQUEUE(3,printk("Test unit ready(%p %d)\n", buff, bufflen));
        if (buff)
            memset(buff, 0, bufflen);
        scsi_debug_errsts = 0;
        break;
     case READ_CAPACITY:
-       printk("Read Capacity\n");
+       SCSI_LOG_LLQUEUE(3,printk("Read Capacity\n"));
        if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
        memset(buff, 0, bufflen);
        buff[0] = (CAPACITY >> 24);
@@ -308,6 +338,12 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
                    p->start_sect = starts[npart];
                    p->nr_sects = starts[npart+1] - starts [npart];
                    p->sys_ind = 0x81;  /* Linux partition */
+                    p->head       = (npart == 0 ? 1 : 0);
+                    p->sector     = 1;
+                    p->cyl        = starts[npart] / N_HEAD / N_SECTOR;
+                    p->end_head   = N_HEAD - 1;
+                    p->end_sector = N_SECTOR;
+                    p->end_cyl    = starts[npart + 1] / N_HEAD / N_SECTOR;
                    p++;
                    npart++;
                };
@@ -365,7 +401,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
        
        SCpnt->result = 0;
        (done)(SCpnt);
-       return;
+       return 0;
        
        if (SCpnt->use_sg && !scsi_debug_errsts)
            if(bh) scsi_dump(SCpnt, 0);
@@ -396,8 +432,15 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 #endif
        scsi_debug_errsts = 0;
        break;
+    case MODE_SENSE:
+        /*
+         * Used to detect write protected status.
+         */
+       scsi_debug_errsts = 0;
+        memset(buff, 0, 6);
+        break;
     default:
-       printk("Unknown command %d\n",*cmd);
+       SCSI_LOG_LLQUEUE(3,printk("Unknown command %d\n",*cmd));
        SCpnt->result =  DID_NO_CONNECT << 16;
        done(SCpnt);
        return 0;
@@ -406,45 +449,45 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     save_flags(flags); 
     cli();
     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){
-       if (SCint[i] == 0) break;
+        if( timeout[i].function == NULL ) break;
     };
     
-    if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0) 
-       panic("Unable to find empty SCSI_DEBUG command slot.\n");
-    
-    SCint[i] = SCpnt;
-    
-    if (done) {
-       DEB(printk("scsi_debug_queuecommand: now waiting for interrupt "););
-       if (do_done[i])
-           printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
-       else
-           do_done[i] = done;
+    /*
+     * If all of the slots are full, just return 1.  The new error handling scheme
+     * allows this, and the mid-level should queue things.
+     */
+    if (i >= SCSI_DEBUG_MAILBOXES ||  timeout[i].function != 0)
+    {
+        SCSI_LOG_LLQUEUE(1,printk("Command rejected - host busy\n"));
+        restore_flags(flags);
+        return 1;
     }
-    else
-       printk("scsi_debug_queuecommand: done can't be NULL\n");
+
+    SCSI_LOG_LLQUEUE(1,printk("Command accepted - slot %d\n", i));
     
 #ifdef IMMEDIATE
     if( !scsi_debug_lockup )
     {
         SCpnt->result = scsi_debug_errsts;
-        scsi_debug_intr_handle();  /* No timer - do this one right away */
+        scsi_debug_intr_handle(i);  /* No timer - do this one right away */
     }
     restore_flags(flags);
 #else
-    timeout[i] = jiffies+DISK_SPEED;
-    
-    /* If no timers active, then set this one */
-    if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) {
-       timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
-       timer_active |= 1 << SCSI_DEBUG_TIMER;
-    };
-    
+        
     SCpnt->result = scsi_debug_errsts;
+    timeout[i].function = scsi_debug_intr_handle;
+    timeout[i].data     = i;
+    timeout[i].expires  = jiffies + DISK_SPEED;
+    SCint[i]   = SCpnt;
+    do_done[i] = done;
+    
     restore_flags(flags);
+    add_timer(&timeout[i]);
+    if (!done)
+       panic("scsi_debug_queuecommand: done can't be NULL\n");
     
 #if 0
-    printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies);
+    printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires,jiffies);
 #endif
 #endif
     
@@ -472,92 +515,52 @@ int scsi_debug_command(Scsi_Cmnd * SCpnt)
 /* A "high" level interrupt handler.  This should be called once per jiffy
  * to simulate a regular scsi disk.  We use a timer to do this. */
 
-static void scsi_debug_intr_handle(void)
+static void scsi_debug_intr_handle(unsigned long indx)
 {
     Scsi_Cmnd * SCtmp;
-    int i, pending;
+    int pending;
     void (*my_done)(Scsi_Cmnd *); 
     unsigned long flags;
     int to;
     
-#ifndef IMMEDIATE
-    timer_table[SCSI_DEBUG_TIMER].expires = 0;
-    timer_active &= ~(1 << SCSI_DEBUG_TIMER);
+#if 0
+    del_timer(&timeout[indx]);
 #endif
     
- repeat:
-    save_flags(flags);
-    cli();
-    for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
-       if (SCint[i] == 0) continue;
-#ifndef IMMEDIATE
-       if (timeout[i] == 0) continue;
-       if (timeout[i] <= jiffies) break;
-#else
-       break;
-#endif
-    };
+    SCtmp                  = (Scsi_Cmnd *) SCint[indx];
+    my_done                = do_done[indx];
+    do_done[indx]          = NULL;
+    timeout[indx].function = NULL;
+    SCint[indx]            = NULL;
     
-    if(i == SCSI_DEBUG_MAILBOXES){
-#ifndef IMMEDIATE
-       pending = INT_MAX;
-       for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
-           if (SCint[i] == 0) continue;
-           if (timeout[i] == 0) continue;
-           if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;};
-           if (timeout[i] > jiffies) {
-               if (pending > timeout[i]) pending = timeout[i];
-               continue;
-           };
-       };
-       if (pending && pending != INT_MAX) {
-           timer_table[SCSI_DEBUG_TIMER].expires = 
-               (pending <= jiffies ? jiffies+1 : pending);
-           timer_active |= 1 << SCSI_DEBUG_TIMER;
-       };
-       restore_flags(flags);
-#endif
-       return;
-    };
+    if (!my_done) {
+      printk("scsi_debug_intr_handle: Unexpected interrupt\n"); 
+      return;
+    }
     
-    if(i < SCSI_DEBUG_MAILBOXES){
-       timeout[i] = 0;
-       my_done = do_done[i];
-       do_done[i] = NULL;
-       to = timeout[i];
-       timeout[i] = 0;
-       SCtmp = (Scsi_Cmnd *) SCint[i];
-       SCint[i] = NULL;
-       restore_flags(flags);
-       
-       if (!my_done) {
-           printk("scsi_debug_intr_handle: Unexpected interrupt\n"); 
-           return;
-       }
-       
 #ifdef DEBUG
-       printk("In intr_handle...");
-       printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
-       printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
+    printk("In intr_handle...");
+    printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
+    printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
 #endif
-       
-       my_done(SCtmp);
+    
+    my_done(SCtmp);
 #ifdef DEBUG
-       printk("Called done.\n");
+    printk("Called done.\n");
 #endif
-    };
-    goto repeat;
 }
 
 
 int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
-    tpnt->proc_dir = &proc_scsi_scsi_debug;
-#ifndef IMMEDIATE
-    timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle;
-    timer_table[SCSI_DEBUG_TIMER].expires = 0;
-#endif
-    return 1;
+    int i;
+
+    for(i=0; i < NR_HOSTS_PRESENT; i++)
+    {
+        tpnt->proc_dir = &proc_scsi_scsi_debug;
+        scsi_register(tpnt,0);
+    }
+    return NR_HOSTS_PRESENT;
 }
 
 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
@@ -587,20 +590,20 @@ int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 
 int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){
     int size = disk->capacity;
-    info[0] = 32;
-    info[1] = 64;
+    info[0] = N_HEAD;
+    info[1] = N_SECTOR;
     info[2] = (size + 2047) >> 11;
     if (info[2] >= 1024) info[2] = 1024;
     return 0;
 }
 
-int scsi_debug_reset(Scsi_Cmnd * SCpnt)
+int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
 {
     int i;
     unsigned long flags;
     
     void (*my_done)(Scsi_Cmnd *);
-    printk("Bus unlocked by reset(%d)\n", SCpnt->host->suggest_bus_reset);
+    printk("Bus unlocked by reset - %d\n", why);
     scsi_debug_lockup = 0;
     DEB(printk("scsi_debug_reset called\n"));
     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
@@ -610,9 +613,9 @@ int scsi_debug_reset(Scsi_Cmnd * SCpnt)
         my_done(SCint[i]);
         save_flags(flags);
         cli();
-        SCint[i] = NULL;
-        do_done[i] = NULL;
-        timeout[i] = 0;
+        SCint[i]            = NULL;
+        do_done[i]          = NULL;
+        timeout[i].function = NULL;
         restore_flags(flags);
     }
     return SCSI_RESET_SUCCESS;
@@ -633,12 +636,21 @@ int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
     int len, pos, begin;
     int orig_length;
 
+    orig_length = length;
+
     if(inout == 1)
     {
         /* First check for the Signature */
         if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
             buffer += 11;
             length -= 11;
+
+            if( buffer[length - 1] == '\n' )
+            {
+                buffer[length-1] = '\0';
+                length--;
+            }
+
             /*
              * OK, we are getting some kind of command.  Figure out
              * what we are supposed to do here.  Simulate bus lockups
@@ -647,18 +659,18 @@ int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
             if( length == 6 && strncmp(buffer, "lockup", length) == 0 )
             {
                 scsi_debug_lockup = 1;
-                return length;
+                return orig_length;
             } 
             
             if( length == 6 && strncmp(buffer, "unlock", length) == 0 )
             {
                 scsi_debug_lockup = 0;
-                return length;
+                return orig_length;
             } 
             
-            printk("Unknown command:%s\n", buffer);
+            printk("Unknown command:%s (%d)\n", buffer, length);
         } else 
-            printk("Wrong Signature:%10s\n", (char *) ((ulong)buffer-11));
+            printk("Wrong Signature:%10s\n", (char *) buffer);
 
         return -EINVAL;
         
index 87ae155f6f94f32cecaa3febeb8511f4fbd16797..43c11af576e825d48505e5c206db87ad1d6b3156 100644 (file)
@@ -8,7 +8,7 @@ int scsi_debug_command(Scsi_Cmnd *);
 int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int scsi_debug_abort(Scsi_Cmnd *);
 int scsi_debug_biosparam(Disk *, kdev_t, int[]);
-int scsi_debug_reset(Scsi_Cmnd *);
+int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
 int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
  
 #ifndef NULL
@@ -16,15 +16,28 @@ int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
 #endif
 
 
-#define SCSI_DEBUG_MAILBOXES 8
+#define SCSI_DEBUG_MAILBOXES 1
 
-#define SCSI_DEBUG {NULL, NULL, NULL, scsi_debug_proc_info, \
-               "SCSI DEBUG", scsi_debug_detect, NULL, \
-               NULL, scsi_debug_command,               \
-               scsi_debug_queuecommand,                        \
-               scsi_debug_abort,                               \
-               scsi_debug_reset,                               \
-               NULL,                                           \
-               scsi_debug_biosparam,                           \
-               SCSI_DEBUG_MAILBOXES, 7, SG_ALL, 1, 0, 1, ENABLE_CLUSTERING}
+/*
+ * Allow the driver to reject commands.  Thus we accept only one, but
+ * and the mid-level will queue the remainder.
+ */
+#define SCSI_DEBUG_CANQUEUE  255
+
+#define SCSI_DEBUG {proc_info:         scsi_debug_proc_info,   \
+                   name:              "SCSI DEBUG",            \
+                   detect:            scsi_debug_detect,       \
+                   command:           scsi_debug_command,      \
+                   queuecommand:      scsi_debug_queuecommand, \
+                   abort:             scsi_debug_abort,        \
+                   reset:             scsi_debug_reset,        \
+                   bios_param:        scsi_debug_biosparam,    \
+                   can_queue:         SCSI_DEBUG_CANQUEUE,     \
+                   this_id:           7,                       \
+                   sg_tablesize:      SG_ALL,                  \
+                   cmd_per_lun:       3,                       \
+                   unchecked_isa_dma: 1,                       \
+                   use_clustering:    ENABLE_CLUSTERING,       \
+                   use_new_eh_code:   1,                       \
+}
 #endif
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
new file mode 100644 (file)
index 0000000..771f141
--- /dev/null
@@ -0,0 +1,1895 @@
+/*
+ *  scsi_error.c Copyright (C) 1997 Eric Youngdale
+ *
+ *  SCSI error/timeout handling
+ *      Initial versions: Eric Youngdale.  Based upon conversations with
+ *                       Leonard Zubkoff and David Miller at Linux Expo, 
+ *                       ideas originating from all over the place.
+ *
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/smp_lock.h>
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#define SHUTDOWN_SIGS  (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+#ifdef DEBUG
+    #define SENSE_TIMEOUT SCSI_TIMEOUT
+    #define ABORT_TIMEOUT SCSI_TIMEOUT
+    #define RESET_TIMEOUT SCSI_TIMEOUT
+#else
+    #define SENSE_TIMEOUT (10*HZ)
+    #define RESET_TIMEOUT (2*HZ)
+    #define ABORT_TIMEOUT (15*HZ)
+#endif
+
+#define STATIC
+
+/*
+ * These should *probably* be handled by the host itself.
+ * Since it is allowed to sleep, it probably should.
+ */
+#define BUS_RESET_SETTLE_TIME   5*HZ
+#define HOST_RESET_SETTLE_TIME  10*HZ
+
+
+static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_error.c,v 1.9 1997/12/07 23:38:23 eric Exp $";
+
+STATIC int         scsi_check_sense (Scsi_Cmnd * SCpnt);
+STATIC int         scsi_request_sense(Scsi_Cmnd *);
+STATIC void        scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout);
+STATIC int         scsi_try_to_abort_command(Scsi_Cmnd *, int);
+STATIC int         scsi_test_unit_ready(Scsi_Cmnd *);
+STATIC int         scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout);
+STATIC int         scsi_try_bus_reset(Scsi_Cmnd *);
+STATIC int         scsi_try_host_reset(Scsi_Cmnd *);
+STATIC int         scsi_unit_is_ready(Scsi_Cmnd *);
+STATIC void        scsi_eh_action_done(Scsi_Cmnd *, int);
+STATIC int         scsi_eh_retry_command(Scsi_Cmnd *);
+STATIC int        scsi_eh_completed_normally(Scsi_Cmnd * SCpnt);
+STATIC void        scsi_restart_operations(struct Scsi_Host *);
+STATIC void        scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt);
+
+
+/*
+ * Function:    scsi_add_timer()
+ *
+ * Purpose:     Start timeout timer for a single scsi command.
+ *
+ * Arguments:   SCset   - command that is about to start running.
+ *              timeout - amount of time to allow this command to run.
+ *              complete - timeout function to call if timer isn't
+ *                      canceled.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:      This should be turned into an inline function.
+ *
+ * More Notes:  Each scsi command has it's own timer, and as it is added to
+ *              the queue, we set up the timer.  When the command completes,
+ *              we cancel the timer.  Pretty simple, really, especially
+ *              compared to the old way of handling this crap.
+ */
+void
+scsi_add_timer(Scsi_Cmnd * SCset, 
+                       int timeout, 
+                       void (*complete)(Scsi_Cmnd *))
+{
+
+    /*
+     * If the clock was already running for this command, then
+     * first delete the timer.  The timer handling code gets rather
+     * confused if we don't do this.
+     */
+    if( SCset->eh_timeout.function != NULL )
+    {
+        del_timer(&SCset->eh_timeout);
+    }
+
+    SCset->eh_timeout.data = (unsigned long) SCset;
+    SCset->eh_timeout.expires = jiffies + timeout;
+    SCset->eh_timeout.function = (void (*)(unsigned long))complete;
+    
+    SCSI_LOG_ERROR_RECOVERY(5,printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete));
+    
+    add_timer(&SCset->eh_timeout);
+
+}
+
+/*
+ * Function:    scsi_delete_timer()
+ *
+ * Purpose:     Delete/cancel timer for a given function.
+ *
+ * Arguments:   SCset   - command that we are canceling timer for.
+ *
+ * Returns:     Amount of time remaining before command would have timed out.
+ *
+ * Notes:      This should be turned into an inline function.
+ */
+int
+scsi_delete_timer(Scsi_Cmnd * SCset)
+{
+  int rtn;
+
+  rtn = jiffies - SCset->eh_timeout.expires;
+  del_timer(&SCset->eh_timeout);
+
+  SCSI_LOG_ERROR_RECOVERY(5,printk("Clearing timer for command %p\n", SCset));
+
+  SCset->eh_timeout.data = (unsigned long) NULL;
+  SCset->eh_timeout.expires = 0;
+  SCset->eh_timeout.function = NULL;
+
+  return rtn;
+}
+
+/*
+ * Function:    scsi_times_out()
+ *
+ * Purpose:     Timeout function for normal scsi commands..
+ *
+ * Arguments:   SCpnt   - command that is timing out.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:
+ */
+void scsi_times_out (Scsi_Cmnd * SCpnt)
+{
+
+    /* 
+     * Notify the low-level code that this operation failed and we are
+     * reposessing the command.  
+     */
+#ifdef ERIC_neverdef
+    /*
+     * FIXME(eric)
+     * Allow the host adapter to push a queue ordering tag
+     * out to the bus to force the command in question to complete.
+     * If the host wants to do this, then we just restart the timer
+     * for the command.  Before we really do this, some real thought
+     * as to the optimum way to handle this should be done.  We *do*
+     * need to force ordering every so often to ensure that all requests
+     * do eventually complete, but I am not sure if this is the best way
+     * to actually go about it.
+     *
+     * Better yet, force a sync here, but don't block since we are in an
+     * interrupt.
+     */
+    if( SCpnt->host->hostt->eh_ordered_queue_tag )
+    {
+        if( (*SCpnt->host->hostt->eh_ordered_queue_tag)(SCpnt))
+        {
+            scsi_add_timer(SCpnt, SCpnt->internal_timeout,
+                           scsi_times_out);
+            return;
+        }
+    }
+    /*
+     * FIXME(eric) - add a second special interface to handle this
+     * case.  Ideally that interface can also be used to request
+     * a queu
+     */
+     if (SCpnt->host->can_queue)
+     {
+         SCpnt->host->hostt->queuecommand (SCpnt, NULL);
+     }
+#endif
+
+    SCpnt->state = SCSI_STATE_TIMEOUT;
+    SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+    
+    SCpnt->host->in_recovery = 1;
+    SCpnt->host->host_failed++;
+    
+    SCSI_LOG_TIMEOUT(3,printk("Command timed out active=%d busy=%d failed=%d\n", 
+                              atomic_read(&SCpnt->host->host_active),
+                              SCpnt->host->host_busy, 
+                              SCpnt->host->host_failed));
+    
+    /*
+     * If the host is having troubles, then look to see if this was the last
+     * command that might have failed.  If so, wake up the error handler.
+     */
+    if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+    {
+        up(SCpnt->host->eh_wait);
+    }
+}
+
+/*
+ * Function     scsi_block_when_processing_errors
+ *
+ * Purpose:     Prevent more commands from being queued while error recovery
+ *              is taking place.
+ *
+ * Arguments:   SDpnt - device on which we are performing recovery.
+ *
+ * Returns:     FALSE   The device was taken offline by error recovery.
+ *              TRUE    OK to proceed.
+ *
+ * Notes:       We block until the host is out of error recovery, and then
+ *              check to see whether the host or the device is offline.
+ */
+int  
+scsi_block_when_processing_errors(Scsi_Device * SDpnt)
+{
+
+  SCSI_SLEEP( &SDpnt->host->host_wait, SDpnt->host->in_recovery);
+
+  SCSI_LOG_ERROR_RECOVERY(5,printk("Open returning %d\n", SDpnt->online));
+
+  return SDpnt->online;
+}
+
+/*
+ * Function:    scsi_eh_times_out()
+ *
+ * Purpose:     Timeout function for error handling.
+ *
+ * Arguments:   SCpnt   - command that is timing out.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:      During error handling, the kernel thread will be sleeping
+ *             waiting for some action to complete on the device.  Our only
+ *             job is to record that it timed out, and to wake up the
+ *             thread.
+ */
+STATIC
+void scsi_eh_times_out (Scsi_Cmnd * SCpnt)
+{
+  SCpnt->request.rq_status = RQ_SCSI_DONE;
+  SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+  SCpnt->eh_state = SCSI_STATE_TIMEOUT;
+
+  SCSI_LOG_ERROR_RECOVERY(5,printk("In scsi_eh_times_out %p\n", SCpnt));
+
+  if (SCpnt->host->eh_action != NULL)
+    up(SCpnt->host->eh_action);
+  else
+    panic("Missing scsi error handler thread");
+}
+
+
+/*
+ * Function:    scsi_eh_done()
+ *
+ * Purpose:     Completion function for error handling.
+ *
+ * Arguments:   SCpnt   - command that is timing out.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:      During error handling, the kernel thread will be sleeping
+ *             waiting for some action to complete on the device.  Our only
+ *             job is to record that the action completed, and to wake up the
+ *             thread.
+ */
+STATIC
+void scsi_eh_done (Scsi_Cmnd * SCpnt)
+{
+  SCpnt->request.rq_status = RQ_SCSI_DONE;
+  
+  SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+  SCpnt->eh_state = SUCCESS;
+
+  SCSI_LOG_ERROR_RECOVERY(5,printk("In eh_done %p result:%x\n", SCpnt, 
+                                   SCpnt->result));
+
+  if (SCpnt->host->eh_action != NULL)
+    up(SCpnt->host->eh_action);
+}
+
+/*
+ * Function:    scsi_eh_action_done()
+ *
+ * Purpose:     Completion function for error handling.
+ *
+ * Arguments:   SCpnt   - command that is timing out.
+ *             answer  - boolean that indicates whether operation succeeded.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:      This callback is only used for abort and reset operations.
+ */
+STATIC
+void scsi_eh_action_done (Scsi_Cmnd * SCpnt, int answer)
+{
+  SCpnt->request.rq_status = RQ_SCSI_DONE;
+  
+  SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+  SCpnt->eh_state = (answer ? SUCCESS : FAILED);
+
+  if (SCpnt->host->eh_action != NULL)
+    up(SCpnt->host->eh_action);
+}
+
+/*
+ * Function:   scsi_sense_valid()
+ *
+ * Purpose:    Determine whether a host has automatically obtained sense
+ *             information or not.  If we have it, then give a recommendation
+ *             as to what we should do next.
+ */
+int
+scsi_sense_valid(Scsi_Cmnd * SCpnt)
+{
+  if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) 
+    {
+      return FALSE;
+    }
+  return TRUE;
+}
+
+/*
+ * Function:   scsi_eh_retry_command()
+ *
+ * Purpose:    Retry the original command
+ *
+ * Returns:    SUCCESS - we were able to get the sense data.
+ *             FAILED  - we were not able to get the sense data.
+ * 
+ * Notes:      This function will *NOT* return until the command either
+ *             times out, or it completes.
+ */
+STATIC int
+scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
+{
+  memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
+          sizeof(SCpnt->data_cmnd));
+  SCpnt->request_buffer = SCpnt->buffer;
+  SCpnt->request_bufflen = SCpnt->bufflen;
+  SCpnt->use_sg = SCpnt->old_use_sg;
+  SCpnt->cmd_len = SCpnt->old_cmd_len;
+
+  SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+
+  scsi_send_eh_cmnd (SCpnt, SCpnt->timeout_per_command);
+
+  /*
+   * Hey, we are done.  Let's look to see what happened.
+   */
+  return SCpnt->eh_state;
+}
+
+/*
+ * Function:   scsi_request_sense()
+ *
+ * Purpose:    Request sense data from a particular target.
+ *
+ * Returns:    SUCCESS - we were able to get the sense data.
+ *             FAILED  - we were not able to get the sense data.
+ * 
+ * Notes:      Some hosts automatically obtain this information, others
+ *             require that we obtain it on our own.
+ *
+ *             This function will *NOT* return until the command either
+ *             times out, or it completes.
+ */
+STATIC int
+scsi_request_sense(Scsi_Cmnd * SCpnt)
+{
+  static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+
+  memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
+         sizeof(generic_sense));
+
+  SCpnt->cmnd[1] = SCpnt->lun << 5;
+  SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+
+  SCpnt->request_buffer = &SCpnt->sense_buffer;
+  SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+  SCpnt->use_sg = 0;
+  SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+
+  scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
+
+  /*
+   * Hey, we are done.  Let's look to see what happened.
+   */
+  return SCpnt->eh_state;
+}
+
+/*
+ * Function:   scsi_test_unit_ready()
+ *
+ * Purpose:    Run test unit ready command to see if the device is talking to us or not.
+ *
+ */
+STATIC int
+scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
+{
+  static unsigned char tur_command[6] = {TEST_UNIT_READY, 0,0,0,0,0};
+
+  memcpy ((void *) SCpnt->cmnd , (void *) tur_command,
+         sizeof(tur_command));
+
+  SCpnt->cmnd[1] = SCpnt->lun << 5;
+  SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+
+  SCpnt->request_buffer = &SCpnt->sense_buffer;
+  SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+  SCpnt->use_sg = 0;
+  SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+
+  scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
+
+  /*
+   * Hey, we are done.  Let's look to see what happened.
+   */
+  return SCpnt->eh_state;
+}
+
+STATIC
+void scsi_sleep_done (struct semaphore * sem)
+{
+    if( sem != NULL )
+    {
+        up(sem);
+    }
+}
+
+
+void scsi_sleep (int timeout)
+{
+    struct semaphore sem = MUTEX_LOCKED;
+    struct timer_list timer;
+
+    timer.data = (unsigned long) &sem;
+    timer.expires = jiffies + timeout;
+    timer.function = (void (*)(unsigned long))scsi_sleep_done;
+    
+    SCSI_LOG_ERROR_RECOVERY(5,printk("Sleeping for timer tics %d\n", timeout));
+    
+    add_timer(&timer);
+
+    down(&sem);
+    
+    del_timer(&timer);
+}
+
+/*
+ * Function:   scsi_send_eh_cmnd
+ *
+ * Purpose:    Send a command out to a device as part of error recovery.
+ *
+ * Notes:      The initialization of the structures is quite a bit different
+ *             in this case, and furthermore, there is a different completion
+ *             handler.
+ */
+STATIC void scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout)
+{
+    struct Scsi_Host * host;
+
+    host = SCpnt->host;
+
+retry:
+    /*
+     * We will use a queued command if possible, otherwise we will emulate the
+     * queuing and calling of completion function ourselves.
+     */
+    SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+    if (host->can_queue)
+    {
+        struct semaphore sem = MUTEX_LOCKED;
+
+        SCpnt->eh_state = SCSI_STATE_QUEUED;
+
+        scsi_add_timer(SCpnt, timeout, scsi_eh_times_out);
+
+       /*
+        * Set up the semaphore so we wait for the command to complete.
+        */
+       SCpnt->host->eh_action = &sem;
+       SCpnt->request.rq_status = RQ_SCSI_BUSY;
+
+       host->hostt->queuecommand (SCpnt, scsi_eh_done);
+       down(&sem);
+        SCpnt->host->eh_action = NULL;
+
+       del_timer(&SCpnt->eh_timeout);
+
+       /*
+        * See if timeout.  If so, tell the host to forget about it.
+        * In other words, we don't want a callback any more.
+        */
+       if( SCpnt->eh_state == SCSI_STATE_TIMEOUT )
+         {
+           SCpnt->eh_state = FAILED;
+         }
+
+        SCSI_LOG_ERROR_RECOVERY(5,printk("send_eh_cmnd: %p eh_state:%x\n", 
+                                         SCpnt, SCpnt->eh_state));
+    }
+    else
+      {
+       int temp;
+
+       /*
+        * We damn well had better never use this code.  There is no timeout
+        * protection here, since we would end up waiting in the actual low
+        * level driver, we don't know how to wake it up.
+        */
+       temp = host->hostt->command (SCpnt);
+       SCpnt->result = temp;
+       if( scsi_eh_completed_normally(SCpnt) )
+         {
+           SCpnt->eh_state = SUCCESS;
+         }
+       else
+         {
+           SCpnt->eh_state = FAILED;
+         }
+      }
+
+    /*
+     * Now examine the actual status codes to see whether the command actually
+     * did complete normally.
+     */
+    if( SCpnt->eh_state == SUCCESS )
+      {
+       switch( scsi_eh_completed_normally(SCpnt) )
+         {
+         case SUCCESS:
+           SCpnt->eh_state = SUCCESS;
+           break;
+         case NEEDS_RETRY:
+           goto retry;
+         case FAILED:
+         default:
+           SCpnt->eh_state = FAILED;
+           break;
+         }
+      }
+    else
+      {
+       SCpnt->eh_state = FAILED;
+      }
+}
+
+/*
+ * Function:   scsi_unit_is_ready()
+ *
+ * Purpose:    Called after TEST_UNIT_READY is run, to test to see if
+ *             the unit responded in a way that indicates it is ready.
+ */
+STATIC int
+scsi_unit_is_ready(Scsi_Cmnd * SCpnt)
+{
+  if (SCpnt->result) 
+    {
+      if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
+          (status_byte (SCpnt->result) & CHECK_CONDITION)) &&
+         ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) 
+       {
+         if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+             ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
+             ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST))
+           {
+             return 0;
+           }
+       }
+    }
+  
+  return 1;
+}
+
+/*
+ * Function:    scsi_eh_finish_command
+ *
+ * Purpose:     Handle a command that we are finished with WRT error handling.
+ *
+ * Arguments:   SClist - pointer to list into which we are putting completed commands.
+ *              SCpnt  - command that is completing
+ *
+ * Notes:       We don't want to use the normal command completion while we are
+ *              are still handling errors - it may cause other commands to be queued,
+ *              and that would disturb what we are doing.  Thus we really want to keep
+ *              a list of pending commands for final completion, and once we
+ *              are ready to leave error handling we handle completion for real.
+ */
+STATIC void
+scsi_eh_finish_command(Scsi_Cmnd **SClist, Scsi_Cmnd * SCpnt)
+{
+    SCpnt->state = SCSI_STATE_BHQUEUE;
+    SCpnt->bh_next = *SClist;
+    /*
+     * Set this back so that the upper level can correctly free up
+     * things.
+     */
+    SCpnt->use_sg = SCpnt->old_use_sg;
+    *SClist = SCpnt;
+}
+
+/*
+ * Function:   scsi_try_to_abort_command
+ *
+ * Purpose:    Ask host adapter to abort a running command.
+ *
+ * Returns:    FAILED          Operation failed or not supported.
+ *             SUCCESS         Succeeded.
+ *
+ * Notes:      This function will not return until the user's completion
+ *             function has been called.  There is no timeout on this
+ *              operation.  If the author of the low-level driver wishes
+ *              this operation to be timed, they can provide this facility
+ *              themselves.  Helper functions in scsi_error.c can be supplied
+ *              to make this easier to do.
+ *
+ * Notes:      It may be possible to combine this with all of the reset
+ *             handling to eliminate a lot of code duplication.  I don't
+ *             know what makes more sense at the moment - this is just a
+ *             prototype.
+ */
+STATIC int
+scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout)
+{
+  SCpnt->eh_state = FAILED; /* Until we come up with something better */
+
+  if( SCpnt->host->hostt->eh_abort_handler == NULL )
+    {
+      return FAILED;
+    }
+  
+  SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+  return SCpnt->host->hostt->eh_abort_handler(SCpnt);
+}
+
+/*
+ * Function:   scsi_try_bus_device_reset
+ *
+ * Purpose:    Ask host adapter to perform a bus device reset for a given
+ *             device.
+ *
+ * Returns:    FAILED          Operation failed or not supported.
+ *             SUCCESS         Succeeded.
+ *
+ * Notes:      There is no timeout for this operation.  If this operation is
+ *              unreliable for a given host, then the host itself needs to put a
+ *              timer on it, and set the host back to a consistent state prior
+ *              to returning.
+ */
+STATIC int
+scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
+{
+  SCpnt->eh_state = FAILED; /* Until we come up with something better */
+
+  if( SCpnt->host->hostt->eh_device_reset_handler == NULL )
+    {
+      return FAILED;
+    }
+  
+  SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+    
+  return SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
+}
+
+/*
+ * Function:   scsi_try_bus_reset
+ *
+ * Purpose:    Ask host adapter to perform a bus reset for a host.
+ *
+ * Returns:    FAILED          Operation failed or not supported.
+ *             SUCCESS         Succeeded.
+ *
+ * Notes:      
+ */
+STATIC int
+scsi_try_bus_reset(Scsi_Cmnd * SCpnt)
+{
+  int             rtn;
+
+  SCpnt->eh_state = FAILED; /* Until we come up with something better */
+  SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+  if( SCpnt->host->hostt->eh_bus_reset_handler == NULL )
+    {
+      return FAILED;
+    }
+
+  rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
+
+  /*
+   * If we had a successful bus reset, mark the command blocks to expect
+   * a condition code of unit attention.
+   */
+  scsi_sleep(BUS_RESET_SETTLE_TIME);
+  if( SCpnt->eh_state == SUCCESS )
+    {
+      Scsi_Device * SDloop;
+      for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next)
+       {
+            if( SCpnt->channel == SDloop->channel )
+            {
+                SDloop->was_reset = 1;
+                SDloop->expecting_cc_ua = 1;
+            }
+       }
+    }
+
+  return SCpnt->eh_state;
+}
+
+/*
+ * Function:   scsi_try_host_reset
+ *
+ * Purpose:    Ask host adapter to reset itself, and the bus.
+ *
+ * Returns:    FAILED          Operation failed or not supported.
+ *             SUCCESS         Succeeded.
+ *
+ * Notes:
+ */
+STATIC int
+scsi_try_host_reset(Scsi_Cmnd * SCpnt)
+{
+    int                   rtn;
+
+    SCpnt->eh_state = FAILED; /* Until we come up with something better */
+    SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+    
+    if( SCpnt->host->hostt->eh_host_reset_handler == NULL )
+    {
+        return FAILED;
+    }
+    
+    rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
+
+    /*
+     * If we had a successful host reset, mark the command blocks to expect
+     * a condition code of unit attention.
+     */
+    scsi_sleep(HOST_RESET_SETTLE_TIME);
+    if( SCpnt->eh_state == SUCCESS )
+    {
+        Scsi_Device * SDloop;
+        for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next)
+       {
+            SDloop->was_reset = 1;
+            SDloop->expecting_cc_ua = 1;
+       }
+    }
+    
+    return SCpnt->eh_state;
+}
+
+/*
+ * Function:   scsi_decide_disposition
+ *
+ * Purpose:    Examine a command block that has come back from the low-level
+ *             and figure out what to do next.
+ *
+ * Returns:    SUCCESS         - pass on to upper level.
+ *             FAILED          - pass on to error handler thread.
+ *             RETRY           - command should be retried.
+ *             SOFTERR         - command succeeded, but we need to log
+ *                               a soft error.
+ *
+ * Notes:      This is *ONLY* called when we are examining the status
+ *             after sending out the actual data command.  Any commands
+ *             that are queued for error recovery (i.e. TEST_UNIT_READY)
+ *             do *NOT* come through here.
+ *
+ *              NOTE - When this routine returns FAILED, it means the error
+ *              handler thread is woken.  In cases where the error code
+ *              indicates an error that doesn't require the error handler
+ *              thread (i.e. we don't need to abort/reset), then this function
+ *              should return SUCCESS.
+ */
+int scsi_decide_disposition (Scsi_Cmnd * SCpnt)
+{
+  int  rtn;
+
+  /*
+   * If the device is offline, then we clearly just pass the result back
+   * up to the top level.
+   */
+  if( SCpnt->device->online == FALSE )
+  {
+      SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: device offline - report as SUCCESS\n"));
+      return SUCCESS;
+  }
+
+  /*
+   * First check the host byte, to see if there is anything in there
+   * that would indicate what we need to do.
+   */
+
+  switch(host_byte(SCpnt->result))
+    {
+    case DID_PASSTHROUGH:
+        /*
+         * No matter what, pass this through to the upper layer.
+         * Nuke this special code so that it looks like we are saying
+         * DID_OK.
+         */
+        SCpnt->result &= 0xff00ffff;
+        return SUCCESS;
+    case DID_OK:
+      /*
+       * Looks good.  Drop through, and check the next byte.
+       */
+      break;
+    case DID_NO_CONNECT:
+    case DID_BAD_TARGET:
+    case DID_ABORT:
+      /*
+       * Note - this means that we just report the status back to the
+       * top level driver, not that we actually think that it indicates
+       * sucess.
+       */
+      return SUCCESS;
+    case DID_PARITY:
+    case DID_BUS_BUSY:
+    case DID_ERROR:
+      goto maybe_retry;
+    case DID_TIME_OUT:
+      /*
+         * When we scan the bus, we get timeout messages for
+         * these commands if there is no device available.
+         * Other hosts report DID_NO_CONNECT for the same thing.
+         */
+        if( (SCpnt->cmnd[0] == TEST_UNIT_READY ||
+             SCpnt->cmnd[0] == INQUIRY) )
+        {
+            return SUCCESS;
+        }
+        else
+        {
+            return FAILED;
+        }
+    case DID_RESET:
+      /*
+       * In the normal case where we haven't initiated a reset, this is
+       * a failure.
+       */
+      if( SCpnt->flags & IS_RESETTING )
+       {
+         SCpnt->flags &= ~IS_RESETTING;
+         goto maybe_retry;
+       }
+
+      /*
+       * Examine the sense data to figure out how to proceed from here.
+       * If there is no sense data, we will be forced into the error
+       * handler thread, where we get to examine the thing in a lot more
+       * detail.
+       */
+      return scsi_check_sense (SCpnt);
+    default:
+      return FAILED;
+    }
+
+  /*
+   * Next, check the message byte.
+   */
+  if( msg_byte(SCpnt->result) != COMMAND_COMPLETE )
+    {
+      return FAILED;
+    }
+
+  /*
+   * Now, check the status byte to see if this indicates anything special.
+   */
+  switch (status_byte(SCpnt->result))
+    {
+    case QUEUE_FULL:
+      /*
+       * The case of trying to send too many commands to a tagged queueing
+       * device.
+       */
+      return ADD_TO_MLQUEUE;
+    case GOOD:
+    case COMMAND_TERMINATED:
+      return SUCCESS;
+    case CHECK_CONDITION:
+      rtn = scsi_check_sense(SCpnt);
+      if( rtn == NEEDS_RETRY )
+       {
+         goto maybe_retry;
+       }
+      return rtn;
+    case CONDITION_GOOD:
+    case INTERMEDIATE_GOOD:
+    case INTERMEDIATE_C_GOOD:
+      /*
+       * Who knows?  FIXME(eric)
+       */
+      return SUCCESS;
+    case BUSY:
+    case RESERVATION_CONFLICT:
+      goto maybe_retry;
+    default:
+      return FAILED;
+    }
+  return FAILED;
+
+maybe_retry:
+
+  if ((++SCpnt->retries) < SCpnt->allowed)
+    {
+      return NEEDS_RETRY;
+    }
+  else
+    {
+      return FAILED;
+    }
+}
+
+/*
+ * Function:   scsi_eh_completed_normally
+ *
+ * Purpose:    Examine a command block that has come back from the low-level
+ *             and figure out what to do next.
+ *
+ * Returns:    SUCCESS         - pass on to upper level.
+ *             FAILED          - pass on to error handler thread.
+ *             RETRY           - command should be retried.
+ *             SOFTERR         - command succeeded, but we need to log
+ *                               a soft error.
+ *
+ * Notes:      This is *ONLY* called when we are examining the status
+ *             of commands queued during error recovery.  The main
+ *             difference here is that we don't allow for the possibility
+ *             of retries here, and we are a lot more restrictive about what
+ *              we consider acceptable.
+ */
+STATIC int scsi_eh_completed_normally (Scsi_Cmnd * SCpnt)
+{
+  int  rtn;
+  /*
+   * First check the host byte, to see if there is anything in there
+   * that would indicate what we need to do.
+   */
+  if( host_byte(SCpnt->result) == DID_RESET )
+    {
+     if (SCpnt->flags & IS_RESETTING )
+       {
+        /*
+         * OK, this is normal.  We don't know whether in fact the
+         * command in question really needs to be rerun or not - 
+         * if this was the original data command then the answer is yes,
+         * otherwise we just flag it as success.
+         */
+        SCpnt->flags &= ~IS_RESETTING;
+        return NEEDS_RETRY;
+       }
+
+     /*
+      * Rats.  We are already in the error handler, so we now get to try
+      * and figure out what to do next.  If the sense is valid, we have
+      * a pretty good idea of what to do.  If not, we mark it as failed.
+      */
+     return scsi_check_sense (SCpnt);
+    }
+
+  if(host_byte(SCpnt->result) != DID_OK )
+  {
+      return FAILED;
+  }
+
+  /*
+   * Next, check the message byte.
+   */
+  if( msg_byte(SCpnt->result) != COMMAND_COMPLETE )
+    {
+      return FAILED;
+    }
+
+  /*
+   * Now, check the status byte to see if this indicates anything special.
+   */
+  switch (status_byte(SCpnt->result))
+    {
+    case GOOD:
+    case COMMAND_TERMINATED:
+      return SUCCESS;
+    case CHECK_CONDITION:
+      rtn = scsi_check_sense(SCpnt);
+      if( rtn == NEEDS_RETRY )
+       {
+         return FAILED;
+       }
+      return rtn;
+    case CONDITION_GOOD:
+    case INTERMEDIATE_GOOD:
+    case INTERMEDIATE_C_GOOD:
+      /*
+       * Who knows?  FIXME(eric)
+       */
+      return SUCCESS;
+    case BUSY:
+    case QUEUE_FULL:
+    case RESERVATION_CONFLICT:
+    default:
+      return FAILED;
+    }
+  return FAILED;
+}
+
+/*
+ * Function:   scsi_check_sense
+ *
+ * Purpose:    Examine sense information - give suggestion as to what
+ *             we should do with it.
+ */
+STATIC  int scsi_check_sense (Scsi_Cmnd * SCpnt)
+{
+    if ( !scsi_sense_valid(SCpnt) ) 
+      {
+       return FAILED;
+      }
+
+    if (SCpnt->sense_buffer[2] & 0xe0)
+       return FAILED;
+
+    switch (SCpnt->sense_buffer[2] & 0xf)
+    {
+    case NO_SENSE:
+       return SUCCESS;
+    case RECOVERED_ERROR:
+       return SOFT_ERROR;
+
+    case ABORTED_COMMAND:
+       return NEEDS_RETRY;
+    case NOT_READY:
+    case UNIT_ATTENTION:
+        /*
+         * If we are expecting a CC/UA because of a bus reset that we
+         * performed, treat this just as a retry.  Otherwise this is
+         * information that we should pass up to the upper-level driver
+         * so that we can deal with it there.
+         */
+        if( SCpnt->device->expecting_cc_ua )
+        {
+            SCpnt->device->expecting_cc_ua = 0;
+            return NEEDS_RETRY;
+        }
+       return SUCCESS;
+
+    /* these three are not supported */
+    case COPY_ABORTED:
+    case VOLUME_OVERFLOW:
+    case MISCOMPARE:
+
+    case MEDIUM_ERROR:
+       return FAILED;
+
+    case BLANK_CHECK:
+    case DATA_PROTECT:
+    case HARDWARE_ERROR:
+    case ILLEGAL_REQUEST:
+    default:
+       return FAILED;
+    }
+}
+
+
+/*
+ * Function:   scsi_restart_operations
+ *
+ * Purpose:    Restart IO operations to the specified host.
+ *
+ * Arguments:  host  - host that we are restarting
+ *
+ * Returns:    Nothing
+ *
+ * Notes:      When we entered the error handler, we blocked all further
+ *             I/O to this device.  We need to 'reverse' this process.
+ */
+STATIC void
+scsi_restart_operations(struct Scsi_Host * host)
+{
+  Scsi_Device * SDpnt;
+
+  /*
+   * Next free up anything directly waiting upon the host.  This will be
+   * requests for character device operations, and also for ioctls to queued
+   * block devices.
+   */
+  SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: Waking up host to restart\n"));
+
+   wake_up(&host->host_wait);
+
+   /*
+    * Finally, block devices need an extra kick in the pants.  This is because
+    * the request queueing mechanism may have queued lots of pending requests
+    * and there won't be a process waiting in a place where we can simply wake
+    * it up.  Thus we simply go through and call the request function to goose
+    * the various top level drivers and get things moving again.
+    */
+   for( SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next )
+     {
+       SCSI_LOG_ERROR_RECOVERY(5,printk("Calling request function to restart things...\n"));
+
+       if( SDpnt->scsi_request_fn != NULL )
+        (*SDpnt->scsi_request_fn)();
+     }
+}
+
+/*
+ * Function:   scsi_unjam_host
+ *
+ * Purpose:    Attempt to fix a host which has a command that failed for
+ *             some reason.
+ *
+ * Arguments:  host    - host that needs unjamming.
+ * 
+ * Returns:    Nothing
+ *
+ * Notes:      When we come in here, we *know* that all commands on the
+ *             bus have either completed, failed or timed out.  We also
+ *             know that no further commands are being sent to the host,
+ *             so things are relatively quiet and we have freedom to
+ *             fiddle with things as we wish.
+ *
+ * Additional note:  This is only the *default* implementation.  It is possible
+ *             for individual drivers to supply their own version of this
+ *             function, and if the maintainer wishes to do this, it is
+ *             strongly suggested that this function be taken as a template
+ *             and modified.  This function was designed to correctly handle
+ *             problems for about 95% of the different cases out there, and
+ *             it should always provide at least a reasonable amount of error
+ *             recovery.
+ *
+ * Note3:       Any command marked 'FAILED' or 'TIMEOUT' must eventually
+ *              have scsi_finish_command() called for it.  We do all of
+ *              the retry stuff here, so when we restart the host after we
+ *              return it should have an empty queue.
+ */
+STATIC int
+scsi_unjam_host(struct Scsi_Host * host)
+{
+  int           devices_failed;
+  int           numfailed;
+  int           ourrtn;
+  int          rtn = FALSE;
+  int          result;
+  Scsi_Cmnd   * SCloop;
+  Scsi_Cmnd   * SCpnt;
+  Scsi_Device * SDpnt;
+  Scsi_Device * SDloop;
+  Scsi_Cmnd   * SCdone;
+  int           timed_out;
+
+  SCdone = NULL;
+
+  /*
+   * First, protect against any sort of race condition.  If any of the outstanding
+   * commands are in states that indicate that we are not yet blocked (i.e. we are
+   * not in a quiet state) then we got woken up in error.  If we ever end up here,
+   * we need to re-examine some of the assumptions.
+   */
+  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+  {
+      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+      {
+          if( SCpnt->state == SCSI_STATE_FAILED 
+              || SCpnt->state == SCSI_STATE_TIMEOUT 
+              || SCpnt->state == SCSI_STATE_UNUSED)
+          {
+              continue;
+          }
+
+          /*
+           * Rats.  Something is still floating around out there.  This could
+           * be the result of the fact that the upper level drivers are still frobbing
+           * commands that might have succeeded.  There are two outcomes.  One is that
+           * the command block will eventually be freed, and the other one is that
+           * the command will be queued and will be finished along the way.
+           */
+          SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));
+          panic("SCSI Error handler woken too early\n");
+      }
+  }
+
+  /*
+   * Next, see if we need to request sense information.  if so,
+   * then get it now, so we have a better idea of what to do.
+   * FIXME(eric) this has the unfortunate side effect that if a host
+   * adapter does not automatically request sense information, that we end
+   * up shutting it down before we request it.  All hosts should be doing this
+   * anyways, so for now all I have to say is tough noogies if you end up in here.
+   * On second thought, this is probably a good idea.  We *really* want to give
+   * authors an incentive to automatically request this.
+   */
+  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we need to request sense\n"));
+
+  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+  {
+      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+      {
+          if( SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt) )
+          {
+              continue;
+          }
+
+          SCSI_LOG_ERROR_RECOVERY(2,printk("scsi_unjam_host: Requesting sense for %d\n",
+                                           SCpnt->target));
+          rtn = scsi_request_sense(SCpnt);
+          if( rtn != SUCCESS )
+          {
+              continue;
+          }
+
+          SCSI_LOG_ERROR_RECOVERY(3,printk("Sense requested for %p - result %x\n",
+                                           SCpnt, SCpnt->result));
+          SCSI_LOG_ERROR_RECOVERY(3,print_sense("bh",SCpnt));
+                  
+          result = scsi_decide_disposition(SCpnt);
+
+          /*
+           * If the result was normal, then just pass it along to the
+           * upper level.
+           */
+          if( result == SUCCESS )
+          {
+              SCpnt->host->host_failed--;
+              scsi_eh_finish_command(&SCdone, SCpnt);
+          }
+
+          if( result != NEEDS_RETRY )
+          {
+              continue;
+          }
+
+          /* 
+           * We only come in here if we want to retry a
+           * command.  The test to see whether the command
+           * should be retried should be keeping track of the
+           * number of tries, so we don't end up looping, of
+           * course.  
+           */
+          SCpnt->state = NEEDS_RETRY;
+          rtn = scsi_eh_retry_command(SCpnt);
+          if( rtn != SUCCESS )
+          {
+              continue;
+          }
+
+          /*
+           * We eventually hand this one back to the top level.
+           */
+          SCpnt->host->host_failed--;
+          scsi_eh_finish_command(&SCdone, SCpnt);
+      }
+  }
+
+  /*
+   * Go through the list of commands and figure out where we stand and how bad things
+   * really are.
+   */
+  numfailed = 0;
+  timed_out = 0;
+  devices_failed = 0;
+  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+  {
+      unsigned int device_error = 0;
+
+      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+      {
+          if( SCpnt->state == SCSI_STATE_FAILED )
+          {
+              SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d failed\n", 
+                                               SCpnt->target));
+              numfailed++;
+              device_error++;
+          }
+          if( SCpnt->state == SCSI_STATE_TIMEOUT )
+          {
+              SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d timedout\n", 
+                                               SCpnt->target));
+              timed_out++;
+              device_error++;
+          }
+      }
+      if( device_error > 0 )
+      {
+          devices_failed++;
+      }
+  }
+
+  SCSI_LOG_ERROR_RECOVERY(2,printk("Total of %d+%d commands on %d devices require eh work\n", 
+                                   numfailed, timed_out, devices_failed));
+
+  if( host->host_failed == 0 )
+  {
+      ourrtn = TRUE;
+      goto leave;
+  }
+
+
+  /*
+   * Next, try and see whether or not it makes sense to try and abort
+   * the running command.  This only works out to be the case if we have
+   * one command that has timed out.  If the command simply failed, it
+   * makes no sense to try and abort the command, since as far as the
+   * host adapter is concerned, it isn't running.
+   */
+
+  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try abort\n"));
+
+  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+  {
+      for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+      {
+          if( SCloop->state != SCSI_STATE_TIMEOUT )
+          {
+              continue;
+          }
+
+         rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT);
+
+         if( rtn == SUCCESS )
+          {
+             rtn = scsi_test_unit_ready(SCloop);
+              
+             if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+              {
+                 rtn = scsi_eh_retry_command(SCloop);
+                  
+                 if( rtn == SUCCESS )
+                  {
+                      SCloop->host->host_failed--;
+                     scsi_eh_finish_command(&SCdone,SCloop);
+                  }
+              }
+          }
+      }
+  }
+  
+  /*
+   * If we have corrected all of the problems, then we are done.
+   */
+  if( host->host_failed == 0 )
+  {
+      ourrtn = TRUE;
+      goto leave;
+  }
+
+  /*
+   * Either the abort wasn't appropriate, or it didn't succeed.
+   * Now try a bus device reset.  Still, look to see whether we have
+   * multiple devices that are jammed or not - if we have multiple devices,
+   * it makes no sense to try BUS_DEVICE_RESET - we really would need
+   * to try a BUS_RESET instead.
+   *
+   * Does this make sense - should we try BDR on each device individually?
+   * Yes, definitely.
+   */
+  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));
+
+  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+  {
+      for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+      {
+          if( SCloop->state == SCSI_STATE_FAILED 
+              || SCloop->state == SCSI_STATE_TIMEOUT )
+          {
+              break;
+          }
+      }
+
+      if( SCloop == NULL )
+      {
+          continue;
+      }
+
+      /*
+       * OK, we have a device that is having problems.  Try and send
+       * a bus device reset to it.
+       *
+       * FIXME(eric) - make sure we handle the case where multiple
+       * commands to the same device have failed. They all must
+       * get properly restarted.
+       */
+      rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT);
+      
+      if( rtn == SUCCESS )
+      {
+         rtn = scsi_test_unit_ready(SCloop);
+         
+         if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+          {
+             rtn = scsi_eh_retry_command(SCloop);
+             
+             if( rtn == SUCCESS )
+              {
+                  SCloop->host->host_failed--;
+                 scsi_eh_finish_command(&SCdone,SCloop);
+              }
+          }
+      }
+      
+  }
+  
+  if( host->host_failed == 0 )
+  {
+      ourrtn = TRUE;
+      goto leave;
+  }
+
+  /*
+   * If we ended up here, we have serious problems.  The only thing left
+   * to try is a full bus reset.  If someone has grabbed the bus and isn't
+   * letting go, then perhaps this will help.
+   */
+  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard bus reset\n"));
+
+  /* 
+   * We really want to loop over the various channels, and do this on
+   * a channel by channel basis.  We should also check to see if any
+   * of the failed commands are on soft_reset devices, and if so, skip
+   * the reset.  
+   */
+  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+  {
+next_device:
+      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+      {
+          if( SCpnt->state != SCSI_STATE_FAILED 
+              && SCpnt->state != SCSI_STATE_TIMEOUT )
+          {
+              continue;
+          }
+          /*
+           * We have a failed command.  Make sure there are no other failed
+           * commands on the same channel that are timed out and implement a
+           * soft reset.
+           */
+          for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+          {
+              for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+              {
+                  if( SCloop->channel != SCpnt->channel )
+                  {
+                      continue;
+                  }
+                  
+                  if( SCloop->state != SCSI_STATE_FAILED 
+                      && SCloop->state != SCSI_STATE_TIMEOUT )
+                  {
+                      continue;
+                  }
+                  
+                  if( SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT )
+                  {
+                      /* 
+                       * If this device uses the soft reset option, and this
+                       * is one of the devices acting up, then our only
+                       * option is to wait a bit, since the command is
+                       * supposedly still running.  
+                       *
+                       * FIXME(eric) - right now we will just end up falling
+                       * through to the 'take device offline' case.
+                       *
+                       * FIXME(eric) - It is possible that the command completed
+                       * *after* the error recovery procedure started, and if this
+                       * is the case, we are worrying about nothing here.
+                       */
+                      goto next_device;
+                  }
+              }
+          }
+
+          /*
+           * We now know that we are able to perform a reset for the
+           * bus that SCpnt points to.  There are no soft-reset devices
+           * with outstanding timed out commands.
+           */
+          rtn = scsi_try_bus_reset(SCpnt);
+          if( rtn == SUCCESS )
+          {
+              for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+              {
+                  for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+                  {
+                      if( SCloop->channel != SCpnt->channel )
+                      {
+                          continue;
+                      }
+                      
+                      if( SCloop->state != SCSI_STATE_FAILED 
+                          && SCloop->state != SCSI_STATE_TIMEOUT )
+                      {
+                          continue;
+                      }
+                      
+                      rtn = scsi_test_unit_ready(SCloop);
+                      
+                      if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+                      {
+                          rtn = scsi_eh_retry_command(SCloop);
+                          
+                          if( rtn == SUCCESS )
+                          {
+                              SCpnt->host->host_failed--;
+                              scsi_eh_finish_command(&SCdone,SCloop);
+                          }
+                      }
+                      
+                      /*
+                       * If the bus reset worked, but we are still unable to
+                       * talk to the device, take it offline.
+                       * FIXME(eric) - is this really the correct thing to do?
+                       */
+                      if( rtn != SUCCESS )
+                      {
+                          SCloop->device->online = FALSE;
+                          SCloop->host->host_failed--;
+                          scsi_eh_finish_command(&SCdone,SCloop);
+                      }
+                  }
+              }
+          }
+      }
+  }
+
+  if( host->host_failed == 0 )
+  {
+      ourrtn = TRUE;
+      goto leave;
+  }
+  /*
+   * If we ended up here, we have serious problems.  The only thing left
+   * to try is a full host reset - perhaps the firmware on the device
+   * crashed, or something like that.
+   *
+   * It is assumed that a succesful host reset will cause *all* information
+   * about the command to be flushed from both the host adapter *and* the
+   * device.
+   *
+   * FIXME(eric) - it isn't clear that devices that implement the soft reset
+   * option can ever be cleared except via cycling the power.  The problem is
+   * that sending the host reset command will cause the host to forget
+   * about the pending command, but the device won't forget.  For now, we
+   * skip the host reset option if any of the failed devices are configured
+   * to use the soft reset option.
+   */
+  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+  {
+next_device2:
+      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+      {
+          if( SCpnt->state != SCSI_STATE_FAILED 
+              && SCpnt->state != SCSI_STATE_TIMEOUT )
+          {
+              continue;
+          }
+          if( SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT )
+          {
+              /* 
+               * If this device uses the soft reset option, and this
+               * is one of the devices acting up, then our only
+               * option is to wait a bit, since the command is
+               * supposedly still running.  
+               *
+               * FIXME(eric) - right now we will just end up falling
+               * through to the 'take device offline' case.
+               */
+              SCSI_LOG_ERROR_RECOVERY(3,
+                        printk("scsi_unjam_host: Unable to try hard host reset\n"));
+              goto next_device2;
+          }
+
+          SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard host reset\n"));
+
+          /*
+           * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
+           */
+          rtn = scsi_try_host_reset(SCpnt);
+          if( rtn == SUCCESS )
+          {
+              /*
+               * FIXME(eric) we assume that all commands are flushed from the
+               * controller.  We should get a DID_RESET for all of the commands
+               * that were pending.  We should ignore these so that we can
+               * guarantee that we are in a consistent state.
+               *
+               * I believe this to be the case right now, but this needs to be
+               * tested.
+               */
+            for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+              {
+                  for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+                  {
+                      if( SCloop->state != SCSI_STATE_FAILED 
+                          && SCloop->state != SCSI_STATE_TIMEOUT )
+                      {
+                          continue;
+                      }
+                      
+                      rtn = scsi_test_unit_ready(SCloop);
+                      
+                      if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+                      {
+                          rtn = scsi_eh_retry_command(SCloop);
+                          
+                          if( rtn == SUCCESS )
+                          {
+                              SCpnt->host->host_failed--;
+                              scsi_eh_finish_command(&SCdone,SCloop);
+                          }
+                      }
+                      if( rtn != SUCCESS )
+                      {
+                          SCloop->device->online = FALSE;
+                          SCloop->host->host_failed--;
+                          scsi_eh_finish_command(&SCdone,SCloop);
+                      }
+                  }
+              }
+          }
+      }
+  }
+
+
+  /*
+   * If we solved all of the problems, then let's rev up the engines again.
+   */
+  if( host->host_failed == 0 )
+  {
+      ourrtn = TRUE;
+      goto leave;
+  }
+
+  /*
+   * If the HOST RESET failed, then for now we assume that the entire host
+   * adapter is too hosed to be of any use.  For our purposes, however, it is
+   * easier to simply take the devices offline that correspond to commands
+   * that failed.
+   */
+  SCSI_LOG_ERROR_RECOVERY(1,printk("scsi_unjam_host: Take device offline\n"));
+
+  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+  {
+      for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+      {
+          if( SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT )
+          {
+              SCloop->device->online = FALSE;
+              
+              /*
+               * This should pass the failure up to the top level driver, and
+               * it will have to try and do something intelligent with it.
+               */
+              SCloop->host->host_failed--;
+              
+              if( SCloop->state == SCSI_STATE_TIMEOUT )
+              {
+                  SCloop->result |= (DRIVER_TIMEOUT << 24);
+              }
+
+              SCSI_LOG_ERROR_RECOVERY(3,printk("Finishing command for device %d %x\n",
+                     SCloop->device->id, SCloop->result));
+              
+              scsi_eh_finish_command(&SCdone,SCloop);
+          }
+      }
+  }
+
+  if( host->host_failed != 0 )
+  {
+      panic("scsi_unjam_host: Miscount of number of failed commands.\n");
+  }
+
+  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Returning\n"));
+
+  ourrtn = FALSE;
+
+leave:
+
+  /*
+   * We should have a list of commands that we 'finished' during the course of
+   * error recovery.  This should be the same as the list of commands that timed out
+   * or failed.  We are currently holding these things in a linked list - we didn't
+   * put them in the bottom half queue because we wanted to keep things quiet while
+   * we were working on recovery, and passing them up to the top level could easily
+   * cause the top level to try and queue something else again.
+   *
+   * Start by marking that the host is no longer in error recovery.
+   */
+  host->in_recovery = 0;
+
+  /*
+   * Take the list of commands, and stick them in the bottom half queue.
+   * The current implementation of scsi_done will do this for us - if need
+   * be we can create a special version of this function to do the
+   * same job for us.
+   */
+  for(SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone)
+  {
+      SCdone = SCpnt->bh_next;
+      SCpnt->bh_next = NULL;
+      scsi_done(SCpnt);
+  }
+
+  return (ourrtn);
+}
+
+
+/*
+ * Function:   scsi_error_handler
+ *
+ * Purpose:    Handle errors/timeouts of scsi commands, try and clean up
+ *             and unjam the bus, and restart things.
+ *
+ * Arguments:  host    - host for which we are running.
+ *
+ * Returns:    Never returns.
+ *
+ * Notes:      This is always run in the context of a kernel thread.  The
+ *             idea is that we start this thing up when the kernel starts
+ *             up (one per host that we detect), and it immediately goes to
+ *             sleep and waits for some event (i.e. failure).  When this
+ *             takes place, we have the job of trying to unjam the bus
+ *             and restarting things.
+ *
+ */
+void
+scsi_error_handler(void * data)
+{
+       struct Scsi_Host     * host = (struct Scsi_Host *) data;
+       int                    rtn;
+       struct semaphore sem = MUTEX_LOCKED;
+
+       lock_kernel();
+
+       /*
+        * If we were started as result of loading a module, close all of the
+        * user space pages.  We don't need them, and if we didn't close them
+        * they would be locked into memory.
+        */
+       exit_mm(current);
+
+
+       current->session = 1;
+       current->pgrp = 1;
+        /*
+         * FIXME(eric) this is still a child process of the one that did the insmod.
+         * This needs to be attached to task[0] instead.
+         */
+
+       siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+        current->fs->umask = 0;
+
+       /*
+        * Set the name of this process.
+        */
+       sprintf(current->comm, "scsi_eh_%d", host->host_no);
+
+       host->eh_wait = &sem;
+       host->ehandler = current;
+        
+       unlock_kernel();
+
+        /*
+         * Wake up the thread that created us.
+         */
+        SCSI_LOG_ERROR_RECOVERY(3,printk("Wake up parent %d\n", host->eh_notify->count.counter));
+
+        up(host->eh_notify);
+
+       while(1)
+         {
+           /*
+            * If we get a signal, it means we are supposed to go
+            * away and die.  This typically happens if the user is
+            * trying to unload a module.
+            */
+            SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler sleeping\n"));
+           down_interruptible (&sem);
+
+           if (signal_pending(current) )
+             break;
+
+            SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler waking up\n"));
+
+            host->eh_active = 1;
+
+           /*
+            * We have a host that is failing for some reason.  Figure out
+            * what we need to do to get it up and online again (if we can).
+            * If we fail, we end up taking the thing offline.
+            */
+           if( host->hostt->eh_strategy_handler != NULL )
+             {
+               rtn = host->hostt->eh_strategy_handler(host);
+             }
+           else
+             {
+               rtn = scsi_unjam_host(host);
+             }
+
+            host->eh_active = 0;
+
+           /*
+            * Note - if the above fails completely, the action is to take
+            * individual devices offline and flush the queue of any
+            * outstanding requests that may have been pending.  When we
+            * restart, we restart any I/O to any other devices on the bus
+            * which are still online.
+            */
+           scsi_restart_operations(host);
+         }
+
+        SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler exiting\n"));
+
+       /*
+        * Make sure that nobody tries to wake us up again.
+        */
+       host->eh_wait = NULL;
+
+       /*
+        * Knock this down too.  From this point on, the host is flying
+        * without a pilot.  If this is because the module is being unloaded,
+        * that's fine.  If the user sent a signal to this thing, we are
+        * potentially in real danger.
+        */
+       host->in_recovery = 0;
+        host->eh_active = 0;
+       host->ehandler = NULL;
+
+       /*
+        * If anyone is waiting for us to exit (i.e. someone trying to unload
+        * a driver), then wake up that process to let them know we are on
+        * the way out the door.  This may be overkill - I *think* that we
+        * could probably just unload the driver and send the signal, and when
+        * the error handling thread wakes up that it would just exit without
+        * needing to touch any memory associated with the driver itself.
+        */
+       if( host->eh_notify != NULL )
+         up(host->eh_notify);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index 93711a0d21262307186bbedda99d0fd947872f9b..eafaf6a00f744d0716f161533d9493c0fdf72b1e 100644 (file)
@@ -1,8 +1,3 @@
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
 #define __NO_VERSION__
 #include <linux/module.h>
 
@@ -103,8 +98,10 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
 {
     int result;
     Scsi_Cmnd * SCpnt;
-    
-    SCpnt = allocate_device(NULL, dev, 1);
+    Scsi_Device * SDpnt;
+
+    SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
+    SCpnt = scsi_allocate_device(NULL, dev, 1);
     {
        struct semaphore sem = MUTEX_LOCKED;
        SCpnt->request.sem = &sem;
@@ -112,8 +109,11 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
                    scsi_ioctl_done,  MAX_TIMEOUT,
                    MAX_RETRIES);
        down(&sem);
+        SCpnt->request.sem = NULL;
     }
     
+    SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));
+
     if(driver_byte(SCpnt->result) != 0)
        switch(SCpnt->sense_buffer[2] & 0xf) {
        case ILLEGAL_REQUEST:
@@ -146,12 +146,16 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
        };
     
     result = SCpnt->result;
-    SCpnt->request.rq_status = RQ_INACTIVE;
 
-    if (!SCpnt->device->was_reset && SCpnt->device->scsi_request_fn)
-       (*SCpnt->device->scsi_request_fn)();
+    SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
+    SDpnt = SCpnt->device;
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
 
-    wake_up(&SCpnt->device->device_wait);
+    if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+       (*SDpnt->scsi_request_fn)();
+
+    wake_up(&SDpnt->device_wait);
     return result;
 }
 
@@ -166,6 +170,7 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
     unsigned char cmd[12]; 
     char * cmd_in;
     Scsi_Cmnd * SCpnt;
+    Scsi_Device * SDpnt;
     unsigned char opcode;
     int inlen, outlen, cmdlen;
     int needed, buf_needed;
@@ -221,7 +226,7 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
     cmdlen = COMMAND_SIZE(opcode);
 
     result = verify_area(VERIFY_READ, cmd_in, 
-                         cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen);
+                         cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
     if (result) return result;
 
     copy_from_user ((void *) cmd,  cmd_in,  cmdlen);
@@ -261,7 +266,7 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
 
 #ifndef DEBUG_NO_CMD
     
-    SCpnt = allocate_device(NULL, dev, 1);
+    SCpnt = scsi_allocate_device(NULL, dev, 1);
 
     {
        struct semaphore sem = MUTEX_LOCKED;
@@ -269,6 +274,7 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
        scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
                    timeout, retries);
        down(&sem);
+        SCpnt->request.sem = NULL;
     }
     
     /* 
@@ -289,14 +295,16 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
     }
     result = SCpnt->result;
 
-    SCpnt->request.rq_status = RQ_INACTIVE;
+    wake_up(&SCpnt->device->device_wait);
+    SDpnt = SCpnt->device;
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
 
     if (buf) scsi_free(buf, buf_needed);
     
-    if(SCpnt->device->scsi_request_fn)
-       (*SCpnt->device->scsi_request_fn)();
+    if(SDpnt->scsi_request_fn)
+       (*SDpnt->scsi_request_fn)();
     
-    wake_up(&SCpnt->device->device_wait);
     return result;
 #else
     {
@@ -329,6 +337,17 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
     /* No idea how this happens.... */
     if (!dev) return -ENXIO;
     
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(dev) )
+      {
+        return -ENODEV;
+      }
+    
     switch (cmd) {
     case SCSI_IOCTL_GET_IDLUN:
         result = verify_area(VERIFY_WRITE, arg, sizeof (Scsi_Idlun));
diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c
new file mode 100644 (file)
index 0000000..b76f8c7
--- /dev/null
@@ -0,0 +1,1131 @@
+/*
+ *  scsi.c Copyright (C) 1992 Drew Eckhardt
+ *         Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *
+ *  generic mid-level SCSI driver
+ *      Initial versions: Drew Eckhardt
+ *      Subsequent revisions: Eric Youngdale
+ *
+ *  <drew@colorado.edu>
+ *
+ *  Bug correction thanks go to :
+ *      Rik Faith <faith@cs.unc.edu>
+ *      Tommy Thorn <tthorn>
+ *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
+ *
+ *  Modified by Eric Youngdale eric@aib.com to
+ *  add scatter-gather, multiple outstanding request, and other
+ *  enhancements.
+ *
+ *  Native multichannel, wide scsi, /proc/scsi and hot plugging
+ *  support added by Michael Neuffer <mike@i-connect.net>
+ *
+ *  Added request_module("scsi_hostadapter") for kerneld:
+ *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
+ *  Bjorn Ekwall  <bj0rn@blox.se>
+ *
+ *  Major improvements to the timeout, abort, and reset processing,
+ *  as well as performance modifications for large queue depths by
+ *  Leonard N. Zubkoff <lnz@dandelion.com>
+ */
+
+/*
+ *#########################################################################
+ *#########################################################################
+ *#########################################################################
+ *#########################################################################
+ *             NOTE - NOTE - NOTE - NOTE - NOTE - NOTE - NOTE
+ *
+ *#########################################################################
+ *#########################################################################
+ *#########################################################################
+ *#########################################################################
+ *
+ * This file contains the 'old' scsi error handling.  It is only present
+ * while the new error handling code is being debugged, and while the low
+ * level drivers are being converted to use the new code.  Once the last
+ * driver uses the new code this *ENTIRE* file will be nuked.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+#undef USE_STATIC_SCSI_MEMORY
+
+/*
+static const char RCSid[] = "$Header: /mnt/ide/home/eric/linux/drivers/scsi/RCS/scsi_obsolete.c,v 1.3 1997/04/29 04:25:08 eric Exp $";
+*/
+
+
+#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
+
+
+static int scsi_abort (Scsi_Cmnd *, int code);
+static int scsi_reset (Scsi_Cmnd *, unsigned int);
+
+extern void scsi_old_done (Scsi_Cmnd *SCpnt);
+static int update_timeout (Scsi_Cmnd *, int);
+extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
+extern void internal_cmnd (Scsi_Cmnd * SCpnt);
+
+static volatile struct Scsi_Host * host_active = NULL;
+#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
+                         || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
+
+static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+
+/*
+ *  This is the number  of clock ticks we should wait before we time out
+ *  and abort the command.  This is for  where the scsi.c module generates
+ *  the command, not where it originates from a higher level, in which
+ *  case the timeout is specified there.
+ *
+ *  ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
+ *  respectively.
+ */
+
+#ifdef DEBUG_TIMEOUT
+static void scsi_dump_status(void);
+#endif
+
+
+#ifdef DEBUG
+    #define SCSI_TIMEOUT (5*HZ)
+#else
+    #define SCSI_TIMEOUT (2*HZ)
+#endif
+
+#ifdef DEBUG
+    #define SENSE_TIMEOUT SCSI_TIMEOUT
+    #define ABORT_TIMEOUT SCSI_TIMEOUT
+    #define RESET_TIMEOUT SCSI_TIMEOUT
+#else
+    #define SENSE_TIMEOUT (5*HZ/10)
+    #define RESET_TIMEOUT (5*HZ/10)
+    #define ABORT_TIMEOUT (5*HZ/10)
+#endif
+
+
+/* Do not call reset on error if we just did a reset within 15 sec. */
+#define MIN_RESET_PERIOD (15*HZ)
+
+
+
+/*
+ *  Flag bits for the internal_timeout array
+ */
+#define NORMAL_TIMEOUT 0
+#define IN_ABORT  1
+#define IN_RESET  2
+#define IN_RESET2 4
+#define IN_RESET3 8
+
+/*
+ * This is our time out function, called when the timer expires for a
+ * given host adapter.  It will attempt to abort the currently executing
+ * command, that failing perform a kernel panic.
+ */
+
+void scsi_old_times_out (Scsi_Cmnd * SCpnt)
+{
+
+    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
+    {
+    case NORMAL_TIMEOUT:
+       {
+#ifdef DEBUG_TIMEOUT
+           scsi_dump_status();
+#endif
+       }
+
+       if (!scsi_abort (SCpnt, DID_TIME_OUT))
+           return;
+    case IN_ABORT:
+       printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
+              SCpnt->host->host_no, SCpnt->pid);
+       if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
+           return;
+    case IN_RESET:
+    case (IN_ABORT | IN_RESET):
+       /* This might be controversial, but if there is a bus hang,
+        * you might conceivably want the machine up and running
+        * esp if you have an ide disk.
+        */
+       printk("SCSI host %d channel %d reset (pid %ld) timed out - "
+               "trying harder\n",
+              SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
+       SCpnt->internal_timeout &= ~IN_RESET;
+       SCpnt->internal_timeout |= IN_RESET2;
+        scsi_reset (SCpnt,
+                   SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
+        return;
+    case (IN_ABORT | IN_RESET | IN_RESET2):
+       /* Obviously the bus reset didn't work.
+        * Let's try even harder and call for an HBA reset.
+         * Maybe the HBA itself crashed and this will shake it loose.
+        */
+       printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
+              SCpnt->host->host_no, SCpnt->pid);
+       SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
+       SCpnt->internal_timeout |= IN_RESET3;
+        scsi_reset (SCpnt,
+                   SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
+       return;
+
+    default:
+       printk("SCSI host %d reset (pid %ld) timed out again -\n",
+              SCpnt->host->host_no, SCpnt->pid);
+       printk("probably an unrecoverable SCSI bus or device hang.\n");
+       return;
+
+    }
+
+}
+
+
+static void scsi_request_sense (Scsi_Cmnd * SCpnt)
+{
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+    SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
+    update_timeout(SCpnt, SENSE_TIMEOUT);
+    restore_flags(flags);
+
+
+    memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
+           sizeof(generic_sense));
+
+    SCpnt->cmnd[1] = SCpnt->lun << 5;
+    SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+
+    SCpnt->request_buffer = &SCpnt->sense_buffer;
+    SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+    SCpnt->use_sg = 0;
+    SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+    internal_cmnd (SCpnt);
+}
+
+
+
+
+static int check_sense (Scsi_Cmnd * SCpnt)
+{
+    /* If there is no sense information, request it.  If we have already
+     * requested it, there is no point in asking again - the firmware must
+     * be confused.
+     */
+    if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
+       if(!(SCpnt->flags & ASKED_FOR_SENSE))
+           return SUGGEST_SENSE;
+       else
+           return SUGGEST_RETRY;
+    }
+
+    SCpnt->flags &= ~ASKED_FOR_SENSE;
+
+#ifdef DEBUG_INIT
+    printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
+    print_sense("", SCpnt);
+    printk("\n");
+#endif
+    if (SCpnt->sense_buffer[2] & 0xe0)
+       return SUGGEST_ABORT;
+
+    switch (SCpnt->sense_buffer[2] & 0xf)
+    {
+    case NO_SENSE:
+       return 0;
+    case RECOVERED_ERROR:
+       return SUGGEST_IS_OK;
+
+    case ABORTED_COMMAND:
+       return SUGGEST_RETRY;
+    case NOT_READY:
+    case UNIT_ATTENTION:
+        /*
+         * If we are expecting a CC/UA because of a bus reset that we
+         * performed, treat this just as a retry.  Otherwise this is
+         * information that we should pass up to the upper-level driver
+         * so that we can deal with it there.
+         */
+        if( SCpnt->device->expecting_cc_ua )
+        {
+            SCpnt->device->expecting_cc_ua = 0;
+            return SUGGEST_RETRY;
+        }
+       return SUGGEST_ABORT;
+
+    /* these three are not supported */
+    case COPY_ABORTED:
+    case VOLUME_OVERFLOW:
+    case MISCOMPARE:
+
+    case MEDIUM_ERROR:
+       return SUGGEST_REMAP;
+    case BLANK_CHECK:
+    case DATA_PROTECT:
+    case HARDWARE_ERROR:
+    case ILLEGAL_REQUEST:
+    default:
+       return SUGGEST_ABORT;
+    }
+}
+
+/* This function is the mid-level interrupt routine, which decides how
+ *  to handle error conditions.  Each invocation of this function must
+ *  do one and *only* one of the following:
+ *
+ *  (1) Call last_cmnd[host].done.  This is done for fatal errors and
+ *      normal completion, and indicates that the handling for this
+ *      request is complete.
+ *  (2) Call internal_cmnd to requeue the command.  This will result in
+ *      scsi_done being called again when the retry is complete.
+ *  (3) Call scsi_request_sense.  This asks the host adapter/drive for
+ *      more information about the error condition.  When the information
+ *      is available, scsi_done will be called again.
+ *  (4) Call reset().  This is sort of a last resort, and the idea is that
+ *      this may kick things loose and get the drive working again.  reset()
+ *      automatically calls scsi_request_sense, and thus scsi_done will be
+ *      called again once the reset is complete.
+ *
+ *      If none of the above actions are taken, the drive in question
+ *      will hang. If more than one of the above actions are taken by
+ *      scsi_done, then unpredictable behavior will result.
+ */
+void scsi_old_done (Scsi_Cmnd * SCpnt)
+{
+    int status=0;
+    int exit=0;
+    int checked;
+    int oldto;
+    struct Scsi_Host * host = SCpnt->host;
+    int result = SCpnt->result;
+    SCpnt->serial_number = 0;
+    oldto = update_timeout(SCpnt, 0);
+
+#ifdef DEBUG_TIMEOUT
+    if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
+                     result, SCpnt->target, SCpnt->lun);
+#endif
+
+    /* If we requested an abort, (and we got it) then fix up the return
+     *  status to say why
+     */
+    if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
+       SCpnt->result = result = (result & 0xff00ffff) |
+           (SCpnt->abort_reason << 16);
+
+
+#define CMD_FINISHED 0
+#define MAYREDO  1
+#define REDO     3
+#define PENDING  4
+
+#ifdef DEBUG
+    printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
+#endif
+
+    if(SCpnt->flags & WAS_SENSE)
+    {
+       SCpnt->use_sg = SCpnt->old_use_sg;
+       SCpnt->cmd_len = SCpnt->old_cmd_len;
+    }
+
+    switch (host_byte(result))
+    {
+    case DID_OK:
+       if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
+           /* Failed to obtain sense information */
+       {
+           SCpnt->flags &= ~WAS_SENSE;
+#if 0  /* This cannot possibly be correct. */
+           SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+#endif
+
+           if (!(SCpnt->flags & WAS_RESET))
+           {
+               printk("scsi%d : channel %d target %d lun %d request sense"
+                      " failed, performing reset.\n",
+                      SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
+                      SCpnt->lun);
+               scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+               return;
+           }
+           else
+           {
+               exit = (DRIVER_HARD | SUGGEST_ABORT);
+               status = CMD_FINISHED;
+           }
+       }
+       else switch(msg_byte(result))
+       {
+       case COMMAND_COMPLETE:
+           switch (status_byte(result))
+           {
+           case GOOD:
+               if (SCpnt->flags & WAS_SENSE)
+               {
+#ifdef DEBUG
+                   printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
+                            "parsing sense information.\n");
+#endif
+                   SCpnt->flags &= ~WAS_SENSE;
+#if 0  /* This cannot possibly be correct. */
+                   SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+#endif
+
+                   switch (checked = check_sense(SCpnt))
+                   {
+                   case SUGGEST_SENSE:
+                   case 0:
+#ifdef DEBUG
+                       printk("NO SENSE.  status = REDO\n");
+#endif
+                       update_timeout(SCpnt, oldto);
+                       status = REDO;
+                       break;
+                   case SUGGEST_IS_OK:
+                       break;
+                   case SUGGEST_REMAP:
+#ifdef DEBUG
+                       printk("SENSE SUGGEST REMAP - status = CMD_FINISHED\n");
+#endif
+                       status = CMD_FINISHED;
+                       exit = DRIVER_SENSE | SUGGEST_ABORT;
+                       break;
+                   case SUGGEST_RETRY:
+#ifdef DEBUG
+                       printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
+#endif
+                       status = MAYREDO;
+                       exit = DRIVER_SENSE | SUGGEST_RETRY;
+                       break;
+                   case SUGGEST_ABORT:
+#ifdef DEBUG
+                       printk("SENSE SUGGEST ABORT - status = CMD_FINISHED");
+#endif
+                       status = CMD_FINISHED;
+                       exit =  DRIVER_SENSE | SUGGEST_ABORT;
+                       break;
+                   default:
+                       printk ("Internal error %s %d \n", __FILE__,
+                               __LINE__);
+                   }
+               } /* end WAS_SENSE */
+               else
+               {
+#ifdef DEBUG
+                   printk("COMMAND COMPLETE message returned, "
+                           "status = CMD_FINISHED. \n");
+#endif
+                   exit =  DRIVER_OK;
+                   status = CMD_FINISHED;
+               }
+               break;
+
+           case CHECK_CONDITION:
+           case COMMAND_TERMINATED:
+               switch (check_sense(SCpnt))
+               {
+               case 0:
+                   update_timeout(SCpnt, oldto);
+                   status = REDO;
+                   break;
+               case SUGGEST_REMAP:
+                   status = CMD_FINISHED;
+                   exit =  DRIVER_SENSE | SUGGEST_ABORT;
+                   break;
+               case SUGGEST_RETRY:
+                   status = MAYREDO;
+                   exit = DRIVER_SENSE | SUGGEST_RETRY;
+                   break;
+               case SUGGEST_ABORT:
+                   status = CMD_FINISHED;
+                   exit =  DRIVER_SENSE | SUGGEST_ABORT;
+                   break;
+               case SUGGEST_SENSE:
+                   scsi_request_sense (SCpnt);
+                   status = PENDING;
+                   break;
+               }
+               break;
+
+           case CONDITION_GOOD:
+           case INTERMEDIATE_GOOD:
+           case INTERMEDIATE_C_GOOD:
+               break;
+
+           case BUSY:
+           case QUEUE_FULL:
+               update_timeout(SCpnt, oldto);
+               status = REDO;
+               break;
+
+           case RESERVATION_CONFLICT:
+               printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
+                      " reset.\n", SCpnt->host->host_no, SCpnt->channel);
+               scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+               return;
+#if 0
+               exit = DRIVER_SOFT | SUGGEST_ABORT;
+               status = MAYREDO;
+               break;
+#endif
+           default:
+               printk ("Internal error %s %d \n"
+                       "status byte = %d \n", __FILE__,
+                       __LINE__, status_byte(result));
+
+           }
+           break;
+       default:
+           panic("scsi: unsupported message byte %d received\n",
+                 msg_byte(result));
+       }
+       break;
+    case DID_TIME_OUT:
+#ifdef DEBUG
+       printk("Host returned DID_TIME_OUT - ");
+#endif
+
+       if (SCpnt->flags & WAS_TIMEDOUT)
+       {
+#ifdef DEBUG
+           printk("Aborting\n");
+#endif
+           /*
+             Allow TEST_UNIT_READY and INQUIRY commands to timeout early
+             without causing resets.  All other commands should be retried.
+           */
+           if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
+               SCpnt->cmnd[0] != INQUIRY)
+                   status = MAYREDO;
+           exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
+       }
+       else
+       {
+#ifdef DEBUG
+           printk ("Retrying.\n");
+#endif
+           SCpnt->flags  |= WAS_TIMEDOUT;
+           SCpnt->internal_timeout &= ~IN_ABORT;
+           status = REDO;
+       }
+       break;
+    case DID_BUS_BUSY:
+    case DID_PARITY:
+       status = REDO;
+       break;
+    case DID_NO_CONNECT:
+#ifdef DEBUG
+       printk("Couldn't connect.\n");
+#endif
+       exit  = (DRIVER_HARD | SUGGEST_ABORT);
+       break;
+    case DID_ERROR:
+       status = MAYREDO;
+       exit = (DRIVER_HARD | SUGGEST_ABORT);
+       break;
+    case DID_BAD_TARGET:
+    case DID_ABORT:
+       exit = (DRIVER_INVALID | SUGGEST_ABORT);
+       break;
+    case DID_RESET:
+       if (SCpnt->flags & IS_RESETTING)
+       {
+           SCpnt->flags &= ~IS_RESETTING;
+           status = REDO;
+           break;
+       }
+
+       if(msg_byte(result) == GOOD &&
+          status_byte(result) == CHECK_CONDITION) {
+           switch (check_sense(SCpnt)) {
+           case 0:
+               update_timeout(SCpnt, oldto);
+               status = REDO;
+               break;
+           case SUGGEST_REMAP:
+           case SUGGEST_RETRY:
+               status = MAYREDO;
+               exit = DRIVER_SENSE | SUGGEST_RETRY;
+               break;
+           case SUGGEST_ABORT:
+               status = CMD_FINISHED;
+               exit =  DRIVER_SENSE | SUGGEST_ABORT;
+               break;
+           case SUGGEST_SENSE:
+               scsi_request_sense (SCpnt);
+               status = PENDING;
+               break;
+           }
+       } else {
+           status=REDO;
+           exit = SUGGEST_RETRY;
+       }
+       break;
+    default :
+       exit = (DRIVER_ERROR | SUGGEST_DIE);
+    }
+
+    switch (status)
+    {
+    case CMD_FINISHED:
+    case PENDING:
+       break;
+    case MAYREDO:
+#ifdef DEBUG
+       printk("In MAYREDO, allowing %d retries, have %d\n",
+              SCpnt->allowed, SCpnt->retries);
+#endif
+       if ((++SCpnt->retries) < SCpnt->allowed)
+       {
+           if ((SCpnt->retries >= (SCpnt->allowed >> 1))
+               && !(SCpnt->host->last_reset > 0 &&
+                    jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
+               && !(SCpnt->flags & WAS_RESET))
+           {
+               printk("scsi%d channel %d : resetting for second half of retries.\n",
+                      SCpnt->host->host_no, SCpnt->channel);
+               scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+               break;
+           }
+
+       }
+       else
+       {
+           status = CMD_FINISHED;
+           break;
+       }
+       /* fall through to REDO */
+
+    case REDO:
+
+       if (SCpnt->flags & WAS_SENSE)
+           scsi_request_sense(SCpnt);
+       else
+       {
+           memcpy ((void *) SCpnt->cmnd,
+                   (void*) SCpnt->data_cmnd,
+                   sizeof(SCpnt->data_cmnd));
+           SCpnt->request_buffer = SCpnt->buffer;
+           SCpnt->request_bufflen = SCpnt->bufflen;
+           SCpnt->use_sg = SCpnt->old_use_sg;
+           SCpnt->cmd_len = SCpnt->old_cmd_len;
+           internal_cmnd (SCpnt);
+       }
+       break;
+    default:
+       INTERNAL_ERROR;
+    }
+
+    if (status == CMD_FINISHED) {
+#ifdef DEBUG
+       printk("Calling done function - at address %p\n", SCpnt->done);
+#endif
+       host->host_busy--; /* Indicate that we are free */
+
+       if (host->block && host->host_busy == 0) {
+           host_active = NULL;
+
+           /* For block devices "wake_up" is done in end_scsi_request */
+           if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
+               MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
+               struct Scsi_Host * next;
+
+               for (next = host->block; next != host; next = next->block)
+                   wake_up(&next->host_wait);
+           }
+
+       }
+
+       wake_up(&host->host_wait);
+       SCpnt->result = result | ((exit & 0xff) << 24);
+       SCpnt->use_sg = SCpnt->old_use_sg;
+       SCpnt->cmd_len = SCpnt->old_cmd_len;
+       SCpnt->done (SCpnt);
+    }
+
+#undef CMD_FINISHED
+#undef REDO
+#undef MAYREDO
+#undef PENDING
+}
+
+/*
+ * The scsi_abort function interfaces with the abort() function of the host
+ * we are aborting, and causes the current command to not complete.  The
+ * caller should deal with any error messages or status returned on the
+ * next call.
+ *
+ * This will not be called reentrantly for a given host.
+ */
+
+/*
+ * Since we're nice guys and specified that abort() and reset()
+ * can be non-reentrant.  The internal_timeout flags are used for
+ * this.
+ */
+
+
+static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
+{
+    int oldto;
+    unsigned long flags;
+    struct Scsi_Host * host = SCpnt->host;
+
+    while(1)
+    {
+       save_flags(flags);
+       cli();
+
+       /*
+        * Protect against races here.  If the command is done, or we are
+        * on a different command forget it.
+        */
+       if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+           restore_flags(flags);
+           return 0;
+       }
+
+       if (SCpnt->internal_timeout & IN_ABORT)
+       {
+           restore_flags(flags);
+           while (SCpnt->internal_timeout & IN_ABORT)
+               barrier();
+       }
+       else
+       {
+           SCpnt->internal_timeout |= IN_ABORT;
+           oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
+
+           if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
+               /* OK, this command must have died when we did the
+                *  reset.  The device itself must have lied.
+                */
+               printk("Stale command on %d %d:%d appears to have died when"
+                      " the bus was reset\n",
+                      SCpnt->channel, SCpnt->target, SCpnt->lun);
+           }
+
+           restore_flags(flags);
+           if (!host->host_busy) {
+               SCpnt->internal_timeout &= ~IN_ABORT;
+               update_timeout(SCpnt, oldto);
+               return 0;
+           }
+           printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
+                  " channel %d, id %d, lun %d ",
+                  SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
+                  (int) SCpnt->target, (int) SCpnt->lun);
+           print_command (SCpnt->cmnd);
+           if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
+               return 0;
+           SCpnt->abort_reason = why;
+           switch(host->hostt->abort(SCpnt)) {
+               /* We do not know how to abort.  Try waiting another
+                * time increment and see if this helps. Set the
+                * WAS_TIMEDOUT flag set so we do not try this twice
+                */
+           case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
+                                  * this is too severe
+                                  */
+           case SCSI_ABORT_SNOOZE:
+               if(why == DID_TIME_OUT) {
+                   save_flags(flags);
+                   cli();
+                   SCpnt->internal_timeout &= ~IN_ABORT;
+                   if(SCpnt->flags & WAS_TIMEDOUT) {
+                       restore_flags(flags);
+                       return 1; /* Indicate we cannot handle this.
+                                  * We drop down into the reset handler
+                                  * and try again
+                                  */
+                   } else {
+                       SCpnt->flags |= WAS_TIMEDOUT;
+                       oldto = SCpnt->timeout_per_command;
+                       update_timeout(SCpnt, oldto);
+                   }
+                   restore_flags(flags);
+               }
+               return 0;
+           case SCSI_ABORT_PENDING:
+               if(why != DID_TIME_OUT) {
+                   save_flags(flags);
+                   cli();
+                   update_timeout(SCpnt, oldto);
+                   restore_flags(flags);
+               }
+               return 0;
+           case SCSI_ABORT_SUCCESS:
+               /* We should have already aborted this one.  No
+                * need to adjust timeout
+                */
+                 SCpnt->internal_timeout &= ~IN_ABORT;
+                 return 0;
+           case SCSI_ABORT_NOT_RUNNING:
+               SCpnt->internal_timeout &= ~IN_ABORT;
+               update_timeout(SCpnt, 0);
+               return 0;
+           case SCSI_ABORT_ERROR:
+           default:
+               SCpnt->internal_timeout &= ~IN_ABORT;
+               return 1;
+           }
+       }
+    }
+}
+
+
+/* Mark a single SCSI Device as having been reset. */
+
+static inline void scsi_mark_device_reset(Scsi_Device *Device)
+{
+  Device->was_reset = 1;
+  Device->expecting_cc_ua = 1;
+}
+
+
+/* Mark all SCSI Devices on a specific Host as having been reset. */
+
+void scsi_mark_host_reset(struct Scsi_Host *Host)
+{
+  Scsi_Cmnd   * SCpnt;
+  Scsi_Device * SDpnt;
+
+  for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next)
+    {
+      for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+        scsi_mark_device_reset(SCpnt->device);
+    }
+}
+
+
+/* Mark all SCSI Devices on a specific Host Bus as having been reset. */
+
+static void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
+{
+  Scsi_Cmnd *SCpnt;
+  Scsi_Device * SDpnt;
+
+  for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next)
+    {
+      for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+        if (SCpnt->channel == channel)
+         scsi_mark_device_reset(SCpnt->device);
+    }
+}
+
+
+static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{
+    int temp;
+    unsigned long flags;
+    Scsi_Cmnd * SCpnt1;
+    Scsi_Device * SDpnt;
+    struct Scsi_Host * host = SCpnt->host;
+
+    printk("SCSI bus is being reset for host %d channel %d.\n",
+          host->host_no, SCpnt->channel);
+
+#if 0
+    /*
+     * First of all, we need to make a recommendation to the low-level
+     * driver as to whether a BUS_DEVICE_RESET should be performed,
+     * or whether we should do a full BUS_RESET.  There is no simple
+     * algorithm here - we basically use a series of heuristics
+     * to determine what we should do.
+     */
+    SCpnt->host->suggest_bus_reset = FALSE;
+
+    /*
+     * First see if all of the active devices on the bus have
+     * been jammed up so that we are attempting resets.  If so,
+     * then suggest a bus reset.  Forcing a bus reset could
+     * result in some race conditions, but no more than
+     * you would usually get with timeouts.  We will cross
+     * that bridge when we come to it.
+     *
+     * This is actually a pretty bad idea, since a sequence of
+     * commands will often timeout together and this will cause a
+     * Bus Device Reset followed immediately by a SCSI Bus Reset.
+     * If all of the active devices really are jammed up, the
+     * Bus Device Reset will quickly timeout and scsi_times_out
+     * will follow up with a SCSI Bus Reset anyway.
+     */
+    SCpnt1 = host->host_queue;
+    while(SCpnt1) {
+       if( SCpnt1->request.rq_status != RQ_INACTIVE
+           && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
+               break;
+        SCpnt1 = SCpnt1->next;
+       }
+    if( SCpnt1 == NULL ) {
+        reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
+    }
+
+    /*
+     * If the code that called us is suggesting a hard reset, then
+     * definitely request it.  This usually occurs because a
+     * BUS_DEVICE_RESET times out.
+     *
+     * Passing reset_flags along takes care of this automatically.
+     */
+    if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
+        SCpnt->host->suggest_bus_reset = TRUE;
+    }
+#endif
+
+    while (1) {
+       save_flags(flags);
+       cli();
+
+       /*
+        * Protect against races here.  If the command is done, or we are
+        * on a different command forget it.
+        */
+       if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
+         if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+           restore_flags(flags);
+           return 0;
+         }
+
+       if (SCpnt->internal_timeout & IN_RESET)
+       {
+           restore_flags(flags);
+           while (SCpnt->internal_timeout & IN_RESET)
+               barrier();
+       }
+       else
+       {
+           SCpnt->internal_timeout |= IN_RESET;
+           update_timeout(SCpnt, RESET_TIMEOUT);
+
+           if (host->host_busy)
+           {
+               restore_flags(flags);
+                for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+                {
+                    SCpnt1 = SDpnt->device_queue;
+                    while(SCpnt1) {
+                        if (SCpnt1->request.rq_status != RQ_INACTIVE) {
+#if 0
+                            if (!(SCpnt1->flags & IS_RESETTING) &&
+                                !(SCpnt1->internal_timeout & IN_ABORT))
+                                scsi_abort(SCpnt1, DID_RESET);
+#endif
+                            SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
+                        }
+                        SCpnt1 = SCpnt1->next;
+                    }
+                }
+
+               host->last_reset = jiffies;
+               temp = host->hostt->reset(SCpnt, reset_flags);
+               /*
+                 This test allows the driver to introduce an additional bus
+                 settle time delay by setting last_reset up to 20 seconds in
+                 the future.  In the normal case where the driver does not
+                 modify last_reset, it must be assumed that the actual bus
+                 reset occurred immediately prior to the return to this code,
+                 and so last_reset must be updated to the current time, so
+                 that the delay in internal_cmnd will guarantee at least a
+                 MIN_RESET_DELAY bus settle time.
+               */
+               if (host->last_reset - jiffies > 20UL * HZ)
+                 host->last_reset = jiffies;
+           }
+           else
+           {
+               if (!host->block) host->host_busy++;
+               restore_flags(flags);
+               host->last_reset = jiffies;
+               SCpnt->flags |= (WAS_RESET | IS_RESETTING);
+               temp = host->hostt->reset(SCpnt, reset_flags);
+               if ((host->last_reset < jiffies) ||
+                   (host->last_reset > (jiffies + 20 * HZ)))
+                 host->last_reset = jiffies;
+               if (!host->block) host->host_busy--;
+           }
+
+#ifdef DEBUG
+           printk("scsi reset function returned %d\n", temp);
+#endif
+
+            /*
+             * Now figure out what we need to do, based upon
+             * what the low level driver said that it did.
+            * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
+            * or SCSI_RESET_WAKEUP, then the low level driver did a
+            * bus device reset or bus reset, so we should go through
+            * and mark one or all of the devices on that bus
+            * as having been reset.
+             */
+            switch(temp & SCSI_RESET_ACTION) {
+           case SCSI_RESET_SUCCESS:
+               if (temp & SCSI_RESET_HOST_RESET)
+                 scsi_mark_host_reset(host);
+               else if (temp & SCSI_RESET_BUS_RESET)
+                 scsi_mark_bus_reset(host, SCpnt->channel);
+               else scsi_mark_device_reset(SCpnt->device);
+               save_flags(flags);
+               cli();
+               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+               restore_flags(flags);
+               return 0;
+           case SCSI_RESET_PENDING:
+               if (temp & SCSI_RESET_HOST_RESET)
+                 scsi_mark_host_reset(host);
+               else if (temp & SCSI_RESET_BUS_RESET)
+                 scsi_mark_bus_reset(host, SCpnt->channel);
+               else scsi_mark_device_reset(SCpnt->device);
+           case SCSI_RESET_NOT_RUNNING:
+               return 0;
+           case SCSI_RESET_PUNT:
+               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+                scsi_request_sense (SCpnt);
+                return 0;
+           case SCSI_RESET_WAKEUP:
+               if (temp & SCSI_RESET_HOST_RESET)
+                 scsi_mark_host_reset(host);
+               else if (temp & SCSI_RESET_BUS_RESET)
+                 scsi_mark_bus_reset(host, SCpnt->channel);
+               else scsi_mark_device_reset(SCpnt->device);
+               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+               scsi_request_sense (SCpnt);
+                /*
+                 * If a bus reset was performed, we
+                 * need to wake up each and every command
+                 * that was active on the bus or if it was a HBA
+                 * reset all active commands on all channels
+                 */
+                if( temp & SCSI_RESET_HOST_RESET )
+                {
+                    for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+                    {
+                        SCpnt1 = SDpnt->device_queue;
+                        while(SCpnt1) {
+                            if (SCpnt1->request.rq_status != RQ_INACTIVE
+                                && SCpnt1 != SCpnt)
+                                scsi_request_sense (SCpnt1);
+                            SCpnt1 = SCpnt1->next;
+                        }
+                    }
+                } else if( temp & SCSI_RESET_BUS_RESET ) {
+                    for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+                    {
+                        SCpnt1 = SDpnt->device_queue;
+                        while(SCpnt1) {
+                            if(SCpnt1->request.rq_status != RQ_INACTIVE
+                               && SCpnt1 != SCpnt
+                               && SCpnt1->channel == SCpnt->channel)
+                                scsi_request_sense (SCpnt);
+                            SCpnt1 = SCpnt1->next;
+                        }
+                    }
+                }
+               return 0;
+           case SCSI_RESET_SNOOZE:
+               /* In this case, we set the timeout field to 0
+                * so that this command does not time out any more,
+                * and we return 1 so that we get a message on the
+                * screen.
+                */
+               save_flags(flags);
+               cli();
+               SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+               update_timeout(SCpnt, 0);
+               restore_flags(flags);
+               /* If you snooze, you lose... */
+           case SCSI_RESET_ERROR:
+           default:
+               return 1;
+           }
+
+           return temp;
+       }
+    }
+}
+
+/*
+ * The strategy is to cause the timer code to call scsi_times_out()
+ * when the soonest timeout is pending.
+ * The arguments are used when we are queueing a new command, because
+ * we do not want to subtract the time used from this time, but when we
+ * set the timer, we want to take this value into account.
+ */
+
+static int update_timeout(Scsi_Cmnd * SCset, int timeout)
+{
+  int  rtn;
+
+  /*
+   * We are using the new error handling code to actually register/deregister
+   * timers for timeout.
+   */
+
+  if( SCset->eh_timeout.expires == 0 )
+    {
+      rtn = 0;
+    }
+  else
+    {
+      rtn = SCset->eh_timeout.expires - jiffies;
+    }
+
+  if( timeout == 0 )
+    {
+      scsi_delete_timer(SCset);
+    }
+  else
+    {
+      scsi_add_timer(SCset, timeout, scsi_old_times_out);
+    }
+
+  return rtn;
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/scsi_obsolete.h b/drivers/scsi/scsi_obsolete.h
new file mode 100644 (file)
index 0000000..a923e8e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  scsi_obsolete.h Copyright (C) 1997 Eric Youngdale
+ *
+ */
+
+#ifndef _SCSI_OBSOLETE_H
+#define _SCSI_OBSOLETE_H
+
+/*
+ * These are the return codes for the abort and reset functions.  The mid-level
+ * code uses these to decide what to do next.  Each of the low level abort
+ * and reset functions must correctly indicate what it has done.
+ * The descriptions are written from the point of view of the mid-level code,
+ * so that the return code is telling the mid-level drivers exactly what
+ * the low level driver has already done, and what remains to be done.
+ */
+
+/* We did not do anything.  
+ * Wait some more for this command to complete, and if this does not work, 
+ * try something more serious. */ 
+#define SCSI_ABORT_SNOOZE 0
+
+/* This means that we were able to abort the command.  We have already
+ * called the mid-level done function, and do not expect an interrupt that 
+ * will lead to another call to the mid-level done function for this command */
+#define SCSI_ABORT_SUCCESS 1
+
+/* We called for an abort of this command, and we should get an interrupt 
+ * when this succeeds.  Thus we should not restore the timer for this
+ * command in the mid-level abort function. */
+#define SCSI_ABORT_PENDING 2
+
+/* Unable to abort - command is currently on the bus.  Grin and bear it. */
+#define SCSI_ABORT_BUSY 3
+
+/* The command is not active in the low level code. Command probably
+ * finished. */
+#define SCSI_ABORT_NOT_RUNNING 4
+
+/* Something went wrong.  The low level driver will indicate the correct
+ * error condition when it calls scsi_done, so the mid-level abort function
+ * can simply wait until this comes through */
+#define SCSI_ABORT_ERROR 5
+
+/* We do not know how to reset the bus, or we do not want to.  Bummer.
+ * Anyway, just wait a little more for the command in question, and hope that
+ * it eventually finishes.  If it never finishes, the SCSI device could
+ * hang, so use this with caution. */
+#define SCSI_RESET_SNOOZE 0
+
+/* We do not know how to reset the bus, or we do not want to.  Bummer.
+ * We have given up on this ever completing.  The mid-level code will
+ * request sense information to decide how to proceed from here. */
+#define SCSI_RESET_PUNT 1
+
+/* This means that we were able to reset the bus.  We have restarted all of
+ * the commands that should be restarted, and we should be able to continue
+ * on normally from here.  We do not expect any interrupts that will return
+ * DID_RESET to any of the other commands in the host_queue, and the mid-level
+ * code does not need to do anything special to keep the commands alive. 
+ * If a hard reset was performed then all outstanding commands on the
+ * bus have been restarted. */
+#define SCSI_RESET_SUCCESS 2
+
+/* We called for a reset of this bus, and we should get an interrupt 
+ * when this succeeds.  Each command should get its own status
+ * passed up to scsi_done, but this has not happened yet. 
+ * If a hard reset was performed, then we expect an interrupt
+ * for *each* of the outstanding commands that will have the
+ * effect of restarting the commands.
+ */
+#define SCSI_RESET_PENDING 3
+
+/* We did a reset, but do not expect an interrupt to signal DID_RESET.
+ * This tells the upper level code to request the sense info, and this
+ * should keep the command alive. */
+#define SCSI_RESET_WAKEUP 4
+
+/* The command is not active in the low level code. Command probably
+   finished. */
+#define SCSI_RESET_NOT_RUNNING 5
+
+/* Something went wrong, and we do not know how to fix it. */
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS         0x01
+#define SCSI_RESET_ASYNCHRONOUS                0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET   0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET  0x08
+/*
+ * This is a bitmask that is ored with one of the above codes.
+ * It tells the mid-level code that we did a hard reset.
+ */
+#define SCSI_RESET_BUS_RESET 0x100
+/*
+ * This is a bitmask that is ored with one of the above codes.
+ * It tells the mid-level code that we did a host adapter reset.
+ */
+#define SCSI_RESET_HOST_RESET 0x200
+/*
+ * Used to mask off bits and to obtain the basic action that was
+ * performed.  
+ */
+#define SCSI_RESET_ACTION   0xff
+
+#endif /* SCSI_OBSOLETE_H */
index 83c21c20bb3ceeba62bd270f5c392560f17a8515..0d8c958fc0fb97c56cfdc4c694d1ca59e36882c9 100644 (file)
  * Michael A. Griffith <grif@acm.org>
  */
 
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
 #define __NO_VERSION__
 #include <linux/module.h>
 
@@ -39,6 +34,7 @@
 #define FALSE 0
 #endif
 
+#ifdef CONFIG_PROC_FS
 extern int scsi_proc_info(char *, char **, off_t, int, int, int);
  
 struct scsi_dir {
@@ -295,6 +291,7 @@ void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
     *size = y; 
     return;
 }
+#endif /* CONFIG_SCSI_PROC */
 
 /*
  * Overrides for Emacs so that we get a uniform tabbing style.
diff --git a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c
new file mode 100644 (file)
index 0000000..b9e2a4f
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ *  scsi_queue.c Copyright (C) 1997 Eric Youngdale
+ *
+ *  generic mid-level SCSI queueing.
+ *
+ *  The point of this is that we need to track when hosts are unable to
+ *  accept a command because they are busy.  In addition, we track devices
+ *  that cannot accept a command because of a QUEUE_FULL condition.  In both
+ *  of these cases, we enter the command in the queue.  At some later point,
+ *  we attempt to remove commands from the queue and retry them.
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/smp_lock.h>
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+/*
+ * TODO:
+ *     1) Prevent multiple traversals of list to look for commands to
+ *        queue.
+ *     2) Protect against multiple insertions of list at the same time.
+ * DONE:
+ *     1) Set state of scsi command to a new state value for ml queue.
+ *     2) Insert into queue when host rejects command.
+ *     3) Make sure status code is properly passed from low-level queue func
+ *        so that internal_cmnd properly returns the right value.
+ *     4) Insert into queue when QUEUE_FULL.
+ *     5) Cull queue in bottom half handler.
+ *     6) Check usage count prior to queue insertion.  Requeue if usage
+ *        count is 0.
+ *     7) Don't send down any more commands if the host/device is busy.
+ */
+
+static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_queue.c,v 1.1 1997/10/21 11:16:38 eric Exp $";
+
+/*
+ * Lock used to prevent more than one process from frobbing the list at the
+ * same time.  FIXME(eric) - there should be seperate spinlocks for each host.
+ * This will reduce contention.
+ */
+spinlock_t     scsi_mlqueue_lock        = SPIN_LOCK_UNLOCKED;
+spinlock_t     scsi_mlqueue_remove_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Function:    scsi_mlqueue_insert()
+ *
+ * Purpose:     Insert a command in the midlevel queue.
+ *
+ * Arguments:   cmd    - command that we are adding to queue.
+ *             reason - why we are inserting command to queue.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:      We do this for one of two cases.  Either the host is busy
+ *             and it cannot accept any more commands for the time being,
+ *             or the device returned QUEUE_FULL and can accept no more
+ *             commands.
+ * Notes:      This could be called either from an interrupt context or a
+ *             normal process context.
+ */
+int
+scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
+{
+    Scsi_Cmnd        * cpnt;
+    unsigned long      flags;
+    struct Scsi_Host * host;
+
+    SCSI_LOG_MLQUEUE(1,printk("Inserting command %p into mlqueue\n", cmd));
+
+    /*
+     * We are inserting the command into the ml queue.  First, we
+     * cancel the timer, so it doesn't time out.
+     */
+    scsi_delete_timer(cmd);
+
+    host = cmd->host;
+
+    /*
+     * Next, set the appropriate busy bit for the device/host.
+     */
+    if( reason == SCSI_MLQUEUE_HOST_BUSY )
+    {
+       /*
+        * Protect against race conditions.  If the host isn't busy,
+        * assume that something actually completed, and that we should
+        * be able to queue a command now.  Note that there is an implicit
+        * assumption that every host can always queue at least one command.
+        * If a host is inactive and cannot queue any commands, I don't see
+        * how things could possibly work anyways.
+        */
+       if( host->host_busy == 0 )
+       {
+           if( scsi_retry_command(cmd) == 0 )
+           {
+               return 0;
+           }
+       }
+
+       host->host_blocked   = TRUE;
+       cmd->host_wait       = TRUE;
+    }
+    else
+    {
+       /*
+        * Protect against race conditions.  If the device isn't busy,
+        * assume that something actually completed, and that we should
+        * be able to queue a command now.  Note that there is an implicit
+        * assumption that every host can always queue at least one command.
+        * If a host is inactive and cannot queue any commands, I don't see
+        * how things could possibly work anyways.
+        */
+       if( cmd->device->device_busy == 0 )
+       {
+           if( scsi_retry_command(cmd) == 0 )
+           {
+               return 0;
+           }
+       }
+
+       cmd->device->device_busy = TRUE;
+       cmd->device_wait         = TRUE;
+    }
+
+    /*
+     * Register the fact that we own the thing for now.
+     */
+    cmd->state = SCSI_STATE_MLQUEUE;
+    cmd->owner = SCSI_OWNER_MIDLEVEL;
+    cmd->bh_next = NULL;
+
+    /*
+     * As a performance enhancement, look to see whether the list is
+     * empty.  If it is, then we can just atomicly insert the command
+     * in the list and return without locking.
+     */
+    if( host->pending_commands == NULL )
+    {
+       cpnt = xchg(&host->pending_commands, cmd);
+       if( cpnt == NULL )
+       {
+           return 0;
+       }
+       /*
+        * Rats.  Something slipped in while we were exchanging.
+        * Swap it back and fall through to do it the hard way.
+        */
+       cmd = xchg(&host->pending_commands, cpnt);
+
+    }
+
+    /*
+     * Next append the command to the list of pending commands.
+     */
+    spin_lock_irqsave(&scsi_mlqueue_lock, flags);
+    for(cpnt = host->pending_commands; cpnt && cpnt->bh_next; 
+       cpnt = cpnt->bh_next)
+    {
+       continue;
+    }
+    if( cpnt != NULL )
+    {
+       cpnt->bh_next = cmd;
+    }
+    else
+    {
+       host->pending_commands = cmd;
+    }
+
+    spin_unlock_irqrestore(&scsi_mlqueue_lock, flags);
+    return 0;
+}
+
+/*
+ * Function:    scsi_mlqueue_finish()
+ *
+ * Purpose:     Try and queue commands from the midlevel queue.
+ *
+ * Arguments:   host    - host that just finished a command.
+ *             device  - device that just finished a command.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:      This could be called either from an interrupt context or a
+ *             normal process context.
+ */
+int
+scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device)
+{
+    Scsi_Cmnd      * cpnt;
+    unsigned long    flags;
+    Scsi_Cmnd      * next;
+    Scsi_Cmnd      * prev;
+    int              reason = 0;
+    int              rtn;
+
+    SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish starting\n"));
+    /*
+     * First, clear the flag for the host/device.  We will then start
+     * pushing commands through until either something else blocks, or
+     * the queue is empty.
+     */
+    if( host->host_blocked )
+    {
+       reason = SCSI_MLQUEUE_HOST_BUSY;
+       host->host_blocked = FALSE;
+    }
+
+    if( device->device_busy )
+    {
+       reason = SCSI_MLQUEUE_DEVICE_BUSY;
+       device->device_busy = FALSE;
+    }
+
+    /*
+     * Walk the list of commands to see if there is anything we can
+     * queue.  This probably needs to be optimized for performance at
+     * some point.
+     */
+    prev = NULL;
+    spin_lock_irqsave(&scsi_mlqueue_remove_lock, flags);
+    for(cpnt = host->pending_commands; cpnt; cpnt = next)
+    {
+       next = cpnt->bh_next;
+       /*
+        * First, see if this command is suitable for being retried now.
+        */
+       if( reason == SCSI_MLQUEUE_HOST_BUSY )
+       {
+           /*
+            * The host was busy, but isn't any more.  Thus we may be
+            * able to queue the command now, but we were waiting for
+            * the device, then we should keep waiting.  Similarily, if
+            * the device is now busy, we should also keep waiting.
+            */
+           if(    (cpnt->host_wait == FALSE)
+               || (device->device_busy == TRUE) )
+           {
+               prev = cpnt;
+               continue;
+           }
+       }
+
+       if( reason == SCSI_MLQUEUE_DEVICE_BUSY )
+       {
+           /*
+            * The device was busy, but isn't any more.  Thus we may be
+            * able to queue the command now, but we were waiting for
+            * the host, then we should keep waiting.  Similarily, if
+            * the host is now busy, we should also keep waiting.
+            */
+           if(    (cpnt->device_wait == FALSE)
+               || (host->host_blocked == TRUE) )
+           {
+               prev = cpnt;
+               continue;
+           }
+       }
+
+       /*
+        * First, remove the command from the list.
+        */
+       if( prev == NULL )
+       {
+           host->pending_commands = next;
+       }
+       else
+       {
+           prev->bh_next = next;
+       }
+       cpnt->bh_next = NULL;
+
+       rtn = scsi_retry_command(cpnt);
+
+       /*
+        * If we got a non-zero return value, it means that the host rejected
+        * the command.  The internal_cmnd function will have added the
+        * command back to the end of the list, so we don't have anything
+        * more to do here except return.
+        */
+       if( rtn )
+       {
+           spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
+           SCSI_LOG_MLQUEUE(1,printk("Unable to remove command %p from mlqueue\n", cpnt));
+           goto finish;
+       }
+       SCSI_LOG_MLQUEUE(1,printk("Removed command %p from mlqueue\n", cpnt));
+    }
+
+    spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
+finish:
+    SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish returning\n"));
+    return 0;
+}
index bf82a51cbf2f5f74c6c15f9b85c0dc2e87db0c12..166830208cdad1b241e4f0d70030902c431f8830 100644 (file)
@@ -38,6 +38,8 @@ extern int scsicam_bios_param (Disk * disk,
 extern void print_command (unsigned char *command);
 extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
 
+extern const char *const scsi_device_types[];
+
 EXPORT_SYMBOL(scsi_register_module);
 EXPORT_SYMBOL(scsi_unregister_module);
 EXPORT_SYMBOL(scsi_free);
@@ -45,7 +47,7 @@ EXPORT_SYMBOL(scsi_malloc);
 EXPORT_SYMBOL(scsi_register);
 EXPORT_SYMBOL(scsi_unregister);
 EXPORT_SYMBOL(scsicam_bios_param);
-EXPORT_SYMBOL(allocate_device);
+EXPORT_SYMBOL(scsi_allocate_device);
 EXPORT_SYMBOL(scsi_do_cmd);
 EXPORT_SYMBOL(scsi_command_size);
 EXPORT_SYMBOL(scsi_init_malloc);
@@ -55,13 +57,17 @@ EXPORT_SYMBOL(print_command);
 EXPORT_SYMBOL(print_sense);
 EXPORT_SYMBOL(print_msg);
 EXPORT_SYMBOL(print_status);
-EXPORT_SYMBOL(dma_free_sectors);
+EXPORT_SYMBOL(scsi_dma_free_sectors);
 EXPORT_SYMBOL(kernel_scsi_ioctl);
-EXPORT_SYMBOL(need_isa_buffer);
-EXPORT_SYMBOL(request_queueable);
+EXPORT_SYMBOL(scsi_need_isa_buffer);
+EXPORT_SYMBOL(scsi_request_queueable);
+EXPORT_SYMBOL(scsi_release_command);
 EXPORT_SYMBOL(print_Scsi_Cmnd);
-EXPORT_SYMBOL(scsi_mark_host_reset);
-EXPORT_SYMBOL(scsi_mark_bus_reset);
+EXPORT_SYMBOL(scsi_block_when_processing_errors);
+#if defined(CONFIG_SCSI_LOGGING) /* { */
+EXPORT_SYMBOL(scsi_logging_level);
+#endif
+
 #if defined(CONFIG_PROC_FS)
 EXPORT_SYMBOL(proc_print_scsidevice);
 #endif
@@ -71,7 +77,6 @@ EXPORT_SYMBOL(proc_print_scsidevice);
 EXPORT_SYMBOL(scsi_hostlist);
 EXPORT_SYMBOL(scsi_hosts);
 EXPORT_SYMBOL(scsi_devicelist);
-EXPORT_SYMBOL(scsi_devices);
 EXPORT_SYMBOL(scsi_device_types);
 
 
index e45d80f4e754724f84275c9e82436dc6a38f2a61..3d434d2f69f50f4de976c6fea33c53d17010205a 100644 (file)
  * For more information, please consult the SCSI-CAM draft.
  */
 
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
 #define __NO_VERSION__
 #include <linux/module.h>
 
index 4ec0a82fa6ee0f73c89a08e3e0d477efe5eb2ba9..295a32a36e578a5dc6a33819a04f1e816b6d46f4 100644 (file)
@@ -87,6 +87,26 @@ static int sd_attach(Scsi_Device *);
 static int sd_detect(Scsi_Device *);
 static void sd_detach(Scsi_Device *);
 
+static void sd_devname(unsigned int disknum, char * buffer)
+{
+    if( disknum <= 26 )
+    {
+        sprintf(buffer, "sd%c", 'a' + (disknum >> 4));
+    }
+    else
+    {
+        unsigned int min1;
+        unsigned int min2;
+        /*
+         * For larger numbers of disks, we need to go to a new
+         * naming scheme.
+         */
+        min1 = (disknum >> 4) / 26;
+        min2 = (disknum >> 4) % 26;
+        sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2);
+    }
+}
+
 struct Scsi_Device_Template sd_template =
 { NULL, "disk", "sd", NULL, TYPE_DISK,
       SCSI_DISK_MAJOR, 0, 0, 0, 1,
@@ -99,9 +119,20 @@ static int sd_open(struct inode * inode, struct file * filp)
     int target;
     target =  DEVICE_NR(inode->i_rdev);
 
+    SCSI_LOG_HLQUEUE(1,printk("target=%d, max=%d\n", target, sd_template.dev_max));
+
     if(target >= sd_template.dev_max || !rscsi_disks[target].device)
        return -ENXIO;   /* No such device */
 
+    /*
+     * If the device is in error recovery, wait until it is done.
+     * If the device is offline, then disallow any access to it.
+     */
+    if( !scsi_block_when_processing_errors(rscsi_disks[target].device) )
+      {
+        return -ENXIO;
+      }
+
     /*
      * Make sure that only one process can do a check_change_disk at one time.
      * This is also used to lock out further access when the partition table
@@ -128,6 +159,16 @@ static int sd_open(struct inode * inode, struct file * filp)
            return -EROFS;
     }
 
+    /*
+     * It is possible that the disk changing stuff resulted in the device being taken
+     * offline.  If this is the case, report this to the user, and don't pretend that
+     * the open actually succeeded.
+     */
+    if( !rscsi_disks[target].device->online )
+    {
+        return -ENXIO;
+    }
+
     /*
      * See if we are requesting a non-existent partition.  Do this
      * after checking for disk change.
@@ -222,14 +263,18 @@ static void sd_geninit (struct gendisk *ignored)
 static void rw_intr (Scsi_Cmnd *SCpnt)
 {
     int result = SCpnt->result;
+    char nbuff[6];
     int this_count = SCpnt->bufflen >> 9;
     int good_sectors = (result == 0 ? this_count : 0);
     int block_sectors = 1;
 
-#ifdef DEBUG
-    printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev),
-          SCpnt->host->host_no, result);
-#endif
+    sd_devname(MINOR(SCpnt->request.rq_dev) >> 4, nbuff);
+
+    SCSI_LOG_HLCOMPLETE(1,printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff,
+          SCpnt->host->host_no, 
+                                 result, 
+                                 SCpnt->sense_buffer[0],
+                                 SCpnt->sense_buffer[2]));
 
     /*
       Handle MEDIUM ERRORs that indicate partial success.  Since this is a
@@ -276,20 +321,21 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
 
     if (good_sectors > 0) {
 
-#ifdef DEBUG
-       printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.rq_dev),
-              SCpnt->request.nr_sectors);
-       printk("use_sg is %d\n ",SCpnt->use_sg);
-#endif
+       SCSI_LOG_HLCOMPLETE(1,printk("%s : %ld sectors remain.\n", nbuff,
+              SCpnt->request.nr_sectors));
+       SCSI_LOG_HLCOMPLETE(1,printk("use_sg is %d\n ",SCpnt->use_sg));
+
        if (SCpnt->use_sg) {
            struct scatterlist * sgpnt;
            int i;
            sgpnt = (struct scatterlist *) SCpnt->buffer;
            for(i=0; i<SCpnt->use_sg; i++) {
-#ifdef DEBUG
-               printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address,
-                      sgpnt[i].length);
+
+#if 0
+               SCSI_LOG_HLCOMPLETE(3,printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address,
+                      sgpnt[i].length));
 #endif
+
                if (sgpnt[i].alt_address) {
                    if (SCpnt->request.cmd == READ)
                        memcpy(sgpnt[i].alt_address, sgpnt[i].address,
@@ -302,10 +348,10 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
            scsi_free(SCpnt->buffer, SCpnt->sglist_len);
        } else {
            if (SCpnt->buffer != SCpnt->request.buffer) {
-#ifdef DEBUG
-               printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
-                      SCpnt->bufflen);
-#endif
+               SCSI_LOG_HLCOMPLETE(3,printk("nosg: %p %p %d\n",
+                                             SCpnt->request.buffer, SCpnt->buffer,
+                                             SCpnt->bufflen));
+
                if (SCpnt->request.cmd == READ)
                    memcpy(SCpnt->request.buffer, SCpnt->buffer,
                           SCpnt->bufflen);
@@ -323,10 +369,9 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
 
            if (!SCpnt->request.bh)
            {
-#ifdef DEBUG
-               printk("sd%c : handling page request, no buffer\n",
-                      'a' + MINOR(SCpnt->request.rq_dev));
-#endif
+               SCSI_LOG_HLCOMPLETE(2,printk("%s : handling page request, no buffer\n",
+                      nbuff));
+
                /*
                 * The SCpnt->request.nr_sectors field is always done in
                 * 512 byte sectors, even if this really isn't the case.
@@ -351,20 +396,18 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
        int i;
        sgpnt = (struct scatterlist *) SCpnt->buffer;
        for(i=0; i<SCpnt->use_sg; i++) {
-#ifdef DEBUG
-           printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
-                  SCpnt->bufflen);
-#endif
+           SCSI_LOG_HLCOMPLETE(3,printk("err: %p %p %d\n",
+                                         SCpnt->request.buffer, SCpnt->buffer,
+                                         SCpnt->bufflen));
            if (sgpnt[i].alt_address) {
                scsi_free(sgpnt[i].address, sgpnt[i].length);
            }
        }
        scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
     } else {
-#ifdef DEBUG
-       printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
-              SCpnt->bufflen);
-#endif
+       SCSI_LOG_HLCOMPLETE(2,printk("nosgerr: %p %p %d\n",
+                                     SCpnt->request.buffer, SCpnt->buffer,
+                                     SCpnt->bufflen));
        if (SCpnt->buffer != SCpnt->request.buffer)
            scsi_free(SCpnt->buffer, SCpnt->bufflen);
     }
@@ -484,6 +527,17 @@ static void do_sd_request (void)
        INIT_SCSI_REQUEST;
         SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device;
 
+        /*
+         * If the host for this device is in error recovery mode, don't
+         * do anything at all here.  When the host leaves error recovery
+         * mode, it will automatically restart things and start queueing
+         * commands again.
+         */
+        if( SDev->host->in_recovery )
+          {
+            return;
+          }
+
         /*
          * I am not sure where the best place to do this is.  We need
          * to hook in a place where we are likely to come if in user
@@ -495,7 +549,8 @@ static void do_sd_request (void)
             * We need to relock the door, but we might
             * be in an interrupt handler.  Only do this
             * from user space, since we do not want to
-            * sleep from an interrupt.
+            * sleep from an interrupt.  FIXME(eric) - do this
+             * from the kernel error handling thred.
             */
            if( SDev->removable && !in_interrupt() )
            {
@@ -507,21 +562,21 @@ static void do_sd_request (void)
            SDev->was_reset = 0;
         }
 
-       /* We have to be careful here. allocate_device will get a free pointer,
+       /* We have to be careful here. scsi_allocate_device will get a free pointer,
         * but there is no guarantee that it is queueable.  In normal usage,
         * we want to call this, because other types of devices may have the
         * host all tied up, and we want to make sure that we have at least
         * one request pending for this type of device. We can also come
         * through here while servicing an interrupt, because of the need to
-        * start another command. If we call allocate_device more than once,
+        * start another command. If we call scsi_allocate_device more than once,
         * then the system can wedge if the command is not queueable. The
-        * request_queueable function is safe because it checks to make sure
+        * scsi_request_queueable function is safe because it checks to make sure
         * that the host is able to take another command before it returns
         * a pointer.
         */
 
        if (flag++ == 0)
-           SCpnt = allocate_device(&CURRENT,
+           SCpnt = scsi_allocate_device(&CURRENT,
                           rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
        else SCpnt = NULL;
 
@@ -539,15 +594,19 @@ static void do_sd_request (void)
         * one disk drive.  We want to have the interrupts off when monkeying
         * with the request list, because otherwise the kernel might try to
         * slip in a request in between somewhere.
+         *
+         * FIXME(eric) - this doesn't belong at this level.  The device code in
+         * ll_rw_blk.c should know how to dig down into the device queue to
+         * figure out what it can deal with, and what it can't.  Consider
+         * possibility of pulling entire queue down into scsi layer.
         */
-
        if (!SCpnt && sd_template.nr_dev > 1){
            struct request *req1;
            req1 = NULL;
            cli();
            req = CURRENT;
            while(req){
-               SCpnt = request_queueable(req,
+               SCpnt = scsi_request_queueable(req,
                                    rscsi_disks[DEVICE_NR(req->rq_dev)].device);
                if(SCpnt) break;
                req1 = req;
@@ -573,6 +632,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
 {
     int dev, devm, block, this_count;
     unsigned char cmd[10];
+    char nbuff[6];
     int bounce_size, contiguous;
     int max_sg;
     struct buffer_head * bh, *bhp;
@@ -591,15 +651,16 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
     block = SCpnt->request.sector;
     this_count = 0;
 
-#ifdef DEBUG
-    printk("Doing sd request, dev = %d, block = %d\n", devm, block);
-#endif
+    SCSI_LOG_HLQUEUE(1,printk("Doing sd request, dev = %d, block = %d\n", devm, block));
 
     if (devm >= (sd_template.dev_max << 4) ||
        !rscsi_disks[dev].device ||
+       !rscsi_disks[dev].device->online ||
        block + SCpnt->request.nr_sectors > sd[devm].nr_sects)
     {
+        SCSI_LOG_HLQUEUE(2,printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
        SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+        SCSI_LOG_HLQUEUE(2,printk("Retry with 0x%p\n", SCpnt));
        goto repeat;
     }
 
@@ -616,10 +677,9 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
        goto repeat;
     }
 
-#ifdef DEBUG
-    printk("sd%c : real dev = /dev/sd%c, block = %d\n",
-          'a' + devm, dev, block);
-#endif
+    sd_devname(devm, nbuff);
+    SCSI_LOG_HLQUEUE(2,printk("%s : real dev = /dev/%d, block = %d\n",
+          nbuff, dev, block));
 
     /*
      * If we have a 1K hardware sectorsize, prevent access to single
@@ -702,7 +762,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
        SCpnt->use_sg = 0;
 
     } else if (SCpnt->host->sg_tablesize == 0 ||
-              (need_isa_buffer && dma_free_sectors <= 10)) {
+              (scsi_need_isa_buffer && scsi_dma_free_sectors <= 10)) {
 
        /* Case of host adapter that cannot scatter-gather.  We also
         * come here if we are running low on DMA buffer memory.  We set
@@ -712,8 +772,8 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
         * we have no choice but to panic.
         */
        if (SCpnt->host->sg_tablesize != 0 &&
-           need_isa_buffer &&
-           dma_free_sectors <= 10)
+           scsi_need_isa_buffer &&
+           scsi_dma_free_sectors <= 10)
            printk("Warning: SCSI DMA buffer space running low.  Using non scatter-gather I/O.\n");
 
        this_count = SCpnt->request.current_nr_sectors;
@@ -787,7 +847,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                     * easier to control usage here. In other places we might
                     * have a more pressing need, and we would be screwed if
                     * we ran out */
-                   if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
+                   if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
                        sgpnt[count].address = NULL;
                    } else {
                        sgpnt[count].address =
@@ -832,7 +892,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                        !sgpnt[count].alt_address) continue;
 
                    if(!sgpnt[count].alt_address) {count--; continue; }
-                   if(dma_free_sectors > 10)
+                   if(scsi_dma_free_sectors > 10)
                        tmp = (char *) scsi_malloc(sgpnt[count].length
                                                   + bhp->b_size);
                    else {
@@ -861,7 +921,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
               > SCpnt->host->sg_tablesize){
                bh = SCpnt->request.bh;
                printk("Use sg, count %d %x %d\n",
-                      SCpnt->use_sg, count, dma_free_sectors);
+                      SCpnt->use_sg, count, scsi_dma_free_sectors);
                printk("maxsg = %x, counted = %d this_count = %d\n",
                       max_sg, counted, this_count);
                while(bh){
@@ -903,12 +963,10 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
        }
     }
-#ifdef DEBUG
-    printk("sd%c : %s %d/%d 512 byte blocks.\n",
-          'a' + devm,
-          (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
-          this_count, SCpnt->request.nr_sectors);
-#endif
+    SCSI_LOG_HLQUEUE(2,printk("%s : %s %d/%ld 512 byte blocks.\n",
+                              nbuff,
+                              (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+                              this_count, SCpnt->request.nr_sectors));
 
     cmd[1] = (SCpnt->lun << 5) & 0xe0;
 
@@ -989,6 +1047,20 @@ static int check_scsidisk_media_change(kdev_t full_dev){
 
     if(!rscsi_disks[target].device->removable) return 0;
 
+    /*
+     * If the device is offline, don't send any commands - just pretend as if
+     * the command failed.  If the device ever comes back online, we can deal with
+     * it then.  It is only because of unrecoverable errors that we would ever
+     * take a device offline in the first place.
+     */
+    if( rscsi_disks[target].device->online == FALSE )
+    {
+       rscsi_disks[target].ready = 0;
+       rscsi_disks[target].device->changed = 1;
+       return 1; /* This will force a flush, if called from
+                  * check_disk_change */
+    }
+
     inode.i_rdev = full_dev;  /* This is all we really need here */
     retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
 
@@ -1031,17 +1103,32 @@ static void sd_init_done (Scsi_Cmnd * SCpnt)
 static int sd_init_onedisk(int i)
 {
     unsigned char cmd[10];
+    char          nbuff[6];
     unsigned char *buffer;
     unsigned long spintime;
     int the_result, retries;
     Scsi_Cmnd * SCpnt;
 
+    /*
+     * Get the name of the disk, in case we need to log it somewhere.
+     */
+    sd_devname(i, nbuff);
+
+    /*
+     * If the device is offline, don't try and read capacity or any of the other
+     * nicities.
+     */
+    if( rscsi_disks[i].device->online == FALSE )
+    {
+        return i;
+    }
+
     /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
      * considered a fatal error, and many devices report such an error
      * just after a scsi bus reset.
      */
 
-    SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
+    SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1);
     buffer = (unsigned char *) scsi_malloc(512);
 
     spintime = 0;
@@ -1069,6 +1156,7 @@ static int sd_init_onedisk(int i)
                                 512, sd_init_done,  SD_TIMEOUT,
                                 MAX_RETRIES);
                    down(&sem);
+                    SCpnt->request.sem = NULL;
                }
 
                the_result = SCpnt->result;
@@ -1084,7 +1172,7 @@ static int sd_init_onedisk(int i)
               SCpnt->sense_buffer[2] == NOT_READY) {
                unsigned long time1;
                if(!spintime){
-                   printk( "sd%c: Spinning up disk...", 'a' + i );
+                   printk( "%s: Spinning up disk...", nbuff );
                    cmd[0] = START_STOP;
                    cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
                    cmd[1] |= 1;  /* Return immediately */
@@ -1104,6 +1192,7 @@ static int sd_init_onedisk(int i)
                                     512, sd_init_done,  SD_TIMEOUT,
                                     MAX_RETRIES);
                        down(&sem);
+                        SCpnt->request.sem = NULL;
                    }
 
                    spintime = jiffies;
@@ -1141,6 +1230,7 @@ static int sd_init_onedisk(int i)
                         8, sd_init_done,  SD_TIMEOUT,
                         MAX_RETRIES);
            down(&sem); /* sleep until it is ready */
+            SCpnt->request.sem = NULL;
        }
 
        the_result = SCpnt->result;
@@ -1148,12 +1238,6 @@ static int sd_init_onedisk(int i)
 
     } while(the_result && retries);
 
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-
-    wake_up(&SCpnt->device->device_wait);
-
-    /* Wake up a process waiting for device */
-
     /*
      * The SCSI standard says:
      * "READ CAPACITY is necessary for self configuring software"
@@ -1170,22 +1254,22 @@ static int sd_init_onedisk(int i)
 
     if (the_result)
     {
-       printk ("sd%c : READ CAPACITY failed.\n"
-               "sd%c : status = %x, message = %02x, host = %d, driver = %02x \n",
-               'a' + i, 'a' + i,
+       printk ("%s : READ CAPACITY failed.\n"
+               "%s : status = %x, message = %02x, host = %d, driver = %02x \n",
+               nbuff, nbuff,
                status_byte(the_result),
                msg_byte(the_result),
                host_byte(the_result),
                driver_byte(the_result)
                );
        if (driver_byte(the_result)  & DRIVER_SENSE)
-           printk("sd%c : extended sense code = %1x \n",
-                  'a' + i, SCpnt->sense_buffer[2] & 0xf);
+           printk("%s : extended sense code = %1x \n",
+                  nbuff, SCpnt->sense_buffer[2] & 0xf);
        else
-           printk("sd%c : sense not available. \n", 'a' + i);
+           printk("%s : sense not available. \n", nbuff);
 
-       printk("sd%c : block size assumed to be 512 bytes, disk size 1GB.  \n",
-              'a' + i);
+       printk("%s : block size assumed to be 512 bytes, disk size 1GB.  \n",
+              nbuff);
        rscsi_disks[i].capacity = 0x1fffff;
        rscsi_disks[i].sector_size = 512;
 
@@ -1213,7 +1297,7 @@ static int sd_init_onedisk(int i)
 
        if (rscsi_disks[i].sector_size == 0) {
          rscsi_disks[i].sector_size = 512;
-         printk("sd%c : sector size 0 reported, assuming 512.\n", 'a' + i);
+         printk("%s : sector size 0 reported, assuming 512.\n", nbuff);
        }
 
 
@@ -1222,8 +1306,8 @@ static int sd_init_onedisk(int i)
            rscsi_disks[i].sector_size != 2048 &&
            rscsi_disks[i].sector_size != 256)
        {
-           printk ("sd%c : unsupported sector size %d.\n",
-                   'a' + i, rscsi_disks[i].sector_size);
+           printk ("%s : unsupported sector size %d.\n",
+                   nbuff, rscsi_disks[i].sector_size);
            if(rscsi_disks[i].device->removable){
                rscsi_disks[i].capacity = 0;
            } else {
@@ -1231,6 +1315,12 @@ static int sd_init_onedisk(int i)
                rscsi_disks[i].device = NULL;
                sd_template.nr_dev--;
                sd_gendisk.nr_real--;
+
+                /* Wake up a process waiting for device */
+                wake_up(&SCpnt->device->device_wait);
+                scsi_release_command(SCpnt);
+                SCpnt = NULL;
+                
                return i;
            }
        }
@@ -1268,9 +1358,9 @@ static int sd_init_onedisk(int i)
         m = (mb + 50) / 100;
         sz_quot = m / 10;
         sz_rem = m - (10 * sz_quot);
-       printk ("SCSI device sd%c: hdwr sector= %d bytes."
+       printk ("SCSI device %s: hdwr sector= %d bytes."
                " Sectors= %d [%d MB] [%d.%1d GB]\n",
-               i+'a', hard_sector, rscsi_disks[i].capacity,
+               nbuff, hard_sector, rscsi_disks[i].capacity,
                 mb, sz_quot, sz_rem);
     }
        if(rscsi_disks[i].sector_size == 2048)
@@ -1315,23 +1405,27 @@ static int sd_init_onedisk(int i)
                         512, sd_init_done,  SD_TIMEOUT,
                         MAX_RETRIES);
            down(&sem);
+            SCpnt->request.sem = NULL;
        }
 
        the_result = SCpnt->result;
-       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-       wake_up(&SCpnt->device->device_wait);
 
        if ( the_result ) {
-           printk ("sd%c: test WP failed, assume Write Protected\n",i+'a');
+           printk ("%s: test WP failed, assume Write Protected\n",nbuff);
            rscsi_disks[i].write_prot = 1;
        } else {
            rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0);
-           printk ("sd%c: Write Protect is %s\n",i+'a',
+           printk ("%s: Write Protect is %s\n",nbuff,
                    rscsi_disks[i].write_prot ? "on" : "off");
        }
 
     }  /* check for write protect */
 
+    /* Wake up a process waiting for device */
+    wake_up(&SCpnt->device->device_wait);
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
+
     rscsi_disks[i].ten = 1;
     rscsi_disks[i].remap = 1;
     scsi_free(buffer, 512);
@@ -1435,11 +1529,13 @@ static void sd_finish()
 }
 
 static int sd_detect(Scsi_Device * SDp){
+    char nbuff[6];
     if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
 
-    printk("Detected scsi %sdisk sd%c at scsi%d, channel %d, id %d, lun %d\n",
+    sd_devname(sd_template.dev_noticed++, nbuff);
+    printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
            SDp->removable ? "removable " : "",
-          'a'+ (sd_template.dev_noticed++),
+          nbuff,
           SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
 
     return 1;
@@ -1509,7 +1605,7 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){
     for (i=max_p - 1; i >=0 ; i--) {
        int minor = start+i;
        kdev_t devi = MKDEV(MAJOR_NR, minor);
-       struct super_block *sb = get_super(devi);
+        struct super_block *sb = get_super(devi);
        sync_dev(devi);
        if (sb) invalidate_inodes(sb);
        invalidate_buffers(devi);
@@ -1562,7 +1658,7 @@ static void sd_detach(Scsi_Device * SDp)
            for (i=max_p - 1; i >=0 ; i--) {
                int minor = start+i;
                kdev_t devi = MKDEV(MAJOR_NR, minor);
-               struct super_block *sb = get_super(devi);
+                struct super_block *sb = get_super(devi);
                sync_dev(devi);
                if (sb) invalidate_inodes(sb);
                invalidate_buffers(devi);
index 070e6423ea38b8652834a19af7da821aec9383e7..58a5b005ca2117e3e56eaa65795ea09b88666103 100644 (file)
@@ -25,9 +25,22 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
     kdev_t dev = inode->i_rdev;
     int error;
     struct Scsi_Host * host;
+    Scsi_Device * SDev;
     int diskinfo[4];
     struct hd_geometry *loc = (struct hd_geometry *) arg;
     
+    SDev = rscsi_disks[MINOR(dev) >> 4].device;
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(SDev) )
+      {
+        return -ENODEV;
+      }
+
     switch (cmd) {
     case HDIO_GETGEO:   /* Return BIOS disk parameters */
        if (!loc)  return -EINVAL;
index f339ea6128a57c91a453d37ac48a35339d443cf7..2d07fd9a7e3b5752f06af4e66c694fab4358140f 100644 (file)
@@ -27,13 +27,18 @@ int seagate_st0x_reset(Scsi_Cmnd *, unsigned int);
 #include <linux/kdev_t.h>
 int seagate_st0x_biosparam(Disk *, kdev_t, int*);
 
-#define SEAGATE_ST0X  {  NULL, NULL, NULL, NULL, \
-                        NULL, seagate_st0x_detect,     \
-                        NULL,                                          \
-                        seagate_st0x_info, seagate_st0x_command,       \
-                        seagate_st0x_queue_command, seagate_st0x_abort, \
-                        seagate_st0x_reset, NULL, seagate_st0x_biosparam, \
-                        1, 7, SG_ALL, 1, 0, 0, DISABLE_CLUSTERING}
+#define SEAGATE_ST0X  {  detect:         seagate_st0x_detect,          \
+                        info:           seagate_st0x_info,             \
+                        command:        seagate_st0x_command,          \
+                        queuecommand:   seagate_st0x_queue_command,    \
+                        abort:          seagate_st0x_abort,            \
+                        reset:          seagate_st0x_reset,            \
+                        bios_param:     seagate_st0x_biosparam,        \
+                        can_queue:      1,                             \
+                        this_id:        7,                             \
+                        sg_tablesize:   SG_ALL,                        \
+                        cmd_per_lun:    1,                             \
+                        use_clustering: DISABLE_CLUSTERING}
 #endif /* ASM */
 
 #endif /* _SEAGATE_H */
index a94fb569c6aa45516287ba47568d14c726be599a..8c0d9f23dd876d40500f1715508b32fc51669d78 100644 (file)
@@ -67,10 +67,22 @@ static void sg_free(char *buff,int size);
 static int sg_ioctl(struct inode * inode,struct file * file,
                    unsigned int cmd_in, unsigned long arg)
 {
-    int result;
-    int dev = MINOR(inode->i_rdev);
+    int                         dev = MINOR(inode->i_rdev);
+    int                         result;
+
     if ((dev<0) || (dev>=sg_template.dev_max))
        return -ENXIO;
+
+    /*
+     * If we are in the middle of error recovery, then don't allow any
+     * access to this device.  Also, error recovery *may* have taken the
+     * device offline, in which case all further access is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+      {
+        return -ENXIO;
+      }
+
     switch(cmd_in)
     {
     case SG_SET_TIMEOUT:
@@ -92,6 +104,12 @@ static int sg_open(struct inode * inode, struct file * filp)
     int flags=filp->f_flags;
     if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
        return -ENXIO;
+
+    if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+      {
+        return -ENXIO;
+      }
+
     if (O_RDWR!=(flags & O_ACCMODE))
        return -EACCES;
 
@@ -209,6 +227,17 @@ static ssize_t sg_read(struct file *filp, char *buf,
     unsigned long flags;
     struct scsi_generic *device=&scsi_generics[dev];
 
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+      {
+        return -ENXIO;
+      }
+
     if (ppos != &filp->f_pos) {
       /* FIXME: Hmm.  Seek to the right place, or fail?  */
     }
@@ -278,7 +307,8 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
     if (!device->pending)
     {
        printk("unexpected done for sg %d\n",dev);
-       SCpnt->request.rq_status = RQ_INACTIVE;
+        scsi_release_command(SCpnt);
+        SCpnt = NULL;
        return;
     }
 
@@ -325,7 +355,8 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
      * result.
      */
     device->complete=1;
-    SCpnt->request.rq_status = RQ_INACTIVE;
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
     wake_up(&scsi_generics[dev].read_wait);
 }
 
@@ -342,6 +373,17 @@ static ssize_t sg_write(struct file *filp, const char *buf,
     unsigned char        opcode;
     Scsi_Cmnd          * SCpnt;
 
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+      {
+        return -ENXIO;
+      }
+
     if (ppos != &filp->f_pos) {
       /* FIXME: Hmm.  Seek to the right place, or fail?  */
     }
@@ -444,7 +486,7 @@ static ssize_t sg_write(struct file *filp, const char *buf,
      * Grab a device pointer for the device we want to talk to.  If we
      * don't want to block, just return with the appropriate message.
      */
-    if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
+    if (!(SCpnt=scsi_allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
     {
        device->pending=0;
        wake_up(&device->write_wait);
index 2504b30a59efcf880bd29e0b6b2bf5d74c631e5c..153e3b73877b8177b8465f843d39be51f73200db 100644 (file)
@@ -385,6 +385,21 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose)
 {
     check_disk_change(cdi->dev);
 
+    if(   MINOR(cdi->dev) >= sr_template.dev_max 
+       || !scsi_CDs[MINOR(cdi->dev)].device)
+      {
+       return -ENXIO;   /* No such device */
+      }
+
+    /*
+     * If the device is in error recovery, wait until it is done.
+     * If the device is offline, then disallow any access to it.
+     */
+    if( !scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device) )
+      {
+        return -ENXIO;
+      }
+
     scsi_CDs[MINOR(cdi->dev)].device->access_count++;
     if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
        __MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
@@ -428,6 +443,17 @@ static void do_sr_request (void)
 
        SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device;
 
+        /*
+         * If the host for this device is in error recovery mode, don't
+         * do anything at all here.  When the host leaves error recovery
+         * mode, it will automatically restart things and start queueing
+         * commands again.
+         */
+        if( SDev->host->in_recovery )
+          {
+            return;
+          }
+
        /*
         * I am not sure where the best place to do this is.  We need
         * to hook in a place where we are likely to come if in user
@@ -460,7 +486,7 @@ static void do_sr_request (void)
        }
 
        if (flag++ == 0)
-           SCpnt = allocate_device(&CURRENT,
+           SCpnt = scsi_allocate_device(&CURRENT,
                                    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
        else SCpnt = NULL;
        restore_flags(flags);
@@ -479,7 +505,7 @@ static void do_sr_request (void)
            cli();
            req = CURRENT;
            while(req){
-               SCpnt = request_queueable(req,
+               SCpnt = scsi_request_queueable(req,
                                          scsi_CDs[DEVICE_NR(req->rq_dev)].device);
                if(SCpnt) break;
                req1 = req;
@@ -537,6 +563,13 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
                goto repeat;
        }
 
+       if( !scsi_CDs[dev].device->online )
+          {
+            SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+            tries = 2;
+            goto repeat;
+          }
+
        if (scsi_CDs[dev].device->changed) {
        /*
         * quietly refuse to do anything to a changed disc
@@ -583,8 +616,8 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
        SCpnt->use_sg = 0;
 
        if (SCpnt->host->sg_tablesize > 0 &&
-           (!need_isa_buffer ||
-        dma_free_sectors >= 10)) {
+           (!scsi_need_isa_buffer ||
+        scsi_dma_free_sectors >= 10)) {
        struct buffer_head * bh;
        struct scatterlist * sgpnt;
        int count, this_count_max;
@@ -655,7 +688,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
                    /* We try to avoid exhausting the DMA pool, since it is easier
                     * to control usage here.  In other places we might have a more
                     * pressing need, and we would be screwed if we ran out */
-                   if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
+                   if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
                        sgpnt[count].address = NULL;
                    } else {
                        sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
@@ -849,7 +882,7 @@ void get_sectorsize(int i){
     Scsi_Cmnd * SCpnt;
 
     buffer = (unsigned char *) scsi_malloc(512);
-    SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
+    SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1);
 
     retries = 3;
     do {
@@ -877,9 +910,10 @@ void get_sectorsize(int i){
 
     } while(the_result && retries);
 
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
 
     wake_up(&SCpnt->device->device_wait);
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
 
     if (the_result) {
        scsi_CDs[i].capacity = 0x1fffff;
index 265c7d04fa9b9d6b26692521259a850a13993818..344c1665456b98942f1c074b28cef48665c1a878 100644 (file)
@@ -53,7 +53,7 @@ int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned bufl
     Scsi_Cmnd * SCpnt;
     int result, err = 0, retries = 0;
 
-    SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
+    SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1);
 
 retry:
     {
@@ -63,6 +63,7 @@ retry:
                    (void *) sr_cmd, buffer, buflength, sr_ioctl_done, 
                    IOCTL_TIMEOUT, IOCTL_RETRIES);
        down(&sem);
+        SCpnt->request.sem = NULL;
     }
     
     result = SCpnt->result;
@@ -125,10 +126,10 @@ retry:
        };
     
     result = SCpnt->result;
-    SCpnt->request.rq_status = RQ_INACTIVE; /* Deallocate */
-    /* Wake up a process waiting for device */
+    /* Wake up a process waiting for device*/
     wake_up(&SCpnt->device->device_wait);
-    
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
     return err;
 }
 
@@ -186,7 +187,7 @@ int sr_disk_status(struct cdrom_device_info *cdi)
         /* look for data tracks */
         if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
                 return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
-        
+
         for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
                 toc_e.cdte_track  = i;
                 toc_e.cdte_format = CDROM_LBA;
@@ -278,10 +279,23 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed)
 int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
 {
     u_char  sr_cmd[10];    
+    Scsi_Device * SDev;
     int result, target;
     
     target = MINOR(cdi->dev);
     
+    SDev = scsi_CDs[target].device;
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(SDev) )
+      {
+        return -ENODEV;
+      }
+
     switch (cmd) 
     {
        /* Sun-compatible */
@@ -704,9 +718,22 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi,
                  unsigned int cmd, unsigned long arg)
 {
     int target, err;
+    Scsi_Device * SDev;
     
     target = MINOR(cdi->dev);
     
+    SDev = scsi_CDs[target].device;
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(SDev) )
+      {
+        return -ENODEV;
+      }
+
     switch (cmd) {
     case CDROMREADMODE1:
     case CDROMREADMODE2:
index 1d7ed45b48a57fd48613a1a0d6478ef09ed8d02b..c61fa1c30289689ad9242cbdce3381ad0257ab97 100644 (file)
@@ -230,7 +230,6 @@ st_sleep_done (Scsi_Cmnd * SCpnt)
     }
     else
       (STp->buffer)->last_result = SCpnt->result;
-
     SCpnt->request.rq_status = RQ_SCSI_DONE;
     (STp->buffer)->last_SCpnt = SCpnt;
 
@@ -252,7 +251,7 @@ st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
           int timeout, int retries)
 {
   if (SCpnt == NULL)
-    if ((SCpnt = allocate_device(NULL, STp->device, 1)) == NULL) {
+    if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
       printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
       return NULL;
     }
@@ -293,7 +292,7 @@ write_behind_check(Scsi_Tape *STp)
   down(&(STp->sem));
 
   (STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt);
-  ((STp->buffer)->last_SCpnt)->request.rq_status = RQ_INACTIVE;
+  scsi_release_command((STp->buffer)->last_SCpnt);
 
   if (STbuffer->writing < STbuffer->buffer_bytes)
     memcpy(STbuffer->b_data,
@@ -340,7 +339,9 @@ cross_eof(Scsi_Tape *STp, int forward)
   if (!SCpnt)
     return (-EBUSY);
 
-  SCpnt->request.rq_status = RQ_INACTIVE;
+  scsi_release_command(SCpnt);
+  SCpnt = NULL;
+
   if ((STp->buffer)->last_result != 0)
     printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
           TAPE_NR(STp->devt), forward ? "forward" : "backward");
@@ -421,7 +422,8 @@ flush_write_buffer(Scsi_Tape *STp)
       STp->dirty = 0;
       (STp->buffer)->buffer_bytes = 0;
     }
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
   }
   return result;
 }
@@ -543,6 +545,12 @@ scsi_tape_open(struct inode * inode, struct file * filp)
 
     if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
       return (-ENXIO);
+
+    if( !scsi_block_when_processing_errors(scsi_tapes[dev].device) )
+      {
+        return -ENXIO;
+      }
+
     STp = &(scsi_tapes[dev]);
     if (STp->in_use) {
 #if DEBUG
@@ -644,7 +652,8 @@ scsi_tape_open(struct inode * inode, struct file * filp)
        STp->ready = ST_NO_TAPE;
       } else
        STp->ready = ST_NOT_READY;
-      SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+      scsi_release_command(SCpnt);
+      SCpnt = NULL;
       STp->density = 0;        /* Clear the erroneous "residue" */
       STp->write_prot = 0;
       STp->block_size = 0;
@@ -736,7 +745,8 @@ scsi_tape_open(struct inode * inode, struct file * filp)
       }
       STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
     }
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
 
     if (STp->block_size > 0)
       (STp->buffer)->buffer_blocks = st_buffer_size / STp->block_size;
@@ -874,13 +884,15 @@ scsi_tape_close(struct inode * inode, struct file * filp)
               SCpnt->sense_buffer[5] |
               SCpnt->sense_buffer[6]) == 0))) {
            /* Filter out successful write at EOM */
-           SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+           scsi_release_command(SCpnt);
+           SCpnt = NULL;
            printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
            if (result == 0)
                result = (-EIO);
        }
        else {
-         SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+         scsi_release_command(SCpnt);
+         SCpnt = NULL;
          if (STps->drv_file >= 0)
              STps->drv_file++ ;
          STps->drv_block = 0;
@@ -965,6 +977,19 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
     ST_partstat * STps;
     int dev = TAPE_NR(inode->i_rdev);
 
+    STp = &(scsi_tapes[dev]);
+
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(STp->device) )
+      {
+        return -ENXIO;
+      }
+    
     if (ppos != &filp->f_pos) {
       /* "A request was outside the capabilities of the device." */
       return -ENXIO;
@@ -1098,7 +1123,10 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
                         (STp->buffer)->buffer_bytes, b_point, do_count);
       if (i) {
          if (SCpnt != NULL)
-             SCpnt->request.rq_status = RQ_INACTIVE;
+           {
+             scsi_release_command(SCpnt);
+             SCpnt = NULL;
+           }
          return (-EFAULT);
       }
 
@@ -1167,7 +1195,8 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
          retval = (-EIO);
        }
 
-       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+       scsi_release_command(SCpnt);
+       SCpnt = NULL;
        (STp->buffer)->buffer_bytes = 0;
        STp->dirty = 0;
        if (count < total)
@@ -1193,7 +1222,10 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
                         (STp->buffer)->buffer_bytes, b_point, count);
       if (i) {
          if (SCpnt != NULL)
-             SCpnt->request.rq_status = RQ_INACTIVE;
+           {
+             scsi_release_command(SCpnt);
+             SCpnt = NULL;
+           }
          return (-EFAULT);
       }
       filp->f_pos += count;
@@ -1202,7 +1234,8 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
     }
 
     if (doing_write && (STp->buffer)->last_result_fatal != 0) {
-      SCpnt->request.rq_status = RQ_INACTIVE;
+      scsi_release_command(SCpnt);
+      SCpnt = NULL;
       return (STp->buffer)->last_result_fatal;
     }
 
@@ -1212,7 +1245,7 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
         STp->block_size == 0) ) {
       /* Schedule an asynchronous write */
       if (!SCpnt) {
-       SCpnt = allocate_device(NULL, STp->device, 1);
+       SCpnt = scsi_allocate_device(NULL, STp->device, 1);
        if (!SCpnt)
          return (-EBUSY);
       }
@@ -1245,8 +1278,10 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
                   st_sleep_done, STp->timeout, MAX_WRITE_RETRIES);
     }
     else if (SCpnt != NULL)
-      SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-
+      {
+       scsi_release_command(SCpnt);
+       SCpnt = NULL;
+      }
     STps->at_sm &= (total == 0);
     if (total > 0)
        STps->eof = ST_NOEOF;
@@ -1346,7 +1381,7 @@ read_tape(struct inode *inode, long count, Scsi_Cmnd **aSCpnt)
                        (STp->buffer)->buffer_bytes = bytes - transfer;
                    }
                    else {
-                       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+                       scsi_release_command(SCpnt);
                        SCpnt = *aSCpnt = NULL;
                        if (transfer == blks) {  /* We did not get anything, error */
                            printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
@@ -1457,6 +1492,19 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
     ST_partstat * STps;
     int dev = TAPE_NR(inode->i_rdev);
 
+    STp = &(scsi_tapes[dev]);
+
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(STp->device) )
+      {
+        return -ENXIO;
+      }
+    
     if (ppos != &filp->f_pos) {
       /* "A request was outside the capabilities of the device." */
       return -ENXIO;
@@ -1537,7 +1585,9 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
          special = read_tape(inode, count - total, &SCpnt);
          if (special < 0) { /* No need to continue read */
              if (SCpnt != NULL)
-                 SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+               {
+                 scsi_release_command(SCpnt);
+               }
              return special;
          }
       }
@@ -1555,7 +1605,10 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
                         (STp->buffer)->read_pointer, transfer);
        if (i) {
            if (SCpnt != NULL)
-               SCpnt->request.rq_status = RQ_INACTIVE;
+             {
+               scsi_release_command(SCpnt);
+               SCpnt = NULL;
+             }
            return (-EFAULT);
        }
        filp->f_pos += transfer;
@@ -1571,7 +1624,10 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
     } /* for (total = 0, special = 0; total < count && !special; ) */
 
     if (SCpnt != NULL)
-      SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+      {
+       scsi_release_command(SCpnt);
+       SCpnt = NULL;
+      }
 
     /* Change the eof state if no data from tape or buffer */
     if (total == 0) {
@@ -1815,7 +1871,8 @@ st_compression(Scsi_Tape * STp, int state)
     if (debugging)
       printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev);
 #endif
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
     return (-EIO);
   }
 #if DEBUG
@@ -1830,7 +1887,8 @@ st_compression(Scsi_Tape * STp, int state)
     if (debugging)
       printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev);
 #endif
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
     return (-EIO);
   }
 
@@ -1855,7 +1913,8 @@ st_compression(Scsi_Tape * STp, int state)
     if (debugging)
       printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev);
 #endif
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
     return (-EIO);
   }
 
@@ -1865,7 +1924,8 @@ st_compression(Scsi_Tape * STp, int state)
           dev, state);
 #endif
 
-  SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+  scsi_release_command(SCpnt);
+  SCpnt = NULL;
   STp->compression_changed = TRUE;
   return 0;
 }
@@ -2238,7 +2298,8 @@ st_int_ioctl(struct inode * inode,
 
    ioctl_result = (STp->buffer)->last_result_fatal;
 
-   SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+   scsi_release_command(SCpnt);
+   SCpnt = NULL;
 
    if (!ioctl_result) {  /* SCSI command successful */
      STps->drv_block = blkno;
@@ -2441,7 +2502,8 @@ get_location(struct inode * inode, unsigned int *block, int *partition,
 #endif
 
     }
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
 
     return result;
 }
@@ -2556,6 +2618,9 @@ set_location(struct inode * inode, unsigned int block, int partition,
       result = 0;
     }
 
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
+
     return result;
 }
 
@@ -2622,7 +2687,8 @@ nbr_partitions(struct inode * inode)
     SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES);
     if (SCpnt == NULL)
       return (-EBUSY);
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
 
     if ((STp->buffer)->last_result_fatal != 0) {
 #if DEBUG
@@ -2696,7 +2762,8 @@ partition_tape(struct inode * inode, int size)
     SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, MAX_READY_RETRIES);
     if (SCpnt == NULL)
       return (-EBUSY);
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
 
     if ((STp->buffer)->last_result_fatal != 0) {
       printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
@@ -2734,6 +2801,17 @@ st_ioctl(struct inode * inode,struct file * file,
    STm = &(STp->modes[STp->current_mode]);
    STps = &(STp->ps[STp->partition]);
 
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(STp->device) )
+      {
+        return -ENXIO;
+      }
+
    cmd_type = _IOC_TYPE(cmd_in);
    cmd_nr   = _IOC_NR(cmd_in);
 
index 43a898200e9bfc000c234da154fb28599df015d3..8f4f27f85e03457ecf95ef963922ebb085ba4217 100644 (file)
@@ -119,13 +119,18 @@ int t128_proc_info (char *buffer, char **start, off_t offset,
 
 #if defined(HOSTS_C) || defined(MODULE)
 
-#define TRANTOR_T128 {NULL, NULL, NULL, NULL, \
-       "Trantor T128/T128F/T228", t128_detect, NULL,  \
-       NULL,                                                   \
-       NULL, t128_queue_command, t128_abort, t128_reset, NULL,         \
-       t128_biosparam,                                                 \
-       /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,                  \
-       /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+#define TRANTOR_T128 {                                 \
+       name:           "Trantor T128/T128F/T228",      \
+       detect:         t128_detect,                    \
+       queuecommand:   t128_queue_command,             \
+       abort:          t128_abort,                     \
+       reset:          t128_reset,                     \
+       bios_param:     t128_biosparam,                 \
+       can_queue:      CAN_QUEUE,                      \
+        this_id:        7,                             \
+       sg_tablesize:   SG_ALL,                         \
+       cmd_per_lun:    CMD_PER_LUN,                    \
+       use_clustering: DISABLE_CLUSTERING}
 
 #endif
 
index 004936393518b9c647be987a4aafa4a6ae8b33b1..244bc811d3b1be3726afbeb325ea9ac64738d9fb 100644 (file)
@@ -13,27 +13,16 @@ int u14_34f_biosparam(Disk *, kdev_t, int *);
 
 #define U14_34F_VERSION "3.11.00"
 
-#define ULTRASTOR_14_34F {                                            \
-               NULL, /* Ptr for modules */                           \
-               NULL, /* usage count for modules */                   \
-               NULL,                                                 \
-               NULL,                                                 \
-               "UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
-               u14_34f_detect,                                       \
-               u14_34f_release,                                      \
-               NULL,                                                 \
-               NULL,                                                 \
-               u14_34f_queuecommand,                                 \
-               u14_34f_abort,                                        \
-               u14_34f_reset,                                        \
-               NULL,                                                 \
-               u14_34f_biosparam,                                    \
-               0,   /* can_queue, reset by detect */                 \
-               7,   /* this_id, reset by detect */                   \
-               0,   /* sg_tablesize, reset by detect */              \
-               0,   /* cmd_per_lun, reset by detect */               \
-               0,   /* number of boards present */                   \
-               1,   /* unchecked isa dma, reset by detect */         \
-               ENABLE_CLUSTERING                                     \
+#define ULTRASTOR_14_34F {                                                        \
+               name:              "UltraStor 14F/34F rev. " U14_34F_VERSION " ",  \
+               detect:            u14_34f_detect,                                 \
+               release:           u14_34f_release,                                \
+               queuecommand:      u14_34f_queuecommand,                           \
+               abort:             u14_34f_abort,                                  \
+               reset:             u14_34f_reset,                                  \
+               bios_param:        u14_34f_biosparam,                              \
+               this_id:           7,   /* this_id, reset by detect */             \
+               unchecked_isa_dma: 1,   /* unchecked isa dma, reset by detect */   \
+               use_clustering:    ENABLE_CLUSTERING                               \
                }
 #endif
index 7a40acc5820f468c0fa78b901137bd2f6e811305..ffe57ec18b802f3111cff9d77e0d5f3dddd5e391 100644 (file)
@@ -31,26 +31,19 @@ int ultrastor_biosparam(Disk *, kdev_t, int *);
 #define ULTRASTOR_24F_PORT 0xC80
 
 
-#define ULTRASTOR_14F { NULL, NULL, /* Ptr for modules*/ \
-                         NULL,                         \
-                         NULL,                         \
-                         "UltraStor 14F/24F/34F",      \
-                         ultrastor_detect,             \
-                         NULL, /* Release */           \
-                         ultrastor_info,               \
-                         0,                            \
-                         ultrastor_queuecommand,       \
-                         ultrastor_abort,              \
-                         ultrastor_reset,              \
-                         0,                            \
-                         ultrastor_biosparam,          \
-                         ULTRASTOR_MAX_CMDS,           \
-                         0,                            \
-                         ULTRASTOR_14F_MAX_SG,         \
-                         ULTRASTOR_MAX_CMDS_PER_LUN,   \
-                         0,                            \
-                         1,                            \
-                         ENABLE_CLUSTERING }
+#define ULTRASTOR_14F {   name:              "UltraStor 14F/24F/34F",  \
+                         detect:            ultrastor_detect,          \
+                         info:              ultrastor_info,            \
+                         queuecommand:      ultrastor_queuecommand,    \
+                         abort:             ultrastor_abort,           \
+                         reset:             ultrastor_reset,           \
+                         bios_param:        ultrastor_biosparam,       \
+                         can_queue:         ULTRASTOR_MAX_CMDS,        \
+                         this_id:           0,                         \
+                         sg_tablesize:      ULTRASTOR_14F_MAX_SG,      \
+                         cmd_per_lun:       ULTRASTOR_MAX_CMDS_PER_LUN,\
+                         unchecked_isa_dma: 1,                         \
+                         use_clustering:    ENABLE_CLUSTERING }
 
 
 #ifdef ULTRASTOR_PRIVATE
index 705f9295833ab026c5b65ab35b8d1c5863d0033b..8835e5f508d6cb43fdab6861aacd6d0657c5aece 100644 (file)
@@ -38,18 +38,18 @@ int wd7000_biosparam(Disk *, kdev_t, int *);
 #define WD7000_Q    16
 #define WD7000_SG   16
 
-#define WD7000 { NULL, NULL,            \
-       NULL,                           \
-       NULL,                           \
-       "Western Digital WD-7000",      \
-       wd7000_detect,                  \
-       NULL,                           \
-       NULL,                           \
-       wd7000_command,                 \
-       wd7000_queuecommand,            \
-       wd7000_abort,                   \
-       wd7000_reset,                   \
-       NULL,                           \
-       wd7000_biosparam,               \
-       WD7000_Q, 7, WD7000_SG, 1, 0, 1, ENABLE_CLUSTERING}
+#define WD7000 {                                          \
+       name:              "Western Digital WD-7000",      \
+       detect:            wd7000_detect,                  \
+       command:           wd7000_command,                 \
+       queuecommand:      wd7000_queuecommand,            \
+       abort:             wd7000_abort,                   \
+       reset:             wd7000_reset,                   \
+       bios_param:        wd7000_biosparam,               \
+       can_queue:         WD7000_Q,                       \
+       this_id:           7,                              \
+       sg_tablesize:      WD7000_SG,                      \
+       cmd_per_lun:       1,                              \
+       unchecked_isa_dma: 1,                              \
+       use_clustering:    ENABLE_CLUSTERING}
 #endif
index e7880fcc211056997a6473ef2424f44144d4cd99..46256256cd7b6e2987312c27bd2558cfa7ec54e0 100644 (file)
@@ -97,3 +97,6 @@ ifdef CONFIG_SOFTOSS
        OBJS := $(OBJS)  softoss.o softoss_rs.o
 endif
 
+ifdef CONFIG_VMIDI
+       OBJS := $(OBJS)  v_midi.o
+endif
diff --git a/drivers/sound/.objects.orig b/drivers/sound/.objects.orig
new file mode 100644 (file)
index 0000000..e7880fc
--- /dev/null
@@ -0,0 +1,99 @@
+OBJS=
+
+ifdef CONFIG_AD1848
+       OBJS := $(OBJS)  ad1848.o
+endif
+
+ifdef CONFIG_YM3812
+       OBJS := $(OBJS)  adlib_card.o
+endif
+
+ifdef CONFIG_AUDIO
+       OBJS := $(OBJS)  audio.o
+endif
+
+ifdef CONFIG_CS4232
+       OBJS := $(OBJS)  cs4232.o
+endif
+
+ifdef CONFIG_AUDIO
+       OBJS := $(OBJS)  dmabuf.o
+endif
+
+ifdef CONFIG_GUSHW
+       OBJS := $(OBJS)  gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
+endif
+
+ifdef CONFIG_MAD16
+       OBJS := $(OBJS)  mad16.o
+endif
+
+ifdef CONFIG_MAUI
+       OBJS := $(OBJS)  maui.o
+endif
+
+ifdef CONFIG_MIDI
+       OBJS := $(OBJS)  midi_synth.o midibuf.o
+endif
+
+ifdef CONFIG_MPU401
+       OBJS := $(OBJS)  mpu401.o
+else
+  ifdef CONFIG_MPU_EMU
+       OBJS := $(OBJS)  mpu401.o
+  endif
+endif
+
+ifdef CONFIG_YM3812
+       OBJS := $(OBJS)  opl3.o
+endif
+
+ifdef CONFIG_PAS
+       OBJS := $(OBJS)  pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
+endif
+
+ifdef CONFIG_PSS
+       OBJS := $(OBJS)  pss.o
+endif
+
+ifdef CONFIG_SBDSP
+       OBJS := $(OBJS) sb_card.o sb_common.o sb_audio.o sb_mixer.o sb_midi.o
+endif
+
+ifdef CONFIG_SEQUENCER
+       OBJS := $(OBJS)  sequencer.o
+endif
+
+
+ifdef CONFIG_SEQUENCER
+       OBJS := $(OBJS)  sound_timer.o
+endif
+
+ifdef CONFIG_SSCAPEHW
+       OBJS := $(OBJS)  sscape.o
+endif
+
+ifdef CONFIG_TRIX
+       OBJS := $(OBJS)  trix.o
+endif
+
+ifdef CONFIG_SEQUENCER
+       OBJS := $(OBJS)  sys_timer.o
+endif
+
+ifdef CONFIG_UART6850
+       OBJS := $(OBJS)  uart6850.o
+endif
+
+ifdef CONFIG_UART401
+       OBJS := $(OBJS)  uart401.o
+endif
+
+ifdef CONFIG_OPL3SA1
+       OBJS := $(OBJS)  opl3sa.o
+endif
+
+ifdef CONFIG_SOFTOSS
+       OBJS := $(OBJS)  softoss.o softoss_rs.o
+endif
+
index 80b8bd37ed9322a7d0a4e87c553ff84bcfe7caba..9b0de3730187b446bfaff7f4be12b4897673af68 100644 (file)
@@ -17,12 +17,13 @@ dep_tristate 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' C
 dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_OPL3SA1 $CONFIG_SOUND
 dep_tristate 'SoftOSS software wave table engine' CONFIG_SOFTOSS $CONFIG_SOUND
 dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 $CONFIG_SOUND
+dep_tristate 'Loopback MIDI device support' CONFIG_VMIDI $CONFIG_VMIDI
 
-if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
+if [ "$CONFIG_AEDSP16" = "y" ]; then
     hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
 fi
 
-if [ "$CONFIG_SB" = "y" -o "$CONFIG_SB" = "m" ]; then
+if [ "$CONFIG_SB" = "y" ]; then
     hex 'I/O base for SB Check from manual of the card' SBC_BASE 220
     int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7
     int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1
@@ -33,12 +34,12 @@ if [ "$CONFIG_SB" = "y" -o "$CONFIG_SB" = "m" ]; then
     int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1
 fi
 
-if [ "$CONFIG_PAS" = "y" -o "$CONFIG_PAS" = "m" ]; then
+if [ "$CONFIG_PAS" = "y" ]; then
     int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10
     int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3
 fi
 
-if [ "$CONFIG_GUS" = "y" -o "$CONFIG_GUS" = "m" ]; then
+if [ "$CONFIG_GUS" = "y" ]; then
     hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220
     int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15
     int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6
@@ -51,23 +52,23 @@ if [ "$CONFIG_GUS16" = "y" ]; then
     int 'GUS DMA 0, 1 or 3' GUS16_DMA 3
 fi
 
-if [ "$CONFIG_MPU401" = "y" -o "$CONFIG_MPU401" = "m" ]; then
+if [ "$CONFIG_MPU401" = "y" ]; then
     hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330
     int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9
 fi
 
-if [ "$CONFIG_MAUI" = "y" -o "$CONFIG_MAUI" = "M" ]; then
+if [ "$CONFIG_MAUI" = "y" ]; then
     comment 'ERROR! You have to use old sound configuration method with Maui.'
     hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330
     int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9
 fi
 
-if [ "$CONFIG_UART6850" = "y" -o "$CONFIG_UART6850" = "m" ]; then
+if [ "$CONFIG_UART6850" = "y" ]; then
     hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
     int 'UART6850 IRQ (Unknown)' U6850_IRQ -1
 fi
 
-if [ "$CONFIG_PSS" = "y" -o "$CONFIG_PSS" = "y" ]; then
+if [ "$CONFIG_PSS" = "y" ]; then
     comment 'ERROR! You have to use old sound configuration method with PSS cards.'
     hex 'PSS I/O base 220 or 240' PSS_BASE 220
     hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530
@@ -77,14 +78,14 @@ if [ "$CONFIG_PSS" = "y" -o "$CONFIG_PSS" = "y" ]; then
     int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9
 fi
 
-if [ "$CONFIG_MSS" = "y" -o "$CONFIG_MSS" = "m" ]; then
+if [ "$CONFIG_MSS" = "y" ]; then
     hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530
     int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11
     int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3
     int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1
 fi
 
-if [ "$CONFIG_SSCAPE" = "y" -o "$CONFIG_SSCAPE" = "m" ]; then
+if [ "$CONFIG_SSCAPE" = "y" ]; then
     hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330
     int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9
     int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3
@@ -92,7 +93,7 @@ if [ "$CONFIG_SSCAPE" = "y" -o "$CONFIG_SSCAPE" = "m" ]; then
     int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11
 fi
 
-if [ "$CONFIG_TRIX" = "y" -o "$CONFIG_TRIX" = "m" ]; then
+if [ "$CONFIG_TRIX" = "y" ]; then
     comment 'ERROR! You have to use old sound configuration method with OPL3-SA1.'
     hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' TRIX_BASE 530
     int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11
@@ -105,7 +106,7 @@ if [ "$CONFIG_TRIX" = "y" -o "$CONFIG_TRIX" = "m" ]; then
     int 'OPL3-SA1 SB DMA 1 or 3' TRIX_SB_DMA 1
 fi
 
-if [ "$CONFIG_OPL3SA1" = "y" -o "$CONFIG_OPL3SA1" = "m" ]; then
+if [ "$CONFIG_OPL3SA1" = "y" ]; then
     hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' OPL3SA1_BASE 530
     int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' OPL3SA1_IRQ 11
     int 'OPL3-SA1 audio DMA 0, 1 or 3' OPL3SA1_DMA 0
@@ -114,7 +115,7 @@ if [ "$CONFIG_OPL3SA1" = "y" -o "$CONFIG_OPL3SA1" = "m" ]; then
     int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' OPL3SA1_MPU_IRQ 9
 fi
 
-if [ "$CONFIG_CS4232" = "y" -o "$CONFIG_CS4232" = "m" ]; then
+if [ "$CONFIG_CS4232" = "y" ]; then
     hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530
     int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11
     int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0
@@ -123,7 +124,7 @@ if [ "$CONFIG_CS4232" = "y" -o "$CONFIG_CS4232" = "m" ]; then
     int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9
 fi
 
-if [ "$CONFIG_MAD16" = "y" -o "$CONFIG_MAD16" = "m" ]; then
+if [ "$CONFIG_MAD16" = "y" ]; then
     hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530
     int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11
     int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3
@@ -132,7 +133,7 @@ if [ "$CONFIG_MAD16" = "y" -o "$CONFIG_MAD16" = "m" ]; then
     int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9
 fi
 
-if [ "$CONFIG_SOFTOSS" = "y" -o "$CONFIG_SOFTOSS" = "m" ]; then
+if [ "$CONFIG_SOFTOSS" = "y" ]; then
     int 'Sampling rate for SoftOSS 8000 to 48000' SOFTOSS_RATE 22050
     int 'Max # of concurrent voices for SoftOSS 4 to 32' SOFTOSS_VOICES 32
 fi
index fb81925b245f51e46a2dc731d8eccc549be67b5d..af83f40e88034e8e45616c34b1dcb0ac9eb627ee 100644 (file)
@@ -90,18 +90,26 @@ ifeq ($(CONFIG_GUS),y)
 L_OBJS += gus.o
 else
   ifeq ($(CONFIG_GUS),m)
-  M_OBJS += gus.o
+    M_OBJS += gus.o
+  endif
+  ifeq ($(CONFIG_GUSMAX),m)
+    ifneq ($(CONFIG_MSS),y)
+      CONFIG_MSS = m
+    endif
   endif
 endif
 
 ifeq ($(CONFIG_SB),y)
 L_OBJS += sb_audio.o sb_common.o sb_midi.o sb_mixer.o
-LX_OBJS += sb_card.o uart401.o
+LX_OBJS += sb_card.o
+CONFIG_UART401 = y
 else
   ifeq ($(CONFIG_SB),m)
   M_OBJS += sb.o
-  MX_OBJS += uart401.o
   MIX_OBJS += sb_card.o
+  ifneq ($(CONFIG_UART401),y)
+    CONFIG_UART401 = m
+  endif
   endif
 endif
 
@@ -181,7 +189,8 @@ ifeq ($(CONFIG_MAD16),y)
 L_OBJS += mad16.o
 else
   ifeq ($(CONFIG_MAD16),m)
-  M_OBJS += mad16.o
+  M_OBJS += mad16.o sb.o uart401.o
+  MX_OBJS += sb_card.o ad1848.o
   endif
 endif
 
@@ -219,6 +228,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_VMIDI),y)
+L_OBJS += v_midi.o
+else
+   ifeq ($(CONFIG_VMIDI),m)
+      M_OBJS += v_midi.o
+   endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 softoss2.o:    softoss.o softoss_rs.o
diff --git a/drivers/sound/README.C931 b/drivers/sound/README.C931
new file mode 100644 (file)
index 0000000..e6f72be
--- /dev/null
@@ -0,0 +1,62 @@
+Support for the OPTI 82C931 chip
+--------------------------------
+
+The opti 82C931 is supported in it's non PnP mode.
+You do not need to set jumpers etc... The sound driver
+will check the card status and if it is required it will
+force the card into a mode that it can be programmed.
+
+To compile support for the OPTI 82C931 card you can use
+the regular Linux config menus (ie, "make xconfig").
+
+Sound card support should be enabled as a module (chose m).
+Enable (m) for  these items:
+  100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support (CONFIG_SB)
+  Generic OPL2/OPL3 FM synthesizer support                         (CONFIG_ADLIB)
+  Microsoft Sound System support                                  (CONFIG_MSS)
+  Support for OPTi MAD16 and/or Mozart based cards                (CONFIG_MAD16)
+  FM synthesizer (YM3812/OPL-3) support                                   (CONFIG_YM3812)
+
+The configuration menu may ask for addresses, irq lines or dma
+channels. If the card is used as a module the module loading
+options will override these values.
+
+Go on and compile your kernel and modules, install the modules.
+
+I use this configuration as part of /etc/conf.modules:
+
+options sb mad16=1
+options mad16 irq=10 dma=1 io=0x530 joystick=1 cdtype=0
+options opl3 io=0x388
+
+After installing everything and booting to a kernel that
+matches the modules you can load the sound driver:
+
+modprobe mad16
+modprobe opl3
+
+As a result these modules are loaded:
+Module                  Size  Used by
+opl3                   10416   0  (unused)
+mad16                   6472   0 
+sb                     23544   0  [mad16]
+uart401                 5796   0  [mad16 sb]
+ad1848                 16532   1  [mad16]
+sound                  82052   0  [opl3 mad16 sb uart401 ad1848]
+
+Known problems:
+1. The uart401 cannot be used. This is probably a problem which
+   was introduced when the sound driver was modularized.
+   Do not try to load uart401 with options (io=xxx, irq=yyy) because
+   it will try to initialize itself and fail.
+
+2. Cannot use the sound driver in Duplex mode. Until it is fixed
+   use only one DMA channel (0, 1 or 3) for mad16.
+
+3. Configuration of the cdrom adaptor on the sound card is not
+   tested and probably does not work.
+
+4. General problem with the modularized sound driver: If you 
+   load part of the sound driver while a sound program is
+   running, stopping the program may result with a situation
+   where the "Used by" count becomes negative.
index fc4de23e684ad7e1a9dfb54dc28c94cc952313d8..944ffab6a27cf6992d803bac0ebabe090afe4d36 100644 (file)
@@ -2521,6 +2521,7 @@ ad1848_tmr_install(int dev)
 EXPORT_SYMBOL(ad1848_detect);
 EXPORT_SYMBOL(ad1848_init);
 EXPORT_SYMBOL(ad1848_unload);
+EXPORT_SYMBOL(ad1848_control);
 EXPORT_SYMBOL(adintr);
 EXPORT_SYMBOL(probe_ms_sound);
 EXPORT_SYMBOL(attach_ms_sound);
index 3ccdc589296e8a431e06a344cf711297023f84ed..44be2e388f1ab44a53d669d2d2dd807e6f727dfc 100644 (file)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
-#include <linux/config.h>
 
+#include <linux/config.h>
 
 #include "sound_config.h"
 
 #if defined(CONFIG_AUDIO) || defined(MODULE)
-
 #include "ulaw.h"
 #include "coproc.h"
 
@@ -37,36 +36,38 @@ static int      local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV];
 static int      local_conversion[MAX_AUDIO_DEV];
 
 #define CNV_MU_LAW     0x00000001
-static int
-set_format(int dev, int fmt)
+
+static int set_format(int dev, int fmt)
 {
        if (fmt != AFMT_QUERY)
-         {
-                 local_conversion[dev] = 0;
-
-                 if (!(audio_devs[dev]->format_mask & fmt))    /* Not supported */
-                         if (fmt == AFMT_MU_LAW)
-                           {
-                                   fmt = AFMT_U8;
-                                   local_conversion[dev] = CNV_MU_LAW;
-                         } else
-                                 fmt = AFMT_U8;        /* This is always supported */
-
-                 audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt);
-                 local_format[dev] = fmt;
-       } else
+       {
+               local_conversion[dev] = 0;
+
+               if (!(audio_devs[dev]->format_mask & fmt))      /* Not supported */
+               {
+                       if (fmt == AFMT_MU_LAW)
+                       {
+                               fmt = AFMT_U8;
+                               local_conversion[dev] = CNV_MU_LAW;
+                       }
+                       else
+                               fmt = AFMT_U8;  /* This is always supported */
+               }
+               audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt);
+               local_format[dev] = fmt;
+       }
+       else
                return local_format[dev];
 
        return local_format[dev];
 }
 
-int
-audio_open(int dev, struct fileinfo *file)
+int audio_open(int dev, struct fileinfo *file)
 {
-       int             ret;
-       int             bits;
-       int             dev_type = dev & 0x0f;
-       int             mode = file->mode & O_ACCMODE;
+       int ret;
+       int bits;
+       int dev_type = dev & 0x0f;
+       int mode = file->mode & O_ACCMODE;
 
        dev = dev >> 4;
 
@@ -82,20 +83,21 @@ audio_open(int dev, struct fileinfo *file)
                return ret;
 
        if (audio_devs[dev]->coproc)
+       {
                if ((ret = audio_devs[dev]->coproc->
-                    open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
-                 {
-                         audio_release(dev, file);
-                         printk("Sound: Can't access coprocessor device\n");
-
-                         return ret;
-                 }
+                       open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
+               {
+                       audio_release(dev, file);
+                       printk(KERN_WARNING "Sound: Can't access coprocessor device\n");
+                       return ret;
+               }
+       }
+       
        local_conversion[dev] = 0;
 
        if (dev_type == SND_DEV_AUDIO)
-         {
                  set_format(dev, AFMT_MU_LAW);
-       } else
+       else 
                set_format(dev, bits);
 
        audio_mode[dev] = AM_NONE;
@@ -105,8 +107,7 @@ audio_open(int dev, struct fileinfo *file)
        return ret;
 }
 
-static void
-sync_output(int dev)
+static void sync_output(int dev)
 {
        int             p, i;
        int             l;
@@ -117,39 +118,40 @@ sync_output(int dev)
        dmap->flags |= DMA_POST;
 
        /* Align the write pointer with fragment boundaries */
+       
        if ((l = dmap->user_counter % dmap->fragment_size) > 0)
-         {
-                 int             len;
-                 unsigned long   offs = dmap->user_counter % dmap->bytes_in_use;
-
-                 len = dmap->fragment_size - l;
-                 memset(dmap->raw_buf + offs, dmap->neutral_byte, len);
-                 DMAbuf_move_wrpointer(dev, len);
-         }
-/*
- * Clean all unused buffer fragments.
- */
+       {
+               int len;
+               unsigned long offs = dmap->user_counter % dmap->bytes_in_use;
+
+               len = dmap->fragment_size - l;
+               memset(dmap->raw_buf + offs, dmap->neutral_byte, len);
+               DMAbuf_move_wrpointer(dev, len);
+       }
+       
+       /*
+        * Clean all unused buffer fragments.
+        */
 
        p = dmap->qtail;
        dmap->flags |= DMA_POST;
 
        for (i = dmap->qlen + 1; i < dmap->nbufs; i++)
-         {
-                 p = (p + 1) % dmap->nbufs;
-                 if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) >
-                     (dmap->raw_buf + dmap->buffsize))
-                         printk("audio: Buffer error 2\n");
+       {
+               p = (p + 1) % dmap->nbufs;
+               if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) >
+                       (dmap->raw_buf + dmap->buffsize))
+                               printk(KERN_ERR "audio: Buffer error 2\n");
 
-                 memset(dmap->raw_buf + p * dmap->fragment_size,
-                        dmap->neutral_byte,
-                        dmap->fragment_size);
-         }
+               memset(dmap->raw_buf + p * dmap->fragment_size,
+                       dmap->neutral_byte,
+                       dmap->fragment_size);
+       }
 
        dmap->flags |= DMA_DIRTY;
 }
 
-void
-audio_release(int dev, struct fileinfo *file)
+void audio_release(int dev, struct fileinfo *file)
 {
        int             mode;
 
@@ -167,8 +169,8 @@ audio_release(int dev, struct fileinfo *file)
 }
 
 #if defined(NO_INLINE_ASM) || !defined(i386)
-static void
-translate_bytes(const unsigned char *table, unsigned char *buff, int n)
+
+static void translate_bytes(const unsigned char *table, unsigned char *buff, int n)
 {
        unsigned long   i;
 
@@ -184,25 +186,24 @@ extern inline void
 translate_bytes(const void *table, void *buff, int n)
 {
        if (n > 0)
-         {
-                 __asm__("cld\n"
-                         "1:\tlodsb\n\t"
-                         "xlatb\n\t"
-                         "stosb\n\t"
+       {
+               __asm__("cld\n"
+                       "1:\tlodsb\n\t"
+                       "xlatb\n\t"
+                       "stosb\n\t"
                "loop 1b\n\t":
                :         "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
                :         "bx", "cx", "di", "si", "ax");
-         }
+       }
 }
 
 #endif
 
-int
-audio_write(int dev, struct fileinfo *file, const char *buf, int count)
+int audio_write(int dev, struct fileinfo *file, const char *buf, int count)
 {
-       int             c, p, l, buf_size;
-       int             err;
-       char           *dma_buf;
+       int c, p, l, buf_size;
+       int err;
+       char *dma_buf;
 
        dev = dev >> 4;
 
@@ -218,61 +219,61 @@ audio_write(int dev, struct fileinfo *file, const char *buf, int count)
                audio_mode[dev] = AM_WRITE;
 
        if (!count)             /* Flush output */
-         {
+       {
                  sync_output(dev);
                  return 0;
-         }
+       }
+       
        while (c)
-         {
-                 if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0)
-                   {
+       {
+               if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0)
+               {
                            /* Handle nonblocking mode */
-                           if (dev_nblock[dev] && err == -EAGAIN)
-                                   return p;   /* No more space. Return # of accepted bytes */
-                           return err;
-                   }
-                 l = c;
-
-                 if (l > buf_size)
-                         l = buf_size;
-
-                 if (!audio_devs[dev]->d->copy_user)
-                   {
-                           if ((dma_buf + l) >
+                       if (dev_nblock[dev] && err == -EAGAIN)
+                               return p;       /* No more space. Return # of accepted bytes */
+                       return err;
+               }
+               l = c;
+
+               if (l > buf_size)
+                       l = buf_size;
+
+               if (!audio_devs[dev]->d->copy_user)
+               {
+                       if ((dma_buf + l) >
                                (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize))
-                             {
-                                     printk("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize);
-                                     return -EDOM;
-                             }
-                           if (dma_buf < audio_devs[dev]->dmap_out->raw_buf)
-                             {
-                                     printk("audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf);
-                                     return -EDOM;
-                             }
-                           copy_from_user(dma_buf, &(buf)[p], l);
-                 } else
-                         audio_devs[dev]->d->copy_user(dev,
-                                                 dma_buf, 0, buf, p, l);
-
-                 if (local_conversion[dev] & CNV_MU_LAW)
-                   {
-                           /*
-                            * This just allows interrupts while the conversion is running
-                            */
-                           sti();
-                           translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);
-                   }
-                 c -= l;
-                 p += l;
-                 DMAbuf_move_wrpointer(dev, l);
-
-         }
+                       {
+                               printk(KERN_ERR "audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize);
+                               return -EDOM;
+                       }
+                       if (dma_buf < audio_devs[dev]->dmap_out->raw_buf)
+                       {
+                               printk(KERN_ERR "audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf);
+                               return -EDOM;
+                       }
+                       if(copy_from_user(dma_buf, &(buf)[p], l))
+                               return -EFAULT;
+               } 
+               else audio_devs[dev]->d->copy_user(dev, dma_buf, 0, buf, p, l);
+
+               if (local_conversion[dev] & CNV_MU_LAW)
+               {
+                       /*
+                        * This just allows interrupts while the conversion is running
+                        */
+                       sti();
+                       translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);
+               }
+               c -= l;
+               p += l;
+               DMAbuf_move_wrpointer(dev, l);
+
+       }
 
        return count;
 }
 
-int
-audio_read(int dev, struct fileinfo *file, char *buf, int count)
+int audio_read(int dev, struct fileinfo *file, char *buf, int count)
 {
        int             c, p, l;
        char           *dmabuf;
@@ -286,251 +287,268 @@ audio_read(int dev, struct fileinfo *file, char *buf, int count)
                return -EPERM;
 
        if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
-         {
-                 sync_output(dev);
-         }
+               sync_output(dev);
+
        if (audio_devs[dev]->flags & DMA_DUPLEX)
                audio_mode[dev] |= AM_READ;
        else
                audio_mode[dev] = AM_READ;
 
-       while (c)
-         {
-                 if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
-                                                  dev_nblock[dev])) < 0)
-                   {
-                           /* Nonblocking mode handling. Return current # of bytes */
+       while(c)
+       {
+               if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
+                       dev_nblock[dev])) < 0)
+               {
+                       /*
+                        *      Nonblocking mode handling. Return current # of bytes
+                        */
 
-                           if (dev_nblock[dev] && buf_no == -EAGAIN)
-                                   return p;
+                       if (dev_nblock[dev] && buf_no == -EAGAIN)
+                               return p;
 
-                           if (p > 0)          /* Avoid throwing away data */
+                       if (p > 0)              /* Avoid throwing away data */
                                return p;       /* Return it instead */
 
-                           return buf_no;
-                   }
-                 if (l > c)
-                         l = c;
+                       return buf_no;
+               }
+               if (l > c)
+                       l = c;
 
-                 /*
-                  * Insert any local processing here.
-                  */
+               /*
+                * Insert any local processing here.
+                */
 
-                 if (local_conversion[dev] & CNV_MU_LAW)
-                   {
-                           /*
-                            * This just allows interrupts while the conversion is running
-                            */
-                           sti();
+               if (local_conversion[dev] & CNV_MU_LAW)
+               {
+                       /*
+                        * This just allows interrupts while the conversion is running
+                        */
+                       sti();
 
-                           translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l);
-                   }
-                 {
-                         char           *fixit = dmabuf;
+                       translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l);
+               }
+               
+               {
+                       char           *fixit = dmabuf;
 
-                         copy_to_user(&(buf)[p], fixit, l);
-                 };
+                       if(copy_to_user(&(buf)[p], fixit, l))
+                               return -EFAULT;
+               };
 
-                 DMAbuf_rmchars(dev, buf_no, l);
+               DMAbuf_rmchars(dev, buf_no, l);
 
-                 p += l;
-                 c -= l;
-         }
+               p += l;
+               c -= l;
+       }
 
        return count - c;
 }
 
-int
-audio_ioctl(int dev, struct fileinfo *file_must_not_be_used,
+int audio_ioctl(int dev, struct fileinfo *file_must_not_be_used,
            unsigned int cmd, caddr_t arg)
 {
-       int             val;
-
-       /* printk( "audio_ioctl(%x, %x)\n",  (int)cmd,  (int)arg); */
+       int val;
 
        dev = dev >> 4;
 
        if (((cmd >> 8) & 0xff) == 'C')
-         {
-                 if (audio_devs[dev]->coproc)  /* Coprocessor ioctl */
-                         return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
-                 else
-                         printk("/dev/dsp%d: No coprocessor for this device\n", dev);
-
-                 return -ENXIO;
-       } else
-               switch (cmd)
-                 {
-                 case SNDCTL_DSP_SYNC:
-                         if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                                 return 0;
-
-                         if (audio_devs[dev]->dmap_out->fragment_size == 0)
-                                 return 0;
-                         sync_output(dev);
-                         DMAbuf_sync(dev);
-                         DMAbuf_reset(dev);
-                         return 0;
-                         break;
-
-                 case SNDCTL_DSP_POST:
-                         if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                                 return 0;
-                         if (audio_devs[dev]->dmap_out->fragment_size == 0)
-                                 return 0;
-                         audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
-                         sync_output(dev);
-                         dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);
-                         return 0;
-                         break;
-
-                 case SNDCTL_DSP_RESET:
-                         audio_mode[dev] = AM_NONE;
-                         DMAbuf_reset(dev);
-                         return 0;
-                         break;
-
-                 case SNDCTL_DSP_GETFMTS:
-                         return (*(int *) arg = audio_devs[dev]->format_mask);
-                         break;
-
-                 case SNDCTL_DSP_SETFMT:
-                         val = *(int *) arg;
-                         return (*(int *) arg = set_format(dev, val));
-
-                 case SNDCTL_DSP_GETISPACE:
-                         if (!(audio_devs[dev]->open_mode & OPEN_READ))
-                                 return 0;
-                         if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
-                                 return -EBUSY;
-
-                         {
-                                 audio_buf_info  info;
-
-                                 int             err = dma_ioctl(dev, cmd, (caddr_t) & info);
-
-                                 if (err < 0)
-                                         return err;
-
-                                 memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-                                 return 0;
-                         }
-
-                 case SNDCTL_DSP_GETOSPACE:
-                         if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+       {
+               if (audio_devs[dev]->coproc)    /* Coprocessor ioctl */
+                       return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
+               /* else
+                       printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */
+               return -ENXIO;
+       }
+       else switch (cmd)
+       {
+               case SNDCTL_DSP_SYNC:
+                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                               return 0;
+
+                       if (audio_devs[dev]->dmap_out->fragment_size == 0)
+                               return 0;
+                       sync_output(dev);
+                       DMAbuf_sync(dev);
+                       DMAbuf_reset(dev);
+                       return 0;
+
+               case SNDCTL_DSP_POST:
+                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                               return 0;
+                       if (audio_devs[dev]->dmap_out->fragment_size == 0)
+                               return 0;
+                       audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
+                       sync_output(dev);
+                       dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);
+                       return 0;
+
+               case SNDCTL_DSP_RESET:
+                       audio_mode[dev] = AM_NONE;
+                       DMAbuf_reset(dev);
+                       return 0;
+
+               case SNDCTL_DSP_GETFMTS:
+                       return (*(int *) arg = audio_devs[dev]->format_mask);
+
+               case SNDCTL_DSP_SETFMT:
+                       val = *(int *) arg;
+                       return (*(int *) arg = set_format(dev, val));
+
+               case SNDCTL_DSP_GETISPACE:
+                       if (!(audio_devs[dev]->open_mode & OPEN_READ))
+                               return 0;
+                       if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+                               return -EBUSY;
+
+                       {
+                               audio_buf_info  info;
+
+                               int err = dma_ioctl(dev, cmd, (caddr_t) & info);
+
+                               if (err < 0)
+                                       return err;
+
+                               memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
+                               return 0;
+                       }
+
+               case SNDCTL_DSP_GETOSPACE:
+                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
                                  return -EPERM;
-                         if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+                       if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
                                  return -EBUSY;
 
-                         {
-                                 audio_buf_info  info;
-
-                                 int             err = dma_ioctl(dev, cmd, (caddr_t) & info);
-
-                                 if (err < 0)
-                                         return err;
-
-                                 memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-                                 return 0;
-                         }
-
-                 case SNDCTL_DSP_NONBLOCK:
-                         dev_nblock[dev] = 1;
-                         return 0;
-                         break;
-
-                 case SNDCTL_DSP_GETCAPS:
-                         {
-                                 int             info = 1;     /* Revision level of this ioctl() */
-
-                                 if (audio_devs[dev]->flags & DMA_DUPLEX &&
-                                     audio_devs[dev]->open_mode == OPEN_READWRITE)
-                                         info |= DSP_CAP_DUPLEX;
-
-                                 if (audio_devs[dev]->coproc)
-                                         info |= DSP_CAP_COPROC;
-
-                                 if (audio_devs[dev]->d->local_qlen)   /* Device has hidden buffers */
-                                         info |= DSP_CAP_BATCH;
-
-                                 if (audio_devs[dev]->d->trigger)      /* Supports SETTRIGGER */
-                                         info |= DSP_CAP_TRIGGER;
-
-                                 info |= DSP_CAP_MMAP;
-
-                                 memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-                                 return 0;
-                         }
-                         break;
-
-                 case SOUND_PCM_WRITE_RATE:
-                         val = *(int *) arg;
-                         return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, val));
-
-                 case SOUND_PCM_READ_RATE:
-                         return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, 0));
-
-                 case SNDCTL_DSP_STEREO:
-                         {
-                                 int             n;
-
-                                 n = *(int *) arg;
-                                 if (n > 1)
-                                   {
-                                           printk("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n);
-                                           return -EINVAL;
-                                   }
-                                 if (n < 0)
-                                         return -EINVAL;
-
-                                 return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, n + 1) - 1);
-                         }
-
-                 case SOUND_PCM_WRITE_CHANNELS:
-                         val = *(int *) arg;
-                         return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, val));
-
-                 case SOUND_PCM_READ_CHANNELS:
-                         return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, 0));
-
-                 case SOUND_PCM_READ_BITS:
-                         return (*(int *) arg = audio_devs[dev]->d->set_bits(dev, 0));
-
-                 case SNDCTL_DSP_SETDUPLEX:
-                         if (audio_devs[dev]->open_mode != OPEN_READWRITE)
-                                 return -EPERM;
-                         if (audio_devs[dev]->flags & DMA_DUPLEX)
-                                 return 0;
-                         else
-                                 return -EIO;
-                         break;
-
-                 case SNDCTL_DSP_PROFILE:
-                         if (audio_devs[dev]->open_mode & OPEN_WRITE)
-                                 audio_devs[dev]->dmap_out->applic_profile = *(int *) arg;
-                         if (audio_devs[dev]->open_mode & OPEN_READ)
-                                 audio_devs[dev]->dmap_in->applic_profile = *(int *) arg;
-                         return 0;
-                         break;
-
-                 default:
-                         return dma_ioctl(dev, cmd, arg);
-                 }
+                       {
+                               audio_buf_info  info;
+
+                               int err = dma_ioctl(dev, cmd, (caddr_t) & info);
+
+                               if (err < 0)
+                                       return err;
+
+                               memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
+                               return 0;
+                       }
+
+               case SNDCTL_DSP_NONBLOCK:
+                       dev_nblock[dev] = 1;
+                       return 0;
+
+               case SNDCTL_DSP_GETCAPS:
+               {
+                       int info = 1;   /* Revision level of this ioctl() */
+
+                       if (audio_devs[dev]->flags & DMA_DUPLEX &&
+                               audio_devs[dev]->open_mode == OPEN_READWRITE)
+                                       info |= DSP_CAP_DUPLEX;
+
+                       if (audio_devs[dev]->coproc)
+                               info |= DSP_CAP_COPROC;
+
+                       if (audio_devs[dev]->d->local_qlen)     /* Device has hidden buffers */
+                               info |= DSP_CAP_BATCH;
+
+                       if (audio_devs[dev]->d->trigger)        /* Supports SETTRIGGER */
+                               info |= DSP_CAP_TRIGGER;
+
+                       info |= DSP_CAP_MMAP;
+
+                       memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
+                       return 0;
+               }
+
+               case SOUND_PCM_WRITE_RATE:
+                       val = *(int *) arg;
+                       return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, val));
+
+               case SOUND_PCM_READ_RATE:
+                       return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, 0));
+
+               case SNDCTL_DSP_STEREO:
+               {
+                       int n;
+
+                       n = *(int *) arg;
+                       if (n > 1)
+                       {
+/*                             printk(KERN_DENUG "sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n);*/
+                               return -EINVAL;
+                       }
+                       if (n < 0)
+                               return -EINVAL;
+
+                       return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, n + 1) - 1);
+               }
+
+               case SOUND_PCM_WRITE_CHANNELS:
+                       val = *(int *) arg;
+                       return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, val));
+
+               case SOUND_PCM_READ_CHANNELS:
+                       return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, 0));
+
+               case SOUND_PCM_READ_BITS:
+                       return (*(int *) arg = audio_devs[dev]->d->set_bits(dev, 0));
+
+               case SNDCTL_DSP_SETDUPLEX:
+                       if (audio_devs[dev]->open_mode != OPEN_READWRITE)
+                               return -EPERM;
+                       if (audio_devs[dev]->flags & DMA_DUPLEX)
+                               return 0;
+                       else
+                               return -EIO;
+
+               case SNDCTL_DSP_PROFILE:
+                       if (audio_devs[dev]->open_mode & OPEN_WRITE)
+                               audio_devs[dev]->dmap_out->applic_profile = *(int *) arg;
+                       if (audio_devs[dev]->open_mode & OPEN_READ)
+                               audio_devs[dev]->dmap_in->applic_profile = *(int *) arg;
+                       return 0;
+
+               case SNDCTL_DSP_GETODELAY:
+               {
+                       int count;
+                       unsigned long   flags;
+                       struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                               return -EINVAL;
+                       if (!(dmap->flags & DMA_ALLOC_DONE))
+                               return *(int *) arg = 0;
+
+                       save_flags (flags);
+                       cli ();
+                       /* Compute number of bytes that have been played */
+                       count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
+                       if (count < dmap->fragment_size && dmap->qhead != 0)
+                               count += dmap->bytes_in_use;    /* Pointer wrap not handled yet */
+                       count += dmap->byte_counter;
+
+                       /* Substract current count from the number of bytes written by app */
+                       count = dmap->user_counter - count;
+                       if (count < 0)
+                               count = 0;
+                       restore_flags (flags);
+
+                       return *(int *) arg = count;
+               }
+               break;
+
+               default:
+                       return dma_ioctl(dev, cmd, arg);
+       }
 }
 
-void
-audio_init_devices(void)
+void audio_init_devices(void)
 {
        /*
         * NOTE! This routine could be called several times during boot.
         */
 }
 
-
 #endif
 
-void
-reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
+void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
 {
        /*
         * This routine breaks the physical device buffers to logical ones.
@@ -538,8 +556,8 @@ reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
 
        struct audio_operations *dsp_dev = audio_devs[dev];
 
-       unsigned        i, n;
-       unsigned        sr, nc, sz, bsz;
+       unsigned i, n;
+       unsigned sr, nc, sz, bsz;
 
        sr = dsp_dev->d->set_speed(dev, 0);
        nc = dsp_dev->d->set_channels(dev, 0);
@@ -551,12 +569,13 @@ reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
                dmap->neutral_byte = NEUTRAL16;
 
        if (sr < 1 || nc < 1 || sz < 1)
-         {
-                 printk("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);
-                 sr = DSP_DEFAULT_SPEED;
-                 nc = 1;
-                 sz = 8;
-         }
+       {
+/*             printk(KERN_DEBUG "Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);*/
+               sr = DSP_DEFAULT_SPEED;
+               nc = 1;
+               sz = 8;
+       }
+       
        sz = sr * nc * sz;
 
        sz /= 8;                /* #bits -> #bytes */
@@ -567,52 +586,54 @@ reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
        dmap->needs_reorg = 0;
 
        if (dmap->fragment_size == 0)
-         {                     /* Compute the fragment size using the default algorithm */
-
-                 /*
-                    * Compute a buffer size for time not exceeding 1 second.
-                    * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
-                    * of sound (using the current speed, sample size and #channels).
-                  */
-
-                 bsz = dmap->buffsize;
-                 while (bsz > sz)
-                         bsz /= 2;
-
-                 if (bsz == dmap->buffsize)
-                         bsz /= 2;     /* Needs at least 2 buffers */
-
-/*
- *    Split the computed fragment to smaller parts. After 3.5a9
- *      the default subdivision is 4 which should give better
- *      results when recording.
- */
-
-                 if (dmap->subdivision == 0)   /* Not already set */
-                   {
-                           dmap->subdivision = 4;      /* Init to the default value */
-
-                           if ((bsz / dmap->subdivision) > 4096)
-                                   dmap->subdivision *= 2;
-                           if ((bsz / dmap->subdivision) < 4096)
-                                   dmap->subdivision = 1;
-                   }
-                 bsz /= dmap->subdivision;
-
-                 if (bsz < 16)
-                         bsz = 16;     /* Just a sanity check */
-
-                 dmap->fragment_size = bsz;
-       } else
-         {
-                 /*
-                    * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
-                    * the buffer size computation has already been done.
-                  */
-                 if (dmap->fragment_size > (dmap->buffsize / 2))
-                         dmap->fragment_size = (dmap->buffsize / 2);
-                 bsz = dmap->fragment_size;
-         }
+       {       
+               /* Compute the fragment size using the default algorithm */
+
+               /*
+                * Compute a buffer size for time not exceeding 1 second.
+                * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
+                * of sound (using the current speed, sample size and #channels).
+                */
+
+               bsz = dmap->buffsize;
+               while (bsz > sz)
+                       bsz /= 2;
+
+               if (bsz == dmap->buffsize)
+                       bsz /= 2;       /* Needs at least 2 buffers */
+
+               /*
+                *    Split the computed fragment to smaller parts. After 3.5a9
+                *      the default subdivision is 4 which should give better
+                *      results when recording.
+                */
+
+               if (dmap->subdivision == 0)     /* Not already set */
+               {
+                       dmap->subdivision = 4;  /* Init to the default value */
+
+                       if ((bsz / dmap->subdivision) > 4096)
+                               dmap->subdivision *= 2;
+                       if ((bsz / dmap->subdivision) < 4096)
+                               dmap->subdivision = 1;
+               }
+               bsz /= dmap->subdivision;
+
+               if (bsz < 16)
+                       bsz = 16;       /* Just a sanity check */
+
+               dmap->fragment_size = bsz;
+       }
+       else
+       {
+               /*
+                * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
+                * the buffer size computation has already been done.
+                */
+               if (dmap->fragment_size > (dmap->buffsize / 2))
+                       dmap->fragment_size = (dmap->buffsize / 2);
+               bsz = dmap->fragment_size;
+       }
 
        if (audio_devs[dev]->min_fragment)
                if (bsz < (1 << audio_devs[dev]->min_fragment))
@@ -632,42 +653,39 @@ reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
                n = dmap->max_fragments;
 
        if (n < 2)
-         {
-                 n = 2;
-                 bsz /= 2;
-         }
+       {
+               n = 2;
+               bsz /= 2;
+       }
        dmap->nbufs = n;
        dmap->bytes_in_use = n * bsz;
        dmap->fragment_size = bsz;
        dmap->max_byte_counter = (dmap->data_rate * 60 * 60) +
-           dmap->bytes_in_use; /* Approximately one hour */
+                       dmap->bytes_in_use;     /* Approximately one hour */
 
        if (dmap->raw_buf)
-         {
-                 memset(dmap->raw_buf,
-                        dmap->neutral_byte,
-                        dmap->bytes_in_use);
-         }
+       {
+               memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use);
+       }
+       
        for (i = 0; i < dmap->nbufs; i++)
-         {
-                 dmap->counts[i] = 0;
-         }
+       {
+               dmap->counts[i] = 0;
+       }
 
        dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;
 }
 
-static int
-dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
+static int dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
 {
        if (fact == 0)
-         {
-                 fact = dmap->subdivision;
-                 if (fact == 0)
-                         fact = 1;
-                 return (*(int *) arg = fact);
-         }
-       if (dmap->subdivision != 0 ||
-           dmap->fragment_size)        /* Too late to change */
+       {
+               fact = dmap->subdivision;
+               if (fact == 0)
+                       fact = 1;
+               return (*(int *) arg = fact);
+       }
+       if (dmap->subdivision != 0 || dmap->fragment_size)      /* Too late to change */
                return -EINVAL;
 
        if (fact > MAX_REALTIME_FACTOR)
@@ -680,10 +698,9 @@ dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
        return (*(int *) arg = fact);
 }
 
-static int
-dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
+static int dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
 {
-       int             bytes, count;
+       int bytes, count;
 
        if (fact == 0)
                return -EIO;
@@ -736,309 +753,305 @@ dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
                return 0;
 }
 
-int
-dma_ioctl(int dev, unsigned int cmd, caddr_t arg)
+int dma_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
 
        struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
        struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
 
        switch (cmd)
-         {
-
-         case SNDCTL_DSP_SUBDIVIDE:
-                 {
-                         int             fact;
-                         int             ret = 0;
-
-                         fact = *(int *) arg;
-
-                         if (audio_devs[dev]->open_mode & OPEN_WRITE)
-                                 ret = dma_subdivide(dev, dmap_out, arg, fact);
-                         if (ret < 0)
-                                 return ret;
-
-                         if (audio_devs[dev]->open_mode != OPEN_WRITE ||
-                             (audio_devs[dev]->flags & DMA_DUPLEX &&
-                              audio_devs[dev]->open_mode & OPEN_READ))
-                                 ret = dma_subdivide(dev, dmap_in, arg, fact);
-
-                         return ret;
-                 }
-                 break;
-
-         case SNDCTL_DSP_GETISPACE:
-         case SNDCTL_DSP_GETOSPACE:
-                 {
-                         struct dma_buffparms *dmap = dmap_out;
-
-                         audio_buf_info *info = (audio_buf_info *) arg;
-
-                         if (cmd == SNDCTL_DSP_GETISPACE &&
-                             !(audio_devs[dev]->open_mode & OPEN_READ))
-                                 return -EINVAL;
-
-                         if (cmd == SNDCTL_DSP_GETOSPACE &&
-                             !(audio_devs[dev]->open_mode & OPEN_WRITE))
-                                 return -EINVAL;
-
-                         if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
-                                 dmap = dmap_in;
-
-                         if (dmap->mapping_flags & DMA_MAP_MAPPED)
-                                 return -EINVAL;
-
-                         if (!(dmap->flags & DMA_ALLOC_DONE))
-                                 reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
-
-                         info->fragstotal = dmap->nbufs;
-
-                         if (cmd == SNDCTL_DSP_GETISPACE)
-                                 info->fragments = dmap->qlen;
-                         else
-                           {
-                                   if (!DMAbuf_space_in_queue(dev))
-                                           info->fragments = 0;
-                                   else
-                                     {
-                                             info->fragments = DMAbuf_space_in_queue(dev);
-                                             if (audio_devs[dev]->d->local_qlen)
-                                               {
-                                                       int             tmp = audio_devs[dev]->d->local_qlen(dev);
-
-                                                       if (tmp && info->fragments)
-                                                               tmp--;  /*
-                                                                        * This buffer has been counted twice
-                                                                        */
-                                                       info->fragments -= tmp;
-                                               }
-                                     }
-                           }
-
-                         if (info->fragments < 0)
-                                 info->fragments = 0;
-                         else if (info->fragments > dmap->nbufs)
-                                 info->fragments = dmap->nbufs;
-
-                         info->fragsize = dmap->fragment_size;
-                         info->bytes = info->fragments * dmap->fragment_size;
-
-                         if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
-                                 info->bytes -= dmap->counts[dmap->qhead];
-                         else
-                           {
-                                   info->fragments = info->bytes / dmap->fragment_size;
-                                   info->bytes -= dmap->user_counter % dmap->fragment_size;
-                           }
-                 }
-                 return 0;
-
-         case SNDCTL_DSP_SETTRIGGER:
-                 {
-                         unsigned long   flags;
-
-                         int             bits;
-                         int             changed;
-
-                         bits = *(int *) arg;
-                         bits &= audio_devs[dev]->open_mode;
-
-                         if (audio_devs[dev]->d->trigger == NULL)
-                                 return -EINVAL;
-
-                         if (!(audio_devs[dev]->flags & DMA_DUPLEX))
-                                 if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))
-                                   {
-                                           printk("Sound: Device doesn't have full duplex capability\n");
-                                           return -EINVAL;
-                                   }
-                         save_flags(flags);
-                         cli();
-                         changed = audio_devs[dev]->enable_bits ^ bits;
-
-                         if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)
-                           {
-                                   int             err;
-
-                                   reorganize_buffers(dev, dmap_in, 1);
-
-                                   if ((err = audio_devs[dev]->d->prepare_for_input(dev,
-                                                                                    dmap_in->fragment_size, dmap_in->nbufs)) < 0)
-                                           return -err;
-
-                                   dmap_in->dma_mode = DMODE_INPUT;
-                                   audio_devs[dev]->enable_bits = bits;
-                                   DMAbuf_activate_recording(dev, dmap_in);
-                           }
-                         if ((changed & bits) & PCM_ENABLE_OUTPUT &&
-                             (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
-                             audio_devs[dev]->go)
-                           {
-
-                                   if (!(dmap_out->flags & DMA_ALLOC_DONE))
-                                     {
-                                             reorganize_buffers(dev, dmap_out, 0);
-                                     }
-                                   dmap_out->dma_mode = DMODE_OUTPUT;
-                                   ;
-                                   audio_devs[dev]->enable_bits = bits;
-                                   dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
-                                   DMAbuf_launch_output(dev, dmap_out);
-                                   ;
-                           }
-                         audio_devs[dev]->enable_bits = bits;
-                         if (changed && audio_devs[dev]->d->trigger)
-                           {
-                                   audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);
-                           }
-                         restore_flags(flags);
-                 }
-         case SNDCTL_DSP_GETTRIGGER:
-                 return (*(int *) arg = audio_devs[dev]->enable_bits);
-                 break;
-
-         case SNDCTL_DSP_SETSYNCRO:
-
-                 if (!audio_devs[dev]->d->trigger)
-                         return -EINVAL;
-
-                 audio_devs[dev]->d->trigger(dev, 0);
-                 audio_devs[dev]->go = 0;
-                 return 0;
-                 break;
-
-         case SNDCTL_DSP_GETIPTR:
-                 {
-                         count_info      info;
-                         unsigned long   flags;
-                         struct dma_buffparms *dmap = dmap_in;
-
-                         if (!(audio_devs[dev]->open_mode & OPEN_READ))
-                                 return -EINVAL;
-
-                         save_flags(flags);
-                         cli();
-                         info.bytes = dmap->byte_counter;
-                         info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_INPUT) & ~3;
-                         if (info.ptr < dmap->fragment_size && dmap->qtail != 0)
-                                 info.bytes += dmap->bytes_in_use;     /* Pointer wrap not handled yet */
-
-                         info.blocks = dmap->qlen;
-                         info.bytes += info.ptr;
-                         memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-
-                         if (dmap->mapping_flags & DMA_MAP_MAPPED)
-                                 dmap->qlen = 0;       /* Reset interrupt counter */
-                         restore_flags(flags);
-                         return 0;
-                 }
-                 break;
-
-         case SNDCTL_DSP_GETOPTR:
-                 {
-                         count_info      info;
-                         unsigned long   flags;
-                         struct dma_buffparms *dmap = dmap_out;
-
-                         if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                                 return -EINVAL;
-
-                         save_flags(flags);
-                         cli();
-                         info.bytes = dmap->byte_counter;
-                         info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT) & ~3;
-                         if (info.ptr < dmap->fragment_size && dmap->qhead != 0)
-                                 info.bytes += dmap->bytes_in_use;     /* Pointer wrap not handled yet */
-                         info.blocks = dmap->qlen;
-                         info.bytes += info.ptr;
-                         memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-
-                         if (dmap->mapping_flags & DMA_MAP_MAPPED)
-                                 dmap->qlen = 0;       /* Reset interrupt counter */
-
-                         restore_flags(flags);
-                         return 0;
-                 }
-                 break;
-
-    case SNDCTL_DSP_GETODELAY:
-      {
-       int count;
-       unsigned long   flags;
-       struct dma_buffparms *dmap = dmap_out;
-
-       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-          return -EINVAL;
-       if (!(dmap->flags & DMA_ALLOC_DONE))
-          return (*(int *) arg = 0);
-
-       save_flags (flags);
-       cli ();
-       /* Compute number of bytes that have been played */
-       count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
-       if (count < dmap->fragment_size && dmap->qhead != 0)
-          count += dmap->bytes_in_use; /* Pointer wrap not handled yet */
-       count += dmap->byte_counter;
-
-       /* Substract current count from the number of bytes written by app */
-       count = dmap->user_counter - count;
-       if (count < 0)
-           count = 0;
-       restore_flags (flags);
-
-       return (*(int *) arg = count);
-      }
-      break;
-
-         case SNDCTL_DSP_POST:
-                 ;
-                 if (audio_devs[dev]->dmap_out->qlen > 0)
-                         if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
-                                 DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);
-                 ;
-                 return 0;
-                 break;
-
-         case SNDCTL_DSP_GETBLKSIZE:
-                 {
-                         int             fragment_size;
-                         struct dma_buffparms *dmap = dmap_out;
-
-                         if (audio_devs[dev]->open_mode & OPEN_WRITE)
-                                 reorganize_buffers(dev, dmap_out,
-                                                    (audio_devs[dev]->open_mode == OPEN_READ));
-                         if (audio_devs[dev]->open_mode != OPEN_WRITE ||
-                             (audio_devs[dev]->flags & DMA_DUPLEX &&
-                              audio_devs[dev]->open_mode & OPEN_READ))
-                                 reorganize_buffers(dev, dmap_in,
-                                                    (audio_devs[dev]->open_mode == OPEN_READ));
-                         if (audio_devs[dev]->open_mode == OPEN_READ)
-                                 dmap = dmap_in;
-                         fragment_size = dmap->fragment_size;
-                         return (*(int *) arg = fragment_size);
-                 }
-                 break;
-
-         case SNDCTL_DSP_SETFRAGMENT:
-                 {
-                         int             fact;
-                         int             ret;
-
-                         fact = *(int *) arg;
-                         ret = dma_set_fragment(dev, dmap_out, arg, fact);
-                         if (ret < 0)
-                                 return ret;
-
-                         if (audio_devs[dev]->flags & DMA_DUPLEX &&
-                             audio_devs[dev]->open_mode & OPEN_READ)
-                                 ret = dma_set_fragment(dev, dmap_in, arg, fact);
-
-                         return ret;
-                 }
-                 break;
-
-         default:
-                 return audio_devs[dev]->d->ioctl(dev, cmd, arg);
-         }
+       {
+
+               case SNDCTL_DSP_SUBDIVIDE:
+               {
+                       int             fact;
+                       int             ret = 0;
+
+                       fact = *(int *) arg;
+
+                       if (audio_devs[dev]->open_mode & OPEN_WRITE)
+                               ret = dma_subdivide(dev, dmap_out, arg, fact);
+                       if (ret < 0)
+                                return ret;
+
+                       if (audio_devs[dev]->open_mode != OPEN_WRITE ||
+                               (audio_devs[dev]->flags & DMA_DUPLEX &&
+                               audio_devs[dev]->open_mode & OPEN_READ))
+                                       ret = dma_subdivide(dev, dmap_in, arg, fact);
+
+                       return ret;
+               }
+               break;
+
+               case SNDCTL_DSP_GETISPACE:
+               case SNDCTL_DSP_GETOSPACE:
+               {
+                       struct dma_buffparms *dmap = dmap_out;
+
+                       audio_buf_info *info = (audio_buf_info *) arg;
+
+                       if (cmd == SNDCTL_DSP_GETISPACE &&
+                               !(audio_devs[dev]->open_mode & OPEN_READ))
+                                       return -EINVAL;
+
+                       if (cmd == SNDCTL_DSP_GETOSPACE &&
+                               !(audio_devs[dev]->open_mode & OPEN_WRITE))
+                                       return -EINVAL;
+
+                       if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
+                               dmap = dmap_in;
+
+                       if (dmap->mapping_flags & DMA_MAP_MAPPED)
+                               return -EINVAL;
+
+                       if (!(dmap->flags & DMA_ALLOC_DONE))
+                               reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
+
+                       info->fragstotal = dmap->nbufs;
+
+                       if (cmd == SNDCTL_DSP_GETISPACE)
+                               info->fragments = dmap->qlen;
+                       else
+                       {
+                               if (!DMAbuf_space_in_queue(dev))
+                                       info->fragments = 0;
+                               else
+                               {
+                                       info->fragments = DMAbuf_space_in_queue(dev);
+                                       if (audio_devs[dev]->d->local_qlen)
+                                       {
+                                               int tmp = audio_devs[dev]->d->local_qlen(dev);
+
+                                               if (tmp && info->fragments)
+                                                       tmp--;  /*
+                                                                * This buffer has been counted twice
+                                                                */
+                                               info->fragments -= tmp;
+                                       }
+                               }
+                       }
+
+                       if (info->fragments < 0)
+                               info->fragments = 0;
+                       else if (info->fragments > dmap->nbufs)
+                               info->fragments = dmap->nbufs;
+
+                       info->fragsize = dmap->fragment_size;
+                       info->bytes = info->fragments * dmap->fragment_size;
+
+                       if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
+                               info->bytes -= dmap->counts[dmap->qhead];
+                       else
+                       {
+                               info->fragments = info->bytes / dmap->fragment_size;
+                               info->bytes -= dmap->user_counter % dmap->fragment_size;
+                       }
+               }
+               return 0;
 
+               case SNDCTL_DSP_SETTRIGGER:
+               {
+                       unsigned long flags;
+
+                       int bits;
+                       int changed;
+
+                       bits = *(int *) arg;
+                       bits &= audio_devs[dev]->open_mode;
+
+                       if (audio_devs[dev]->d->trigger == NULL)
+                               return -EINVAL;
+
+                       if (!(audio_devs[dev]->flags & DMA_DUPLEX))
+                               if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))
+                               {
+                                       /* printk(KERN_WARNING "Sound: Device doesn't have full duplex capability\n");*/
+                                       return -EINVAL;
+                               }
+                       save_flags(flags);
+                       cli();
+                       changed = audio_devs[dev]->enable_bits ^ bits;
+
+                       if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)
+                       {
+                               int err;
+
+                               reorganize_buffers(dev, dmap_in, 1);
+
+                               if ((err = audio_devs[dev]->d->prepare_for_input(dev,
+                                       dmap_in->fragment_size, dmap_in->nbufs)) < 0)
+                                               return -err;
+
+                               dmap_in->dma_mode = DMODE_INPUT;
+                               audio_devs[dev]->enable_bits = bits;
+                               DMAbuf_activate_recording(dev, dmap_in);
+                       }
+                       
+                       if ((changed & bits) & PCM_ENABLE_OUTPUT &&
+                               (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
+                               audio_devs[dev]->go)
+                       {
+
+                               if (!(dmap_out->flags & DMA_ALLOC_DONE))
+                               {
+                                       reorganize_buffers(dev, dmap_out, 0);
+                               }
+                               dmap_out->dma_mode = DMODE_OUTPUT;
+                               audio_devs[dev]->enable_bits = bits;
+                               dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+                               DMAbuf_launch_output(dev, dmap_out);
+                       }
+                       audio_devs[dev]->enable_bits = bits;
+                       
+                       if (changed && audio_devs[dev]->d->trigger)
+                       {
+                               audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);
+                       }
+                       restore_flags(flags);
+               }
+               /* Falls through... */
+
+               case SNDCTL_DSP_GETTRIGGER:
+                       return (*(int *) arg = audio_devs[dev]->enable_bits);
+
+               case SNDCTL_DSP_SETSYNCRO:
+
+                       if (!audio_devs[dev]->d->trigger)
+                               return -EINVAL;
+
+                       audio_devs[dev]->d->trigger(dev, 0);
+                       audio_devs[dev]->go = 0;
+                       return 0;
+                       break;
+
+               case SNDCTL_DSP_GETIPTR:
+               {
+                       count_info      info;
+                       unsigned long   flags;
+                       struct dma_buffparms *dmap = dmap_in;
+
+                       if (!(audio_devs[dev]->open_mode & OPEN_READ))
+                               return -EINVAL;
+
+                       save_flags(flags);
+                       cli();
+                       info.bytes = dmap->byte_counter;
+                       info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_INPUT) & ~3;
+                       if (info.ptr < dmap->fragment_size && dmap->qtail != 0)
+                               info.bytes += dmap->bytes_in_use;       /* Pointer wrap not handled yet */
+
+                       info.blocks = dmap->qlen;
+                       info.bytes += info.ptr;
+                       memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
+
+                       if (dmap->mapping_flags & DMA_MAP_MAPPED)
+                               dmap->qlen = 0; /* Reset interrupt counter */
+                       restore_flags(flags);
+                       return 0;
+               }
+               break;
+
+               case SNDCTL_DSP_GETOPTR:
+               {
+                       count_info      info;
+                       unsigned long   flags;
+                       struct dma_buffparms *dmap = dmap_out;
+
+                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                               return -EINVAL;
+
+                       save_flags(flags);
+                       cli();
+                       info.bytes = dmap->byte_counter;
+                       info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT) & ~3;
+                       if (info.ptr < dmap->fragment_size && dmap->qhead != 0)
+                               info.bytes += dmap->bytes_in_use;       /* Pointer wrap not handled yet */
+                       info.blocks = dmap->qlen;
+                       info.bytes += info.ptr;
+                       memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
+
+                       if (dmap->mapping_flags & DMA_MAP_MAPPED)
+                               dmap->qlen = 0; /* Reset interrupt counter */
+
+                       restore_flags(flags);
+                       return 0;
+               }
+               break;
+
+               case SNDCTL_DSP_GETODELAY:
+               {
+                       int count;
+                       unsigned long   flags;
+                       struct dma_buffparms *dmap = dmap_out;
+
+                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                               return -EINVAL;
+                       if (!(dmap->flags & DMA_ALLOC_DONE))
+                               return (*(int *) arg = 0);
+
+                       save_flags(flags);
+                       cli();
+                       /* Compute number of bytes that have been played */
+                       count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
+                       if (count < dmap->fragment_size && dmap->qhead != 0)
+                               count += dmap->bytes_in_use;    /* Pointer wrap not handled yet */
+                       count += dmap->byte_counter;
+
+                       /* Substract current count from the number of bytes written by app */
+                       count = dmap->user_counter - count;
+                       if (count < 0)
+                               count = 0;
+                       restore_flags (flags);
+
+                       return (*(int *) arg = count);
+               }
+
+               case SNDCTL_DSP_POST:
+                       if (audio_devs[dev]->dmap_out->qlen > 0)
+                               if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
+                                       DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);
+                       return 0;
+
+               case SNDCTL_DSP_GETBLKSIZE:
+               {
+                       int             fragment_size;
+                       struct dma_buffparms *dmap = dmap_out;
+
+                       if (audio_devs[dev]->open_mode & OPEN_WRITE)
+                               reorganize_buffers(dev, dmap_out,
+                                       (audio_devs[dev]->open_mode == OPEN_READ));
+                       if (audio_devs[dev]->open_mode != OPEN_WRITE ||
+                               (audio_devs[dev]->flags & DMA_DUPLEX &&
+                               audio_devs[dev]->open_mode & OPEN_READ))
+                                       reorganize_buffers(dev, dmap_in,
+                                               (audio_devs[dev]->open_mode == OPEN_READ));
+                       if (audio_devs[dev]->open_mode == OPEN_READ)
+                                       dmap = dmap_in;
+                       fragment_size = dmap->fragment_size;
+                       return (*(int *) arg = fragment_size);
+               }
+
+               case SNDCTL_DSP_SETFRAGMENT:
+               {
+                       int  fact;
+                       int  ret = 0;
+
+                       fact = *(int *) arg;
+                       if (audio_devs[dev]->open_mode & OPEN_WRITE)
+                               ret = dma_set_fragment(dev, dmap_out, arg, fact);
+                       if (ret < 0)
+                               return ret;
+
+                       if (audio_devs[dev]->open_mode != OPEN_WRITE ||
+                               (audio_devs[dev]->flags & DMA_DUPLEX &&
+                               audio_devs[dev]->open_mode & OPEN_READ))
+                               ret = dma_set_fragment(dev, dmap_in, arg, fact);
+
+                       return ret;
+               }
+               break;
+
+               default:
+                       return audio_devs[dev]->d->ioctl(dev, cmd, arg);
+       }
 }
index e00ca26f5bb42642aaf9413e2801ca47ba0b240a..6dceeca56bf1dafdfc26f6cb0b2241f5a0bc79fb 100644 (file)
@@ -58,7 +58,8 @@
 #define OPT_UNUSED5    23
 #define OPT_YM3812_AUTO        24
 #define OPT_YM3812     25
-#define OPT_LAST       25      /* Last defined OPT number */
+#define OPT_VMIDI   26
+#define OPT_LAST       27      /* Last defined OPT number */
 
 #define DUMMY_OPTS (B(OPT_YM3812_AUTO))
 
                  B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)| \
                  B(OPT_MSS)|B(OPT_SSCAPE)|B(OPT_UART6850)|B(OPT_TRIX)| \
                  B(OPT_MAD16)|B(OPT_CS4232)|B(OPT_MAUI)|B(OPT_ADLIB)| \
-                 B(OPT_SPNP)|B(OPT_OPL3SA1)|B(OPT_SOFTOSS))
+                 B(OPT_SPNP)|B(OPT_OPL3SA1)|B(OPT_SOFTOSS)|B(OPT_VMIDI))
 #define MPU_DEVS (B(OPT_PSS)|\
                  B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)|B(OPT_SSCAPE))
 #define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_SPNP)|\
                  B(OPT_OPL3SA1))
-#define NON_AUDIO_CARDS (B(OPT_ADLIB)|B(OPT_MPU401)|B(OPT_UART6850)|B(OPT_MAUI))
+#define NON_AUDIO_CARDS (B(OPT_ADLIB)|B(OPT_MPU401)|B(OPT_UART6850)|B(OPT_MAUI)|B(OPT_VMIDI))
 #define AUDIO_CARDS (ANY_DEVS & ~NON_AUDIO_CARDS)
 #define MIDI_CARDS (ANY_DEVS & ~(B(OPT_ADLIB)|B(OPT_MSS)))
 #define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\
@@ -144,7 +145,8 @@ hw_entry        hw_table[] =
        {B(OPT_MPU401) | B(OPT_MAUI), 0, "UNUSED4", 0, 0, 0},
        {MIDI_CARDS, 0, "UNUSED5", 1, 0, 1},
        {B(OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
-       {B(OPT_PSS) | B(OPT_SB) | B(OPT_PAS) | B(OPT_ADLIB) | B(OPT_MSS) | B(OPT_PSS), B(OPT_YM3812_AUTO), "YM3812", 1, 0, 1}
+       {B(OPT_PSS) | B(OPT_SB) | B(OPT_PAS) | B(OPT_ADLIB) | B(OPT_MSS) | B(OPT_PSS), B(OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
+       {0, 0, "VMIDI", 1, 0, 0}
 };
 
 char           *questions[] =
@@ -176,6 +178,7 @@ char           *questions[] =
        "*** Unused option 5 ***",
        "This should not be asked",
        "FM synthesizer (YM3812/OPL-3) support",
+       "Loopback MIDI device support",
        "Is the sky really falling"
 };
 
@@ -271,6 +274,8 @@ char           *help[] =
        "This enables the Yamaha FM synthesizer chip used on many sound\n"
        "cards.\n",
 
+       "This enable Loopback virtual MIDI device\n",
+
        "Is the sky really falling"
 };
 
index a146614c8b03a1b0b7dd28cb1a19373c974f3064..81b9cf4791ae1d95c64bc78f41fc0c37aae181a8 100644 (file)
@@ -26,6 +26,7 @@
 #define SNDCARD_OPL3SA1_SB             39
 #define SNDCARD_OPL3SA1_MPU            40
 #define SNDCARD_SOFTOSS                        36
+#define SNDCARD_VMIDI                  37
 
 void attach_opl3sa_wss (struct address_info *hw_config);
 int probe_opl3sa_wss (struct address_info *hw_config);
@@ -421,6 +422,10 @@ struct sound_timer_operations {
                attach_softsyn_card, probe_softsyn, unload_softsyn},
 #endif
 
+#if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI) && !defined(CONFIG_VMIDI_MODULE)
+               {"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device",      attach_v_midi, probe_v_midi, unload_v_midi},
+#endif
+
 
 
 
@@ -566,6 +571,11 @@ struct sound_timer_operations {
 #if defined(CONFIG_YM3812) 
                {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
+
+#if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI)
+               {SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+
                {0, {0}, 0}
        };
 
index ab5164ee4d2aca4be205218d9bf846f38df17867..32337560493b7d46e7f971e8f2028c2aa6aa75e7 100644 (file)
@@ -1174,7 +1174,7 @@ do_outputintr(int dev, int dummy)
        if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
                dmap->flags &= ~DMA_ACTIVE;
 
-       while (dmap->qlen < 0)
+       while (dmap->qlen <= 0)
          {
                  dmap->underrun_count++;
 
index eba6072d68ba929202901e78ee55d586843ac4ff..823452ef47785ec73d9b0335ca8ee7b5438ae032 100644 (file)
@@ -259,8 +259,10 @@ init_module(void)
 void
 cleanup_module(void)
 {
+#if defined(CONFIG_GUS16)
        if (db16)
                unload_gus_db16(&config);
+#endif
        unload_gus(&config);
        SOUND_LOCK_END;
 }
index 2814ffe12cfe38af3a1da152dbc1b4def39ab434..c8320e95f99a7f969d9036b808520f486b4686b2 100644 (file)
@@ -159,7 +159,7 @@ static int      freq_div_table[] =
        19293                   /* 32 */
 };
 
-static struct patch_info *samples;
+static struct patch_info *samples = NULL;
 static long     sample_ptrs[MAX_SAMPLE + 1];
 static int      sample_map[32];
 static int      free_sample;
@@ -3005,8 +3005,7 @@ gus_default_mixer_init(void)
        return n;
 }
 
-void
-gus_wave_init(struct address_info *hw_config)
+void gus_wave_init(struct address_info *hw_config)
 {
        unsigned long   flags;
        unsigned char   val;
@@ -3025,16 +3024,19 @@ gus_wave_init(struct address_info *hw_config)
        hw_config->slots[5] = -1;       /* No mixer */
 
        if (!gus_pnp_flag)
+       {
                if (irq < 0 || irq > 15)
-                 {
-                         printk("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
-                         return;
-                 }
+               {
+                       printk("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
+                       return;
+               }
+       }
+       
        if (dma < 0 || dma > 7 || dma == 4)
-         {
-                 printk("ERROR! Invalid DMA#%d. GUS Disabled", dma);
-                 return;
-         }
+       {
+               printk("ERROR! Invalid DMA#%d. GUS Disabled", dma);
+               return;
+       }
        gus_irq = irq;
        gus_dma = dma;
        gus_dma2 = dma2;
@@ -3043,9 +3045,9 @@ gus_wave_init(struct address_info *hw_config)
                gus_dma2 = dma;
 
        /*
-          * Try to identify the GUS model.
-          *
-          *  Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+        * Try to identify the GUS model.
+        *
+        *  Versions < 3.6 don't have the digital ASIC. Try to probe it first.
         */
 
        save_flags(flags);
@@ -3055,126 +3057,128 @@ gus_wave_init(struct address_info *hw_config)
        restore_flags(flags);
 
        if (gus_pnp_flag || (val != 0xff && (val & 0x06)))      /* Should be 0x02?? */
-         {
-                 int             ad_flags = 0;
-
-                 if (gus_pnp_flag)
-                         ad_flags = 0x12345678;        /* Interwave "magic" */
-                 /*
-                    * It has the digital ASIC so the card is at least v3.4.
-                    * Next try to detect the true model.
-                  */
-
-                 if (gus_pnp_flag)     /* Hack hack hack */
-                         val = 10;
-                 else
-                         val = inb(u_MixSelect);
-
-                 /*
-                    * Value 255 means pre-3.7 which don't have mixer.
-                    * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
-                    * 10 and above is GUS MAX which has the CS4231 codec/mixer.
-                    *
+       {
+               int             ad_flags = 0;
+
+               if (gus_pnp_flag)
+                       ad_flags = 0x12345678;  /* Interwave "magic" */
+               /*
+                * It has the digital ASIC so the card is at least v3.4.
+                * Next try to detect the true model.
                   */
 
-                 if (val == 255 || val < 5)
-                   {
-                           model_num = "3.4";
-                           gus_type = 0x34;
-                 } else if (val < 10)
-                   {
-                           model_num = "3.7";
-                           gus_type = 0x37;
-                           mixer_type = ICS2101;
-                           request_region(u_MixSelect, 1, "GUS mixer");
-                 } else
-                   {
-                           model_num = "MAX";
-                           gus_type = 0x40;
-                           mixer_type = CS4231;
+               if (gus_pnp_flag)       /* Hack hack hack */
+                       val = 10;
+               else
+                       val = inb(u_MixSelect);
+
+               /*
+                * Value 255 means pre-3.7 which don't have mixer.
+                * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
+                * 10 and above is GUS MAX which has the CS4231 codec/mixer.
+                *
+                */
+
+               if (val == 255 || val < 5)
+               {
+                       model_num = "3.4";
+                       gus_type = 0x34;
+               }
+               else if (val < 10)
+               {
+                       model_num = "3.7";
+                       gus_type = 0x37;
+                       mixer_type = ICS2101;
+                       request_region(u_MixSelect, 1, "GUS mixer");
+               }
+               else
+               {
+                       model_num = "MAX";
+                       gus_type = 0x40;
+                       mixer_type = CS4231;
 #ifdef CONFIG_GUSMAX
-                           {
-                                   unsigned char   max_config = 0x40;  /* Codec enable */
-
-                                   if (gus_dma2 == -1)
-                                           gus_dma2 = gus_dma;
-
-                                   if (gus_dma > 3)
-                                           max_config |= 0x10;         /* 16 bit capture DMA */
-
-                                   if (gus_dma2 > 3)
-                                           max_config |= 0x20;         /* 16 bit playback DMA */
-
-                                   max_config |= (gus_base >> 4) & 0x0f;       /* Extract the X from 2X0 */
-
-                                   outb((max_config), gus_base + 0x106);       /* UltraMax control */
-                           }
-
-                           if (ad1848_detect(gus_base + 0x10c, &ad_flags, hw_config->osp))
-                             {
-                                     char           *name = "GUS MAX";
-                                     int             old_num_mixers = num_mixers;
-
-                                     if (gus_pnp_flag)
-                                             name = "GUS PnP";
-
-                                     gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
-                                     gus_wave_volume = 90;
-                                     have_gus_max = 1;
-                                     if (hw_config->name)
-                                             name = hw_config->name;
-
-                                     hw_config->slots[1] = ad1848_init(name, gus_base + 0x10c,
-                                                                   -irq,
-                                                               gus_dma2,       /* Playback DMA */
-                                                                gus_dma,       /* Capture DMA */
-                                                                       1,      /* Share DMA channels with GF1 */
-                                                        hw_config->osp);
-
-                                     if (num_mixers > old_num_mixers)
-                                       {       /* GUS has it's own mixer map */
-                                               AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH);
-                                               AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
-                                               AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
-                                       }
-                           } else
-                                   printk("[Where's the CS4231?]");
+                       {
+                               unsigned char   max_config = 0x40;      /* Codec enable */
+
+                               if (gus_dma2 == -1)
+                                       gus_dma2 = gus_dma;
+
+                               if (gus_dma > 3)
+                                       max_config |= 0x10;             /* 16 bit capture DMA */
+
+                               if (gus_dma2 > 3)
+                                       max_config |= 0x20;             /* 16 bit playback DMA */
+
+                               max_config |= (gus_base >> 4) & 0x0f;   /* Extract the X from 2X0 */
+
+                               outb((max_config), gus_base + 0x106);   /* UltraMax control */
+                       }
+
+                       if (ad1848_detect(gus_base + 0x10c, &ad_flags, hw_config->osp))
+                       {
+                               char           *name = "GUS MAX";
+                               int             old_num_mixers = num_mixers;
+
+                               if (gus_pnp_flag)
+                                       name = "GUS PnP";
+
+                               gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+                               gus_wave_volume = 90;
+                               have_gus_max = 1;
+                               if (hw_config->name)
+                                       name = hw_config->name;
+
+                               hw_config->slots[1] = ad1848_init(name, gus_base + 0x10c,
+                                                       -irq, gus_dma2, /* Playback DMA */
+                                                       gus_dma,        /* Capture DMA */
+                                                       1,              /* Share DMA channels with GF1 */
+                                                       hw_config->osp);
+
+                               if (num_mixers > old_num_mixers)
+                               {
+                                       /* GUS has it's own mixer map */
+                                       AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH);
+                                       AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
+                                       AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
+                               }
+                       }
+                       else
+                               printk(KERN_WARNING "[Where's the CS4231?]");
 #else
-                           printk("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n");
+                       printk("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n");
 #endif
-                   }
-       } else
-         {
-                 /*
-                    * ASIC not detected so the card must be 2.2 or 2.4.
-                    * There could still be the 16-bit/mixer daughter card.
-                  */
-         }
+               }
+       }
+       else
+       {
+               /*
+                * ASIC not detected so the card must be 2.2 or 2.4.
+                * There could still be the 16-bit/mixer daughter card.
+                */
+       }
 
        if (hw_config->name)
-         {
-
-                 strncpy(tmp, hw_config->name, 45);
-                 tmp[45] = 0;
-                 sprintf(tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024);
-                 tmp2[sizeof(tmp2) - 1] = 0;
-       } else if (gus_pnp_flag)
-         {
-                 sprintf(tmp2, "Gravis UltraSound PnP (%dk)",
-                         (int) gus_mem_size / 1024);
-       } else
+       {
+               strncpy(tmp, hw_config->name, 45);
+               tmp[45] = 0;
+               sprintf(tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024);
+               tmp2[sizeof(tmp2) - 1] = 0;
+       }
+       else if (gus_pnp_flag)
+       {
+               sprintf(tmp2, "Gravis UltraSound PnP (%dk)",
+                       (int) gus_mem_size / 1024);
+       }
+       else
                sprintf(tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
 
 
-       samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc((MAX_SAMPLE + 1) * sizeof(*samples)));
-       sound_mem_sizes[sound_nblocks] = (MAX_SAMPLE + 1) * sizeof(*samples);
-       if (sound_nblocks < 1024)
-               sound_nblocks++;;
+       samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples));
        if (samples == NULL)
-         {
-                 printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n");
-                 return;
-         }
+       {
+               printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n");
+               return;
+       }
        conf_printf(tmp2, hw_config);
        tmp2[sizeof(gus_info.name) - 1] = 0;
        strcpy(gus_info.name, tmp2);
@@ -3182,27 +3186,28 @@ gus_wave_init(struct address_info *hw_config)
        if ((sdev = sound_alloc_synthdev()) == -1)
                printk(KERN_WARNING "gus_init: Too many synthesizers\n");
        else
-         {
-                 voice_alloc = &guswave_operations.alloc;
-                 if (iw_mode)
-                         guswave_operations.id = "IWAVE";
-                 hw_config->slots[0] = sdev;
-                 synth_devs[sdev] = &guswave_operations;
-                 sequencer_init();
+       {
+               voice_alloc = &guswave_operations.alloc;
+               if (iw_mode)
+                       guswave_operations.id = "IWAVE";
+               hw_config->slots[0] = sdev;
+               synth_devs[sdev] = &guswave_operations;
+               sequencer_init();
 #if defined(CONFIG_SEQUENCER) || defined(MODULE)
-                 gus_tmr_install(gus_base + 8);
+               gus_tmr_install(gus_base + 8);
 #endif
-         }
+       }
 
        reset_sample_memory();
 
        gus_initialize();
 
        if (gus_mem_size > 0)
+       {
                if ((dev = sound_alloc_audiodev()) != -1)
-                 {
-                         hw_config->slots[4] = dev;
-                         if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
+               {
+                       hw_config->slots[4] = dev;
+                       if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
                                                            "Ultrasound",
                                                       &gus_audio_driver,
                                             sizeof(struct audio_driver),
@@ -3213,56 +3218,58 @@ gus_wave_init(struct address_info *hw_config)
                                                                   NULL,
                                                                   dma,
                                                              dma2)) < 0)
-                                                 return;
-
-                         audio_devs[gus_devnum]->min_fragment = 9;     /* 512k */
-                         audio_devs[gus_devnum]->max_fragment = 11;    /* 8k (must match size of bounce_buf */
-                         audio_devs[gus_devnum]->mixer_dev = -1;       /* Next mixer# */
-                         audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
+                       {
+                               return;
+                       }
+
+                       audio_devs[gus_devnum]->min_fragment = 9;       /* 512k */
+                       audio_devs[gus_devnum]->max_fragment = 11;      /* 8k (must match size of bounce_buf */
+                       audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */
+                       audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
                } else
-                       printk("GUS: Too many audio devices available\n");
-
+                       printk(KERN_WARNING "GUS: Too many audio devices available\n");
+       }
+       
        /*
-          *  Mixer dependent initialization.
+        *  Mixer dependent initialization.
         */
 
        switch (mixer_type)
-         {
-         case ICS2101:
-                 gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
-                 gus_wave_volume = 90;
-                 request_region(u_MixSelect, 1, "GUS mixer");
-                 hw_config->slots[5] = ics2101_mixer_init();
-                 audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5];      /* Next mixer# */
-                 return;
-
-         case CS4231:
-                 /* Initialized elsewhere (ad1848.c) */
-         default:
-                 hw_config->slots[5] = gus_default_mixer_init();
-                 audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5];      /* Next mixer# */
-                 return;
-         }
-}
-
-void
-gus_wave_unload(struct address_info *hw_config)
+       {
+               case ICS2101:
+                       gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+                       gus_wave_volume = 90;
+                       request_region(u_MixSelect, 1, "GUS mixer");
+                       hw_config->slots[5] = ics2101_mixer_init();
+                       audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5];        /* Next mixer# */
+                       return;
+
+               case CS4231:
+                       /* Initialized elsewhere (ad1848.c) */
+               default:
+                       hw_config->slots[5] = gus_default_mixer_init();
+                       audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5];        /* Next mixer# */
+                       return;
+       }
+}
+
+void gus_wave_unload(struct address_info *hw_config)
 {
 #ifdef CONFIG_GUSMAX
        if (have_gus_max)
-         {
-                 ad1848_unload(gus_base + 0x10c,
+       {
+               ad1848_unload(gus_base + 0x10c,
                                -gus_irq,
                                gus_dma2,       /* Playback DMA */
                                gus_dma,        /* Capture DMA */
                                1);     /* Share DMA channels with GF1 */
-         }
+       }
 #endif
 
        if (mixer_type == ICS2101)
-         {
-                 release_region(u_MixSelect, 1);
-         }
+       {
+               release_region(u_MixSelect, 1);
+       }
        if (hw_config->slots[0] != -1)
                sound_unload_synthdev(hw_config->slots[0]);
        if (hw_config->slots[1] != -1)
@@ -3273,10 +3280,13 @@ gus_wave_unload(struct address_info *hw_config)
                sound_unload_audiodev(hw_config->slots[4]);
        if (hw_config->slots[5] != -1)
                sound_unload_mixerdev(hw_config->slots[4]);
+       
+       if(samples)
+               vfree(samples);
+       samples=NULL;
 }
 
-static void
-do_loop_irq(int voice)
+static void do_loop_irq(int voice)
 {
        unsigned char   tmp;
        int             mode, parm;
index bffc6ef17647a4c73dd654f89fea96ddc3fd859b..4870ec79997fa0aefe3c0bed67d44158ae9db1fa 100644 (file)
@@ -112,6 +112,7 @@ static int      already_initialized = 0;
 static int      board_type = C928;
 
 static int     *mad16_osp;
+static int     c931_detected;  /* minor diferences from C930 */
 
 #ifndef DDB
 #define DDB(x)
@@ -225,6 +226,44 @@ detect_c930(void)
                  DDB(printk("MC7 not writable2 (%x)\n", tmp));
                  return 0;
          }
+
+       tmp = mad_read(MC0_PORT+18);
+       if (tmp == 0xff)
+               return 1;
+       /* We probably have a C931 */
+       DDB(printk("Detected C931 config=0x%02x\n", tmp));
+       c931_detected = 1;
+
+       /*
+         * We cannot configure the chip if it is in PnP mode.
+         * If we have a CSN assigned (bit 8 in MC13) we first try
+         * a software reset, then a software power off, finally
+         * Clearing PnP mode. The last option is not
+        * Bit 8 in MC13 
+         */
+       if ((mad_read(MC0_PORT+13) & 0x80) == 0)
+               return 1;
+
+       /* Software reset */
+       mad_write(MC9_PORT, 0x02);
+       mad_write(MC9_PORT, 0x00);
+
+       if ((mad_read(MC0_PORT+13) & 0x80) == 0)
+               return 1;
+       
+       /* Power off, and on again */
+       mad_write(MC9_PORT, 0xc2);
+       mad_write(MC9_PORT, 0xc0);
+
+       if ((mad_read(MC0_PORT+13) & 0x80) == 0)
+               return 1;
+       
+       /* Force off PnP mode, This is not recommended because
+        * the PnP bios will not recognize the chip on the next
+        * warm boot and may assignd different resources to other
+        * PnP/PCI cards.
+       */
+       mad_write(MC0_PORT+17, 0x04);
        return 1;
 }
 
@@ -329,10 +368,20 @@ wss_init(struct address_info *hw_config)
 static int
 init_c930(struct address_info *hw_config)
 {
-       unsigned char   cfg;
+       unsigned char   cfg = 0;
+
+#ifdef MAD16_CONF
+       cfg |= (0x0f & MAD16_CONF);
+#endif
 
-       cfg = (mad_read(MC1_PORT) & ~0x30);
-       /* mad_write(MC1_PORT, 0); */
+       if(c931_detected)
+       {
+               /* Bit 0 has reversd meaning. Bits 1 and 2 sese
+                  reversed on write.
+                  Support only IDE cdrom. IDE port programmed
+                  somewhere else. */
+               cfg =  (cfg & 0x09) ^ 0x07;
+       }
 
        switch (hw_config->io_base)
          {
@@ -358,7 +407,14 @@ init_c930(struct address_info *hw_config)
        /* MC2 is CD configuration. Don't touch it. */
 
        mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */
-       mad_write(MC4_PORT, 0x52);      /* ??? */
+#ifdef MAD16_CDSEL
+       if(MAD16_CDSEL & 0x20)
+               mad_write(MC4_PORT, 0x66);      /* opl4 */
+       else
+               mad_write(MC4_PORT, 0x56);      /* opl3 */
+#else
+       mad_write(MC4_PORT, 0x56);
+#endif
        mad_write(MC5_PORT, 0x3C);      /* Init it into mode2 */
        mad_write(MC6_PORT, 0x02);      /* Enable WSS, Disable MPU and SB */
        mad_write(MC7_PORT, 0xCB);
index fb65341913d33e8d1b303d4d3074deff8c84fb9a..a28476d920ed1041bcc4682b8ca87ba134dbdd37 100644 (file)
@@ -528,4 +528,11 @@ MIDIbuf_init(void)
 {
 }
 
+int
+MIDIbuf_avail(int dev)
+{
+       return DATA_AVAIL (midi_in_buf[dev]);
+}
+
+
 #endif
index 13751da3dc92496ec54f10deb404ce52fcaecea9..4efb4be2b5e94ccc96224c8dfdd9f270bf361f7a 100644 (file)
@@ -833,7 +833,7 @@ static unsigned int sb16_audio_set_bits(int dev, unsigned int bits)
 
        if (bits != 0)
        {
-               if (devc->bits == AFMT_U8 || bits == AFMT_S16_LE)
+               if (bits == AFMT_U8 || bits == AFMT_S16_LE)
                        devc->bits = bits;
                else
                        devc->bits = AFMT_U8;
index f0b07e8d0f802f3db89c735063ade3f4366a1f7e..62d8d9cd632fa8f4e48bd9c445acfb884f8feeac 100644 (file)
@@ -119,7 +119,7 @@ typedef struct softsyn_devc
 /*
  *     Programs
  */
-       int programs[MAX_SAMPLE];
+       int programs[MAX_PATCH];
 
 /*
  *     Timer parameters
index 829cfcf919c3dc2e7fa102250da76021b0053791..0e7a1666ef49df90f48339ef0fe0535c7038be63 100644 (file)
@@ -74,6 +74,7 @@ void MIDIbuf_release (int dev, struct fileinfo *file);
 int MIDIbuf_ioctl (int dev, struct fileinfo *file,
           unsigned int cmd, caddr_t arg);
 int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait);
+int MIDIbuf_avail(int dev);
 
 void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
 void MIDIbuf_init(void);
@@ -286,3 +287,8 @@ void attach_cs4232_mpu (struct address_info *hw_config);
 void attach_maui(struct address_info * hw_config);
 int probe_maui(struct address_info *hw_config);
 
+/*     From v_midi.c */
+void attach_v_midi (struct address_info *hw_config);
+int probe_v_midi (struct address_info *hw_config);
+void unload_v_midi (struct address_info *hw_config);
+
index 2b80bd165a4812f317614695251f81383348ee5d..9570acf95d2cc2860d7a8667cfe8d618a3751cb8 100644 (file)
@@ -17,11 +17,13 @@ extern struct notifier_block *sound_locker;
 
 EXPORT_SYMBOL(mixer_devs);
 EXPORT_SYMBOL(audio_devs);
+EXPORT_SYMBOL(num_mixers);
 EXPORT_SYMBOL(num_audiodevs);
 
 EXPORT_SYMBOL(note_to_freq);
 EXPORT_SYMBOL(compute_finetune);
 EXPORT_SYMBOL(seq_copy_to_input);
+EXPORT_SYMBOL(sequencer_init);
 EXPORT_SYMBOL(sequencer_timer);
 
 EXPORT_SYMBOL(sound_install_audiodrv);
@@ -35,17 +37,25 @@ EXPORT_SYMBOL(sound_alloc_mididev);
 EXPORT_SYMBOL(sound_alloc_mixerdev);
 EXPORT_SYMBOL(sound_alloc_timerdev);
 EXPORT_SYMBOL(sound_alloc_synthdev);
+EXPORT_SYMBOL(sound_mem_blocks);
+EXPORT_SYMBOL(sound_mem_sizes);
+EXPORT_SYMBOL(sound_nblocks);
 EXPORT_SYMBOL(sound_unload_audiodev);
 EXPORT_SYMBOL(sound_unload_mididev);
 EXPORT_SYMBOL(sound_unload_mixerdev);
 EXPORT_SYMBOL(sound_unload_timerdev);
 EXPORT_SYMBOL(sound_unload_synthdev);
 
+EXPORT_SYMBOL(load_mixer_volumes);
+
 EXPORT_SYMBOL(DMAbuf_start_dma);
+EXPORT_SYMBOL(DMAbuf_open_dma);
+EXPORT_SYMBOL(DMAbuf_close_dma);
 EXPORT_SYMBOL(DMAbuf_inputintr);
 EXPORT_SYMBOL(DMAbuf_outputintr);
 EXPORT_SYMBOL(dma_ioctl);
 
+EXPORT_SYMBOL(conf_printf);
 EXPORT_SYMBOL(conf_printf2);
 
 EXPORT_SYMBOL(sound_timer_init);
@@ -76,3 +86,4 @@ EXPORT_SYMBOL(midi_synth_panning);
 EXPORT_SYMBOL(midi_synth_setup_voice);
 EXPORT_SYMBOL(midi_synth_send_sysex);
 EXPORT_SYMBOL(midi_synth_bender);
+EXPORT_SYMBOL(midi_synth_load_patch);
diff --git a/drivers/sound/v_midi.c b/drivers/sound/v_midi.c
new file mode 100644 (file)
index 0000000..8b9aba1
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * sound/sb_dsp.c
+ *
+ * The low level driver for the Sound Blaster DS chips.
+ */
+/*
+ * Copyright (C) by Hannu Savolainen 1993-1996
+ *
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+
+
+
+#include "sound_config.h"
+#include "soundmodule.h"
+
+#if defined(CONFIG_VMIDI) || defined(MODULE)
+
+#include "v_midi.h"
+
+static vmidi_devc *v_devc[2] = { NULL, NULL};
+static int                     midi1,midi2;
+
+#ifdef MODULE
+
+static struct address_info config;     /* dummy */
+
+int
+init_module(void)
+{
+       printk("MIDI Loopback device driver\n");
+       if (!probe_v_midi(&config))
+               return -ENODEV;
+       attach_v_midi(&config);
+       SOUND_LOCK;
+       return 0;
+}
+
+void
+cleanup_module(void)
+{
+       unload_v_midi(&config);
+       SOUND_LOCK_END;
+}
+
+#endif
+
+/*
+ * The DSP channel can be used either for input or output. Variable
+ * 'sb_irq_mode' will be set when the program calls read or write first time
+ * after open. Current version doesn't support mode changes without closing
+ * and reopening the device. Support for this feature may be implemented in a
+ * future version of this driver.
+ */
+
+
+void            (*midi_input_intr) (int dev, unsigned char data);
+
+static int
+v_midi_open (int dev, int mode,
+             void            (*input) (int dev, unsigned char data),
+             void            (*output) (int dev)
+)
+{
+  vmidi_devc      *devc = midi_devs[dev]->devc;
+  unsigned long   flags;
+
+  if (devc == NULL)
+    return -(ENXIO);
+
+  save_flags (flags);
+  cli ();
+  if (devc->opened)
+    {
+      restore_flags (flags);
+      return -(EBUSY);
+    }
+  devc->opened = 1;
+  restore_flags (flags);
+
+  devc->intr_active = 1;
+
+  if (mode & OPEN_READ)
+    {
+      devc->input_opened = 1;
+      devc->midi_input_intr = input;
+    }
+
+  return 0;
+}
+
+static void
+v_midi_close (int dev)
+{
+  vmidi_devc        *devc = midi_devs[dev]->devc;
+  unsigned long   flags;
+
+  if (devc == NULL)
+    return;
+
+  save_flags (flags);
+  cli ();
+  devc->intr_active = 0;
+  devc->input_opened = 0;
+  devc->opened = 0;
+  restore_flags (flags);
+}
+
+static int
+v_midi_out (int dev, unsigned char midi_byte)
+{
+  vmidi_devc        *devc = midi_devs[dev]->devc;
+  vmidi_devc        *pdevc = midi_devs[devc->pair_mididev]->devc;
+
+  if (devc == NULL)
+    return -(ENXIO);
+
+  if (pdevc->input_opened > 0){
+         if (MIDIbuf_avail(pdevc->my_mididev) > 500)
+               return 0;
+    pdevc->midi_input_intr (pdevc->my_mididev, midi_byte);
+  }
+
+  return 1;
+}
+
+static int
+v_midi_start_read (int dev)
+{
+  return 0;
+}
+
+static int
+v_midi_end_read (int dev)
+{
+  vmidi_devc        *devc = midi_devs[dev]->devc;
+
+  if (devc == NULL)
+    return -(ENXIO);
+
+  devc->intr_active = 0;
+  return 0;
+}
+
+static int
+v_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
+{
+  return -(EPERM);
+}
+
+
+#define MIDI_SYNTH_NAME        "Loopback MIDI"
+#define MIDI_SYNTH_CAPS        SYNTH_CAP_INPUT
+
+#include "midi_synth.h"
+
+static struct midi_operations v_midi_operations =
+{
+  {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI},
+  &std_midi_synth,
+  {0},
+  v_midi_open,
+  v_midi_close,
+  v_midi_ioctl,
+  v_midi_out,
+  v_midi_start_read,
+  v_midi_end_read,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+static struct midi_operations v_midi_operations2 =
+{
+  {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI},
+  &std_midi_synth,
+  {0},
+  v_midi_open,
+  v_midi_close,
+  v_midi_ioctl,
+  v_midi_out,
+  v_midi_start_read,
+  v_midi_end_read,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+void
+attach_v_midi (struct address_info *hw_config)
+{
+
+  /* printk("Attaching v_midi device.....\n"); */
+  if (sound_nblocks >= (1024 - 6)){
+     printk("Sound: Loop Back MIDI: not enough sound driver memory block table\n");
+     return;
+  } 
+
+  midi1 = sound_alloc_mididev();
+  if (midi1 == -1)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return;
+    }
+  midi_devs[midi1] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations)));
+  sound_mem_sizes[sound_nblocks] = sizeof (struct midi_operations);
+       
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (midi_devs[midi1] == NULL)
+    {
+      printk (KERN_WARNING "Loop Back MIDI: Failed to allocate memory\n");
+      sound_unload_mididev(midi1);
+      return;
+    }
+
+  midi2 = sound_alloc_mididev();
+  if (midi2 == -1)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      sound_unload_mididev(midi1);
+      return;
+    }
+
+  midi_devs[midi2] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations)));
+  sound_mem_sizes[sound_nblocks] = sizeof (struct midi_operations);
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (midi_devs[midi2] == NULL)
+    {
+      printk (KERN_WARNING "Loop Back MIDI: Failed to allocate memory\n");
+      sound_unload_mididev(midi1);
+      sound_unload_mididev(midi2);
+      return;
+    }
+
+  /* printk("VMIDI1: %d   VMIDI2: %d\n",midi1,midi2); */
+
+  /* for MIDI-1 */
+  v_devc[0] = (struct vmidi_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct vmidi_devc)));
+  sound_mem_sizes[sound_nblocks] = sizeof (struct vmidi_devc);
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (v_devc[0] == NULL)
+    {
+      printk (KERN_WARNING "Loop Back MIDI: Failed to allocate memory\n");
+      sound_unload_mididev(midi1);
+      sound_unload_mididev(midi2);
+      return;
+    }
+
+  memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations,
+         sizeof (struct midi_operations));
+
+  v_devc[0]->my_mididev = midi1;
+  v_devc[0]->pair_mididev = midi2;
+  v_devc[0]->opened = v_devc[0]->input_opened = 0;
+  v_devc[0]->intr_active = 0;
+  v_devc[0]->midi_input_intr = NULL;
+
+  midi_devs[midi1]->devc = v_devc[0];
+
+  midi_devs[midi1]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations)));
+  sound_mem_sizes[sound_nblocks] = sizeof (struct synth_operations);
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+
+  if (midi_devs[midi1]->converter == NULL)
+    {
+      printk (KERN_WARNING "Loop Back MIDI: Failed to allocate memory\n");
+      sound_unload_mididev(midi1);
+      sound_unload_mididev(midi2);
+      return;
+    }
+
+  std_midi_synth.midi_dev = midi1;
+  memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth,
+         sizeof (struct synth_operations));
+
+  midi_devs[midi1]->converter->id = "V_MIDI 1";
+
+  /* for MIDI-2 */
+  v_devc[1] = (struct vmidi_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct vmidi_devc)));
+  sound_mem_sizes[sound_nblocks] = sizeof (struct vmidi_devc);
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (v_devc[1] == NULL)
+    {
+      printk (KERN_WARNING "Loop Back MIDI: Failed to allocate memory\n");
+      sound_unload_mididev(midi1);
+      sound_unload_mididev(midi2);
+      return;
+    }
+
+
+  memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
+         sizeof (struct midi_operations));
+
+  v_devc[1]->my_mididev = midi2;
+  v_devc[1]->pair_mididev = midi1;
+  v_devc[1]->opened = v_devc[1]->input_opened = 0;
+  v_devc[1]->intr_active = 0;
+  v_devc[1]->midi_input_intr = NULL;
+
+  midi_devs[midi2]->devc = v_devc[1];
+
+
+  midi_devs[midi2]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations)));
+  sound_mem_sizes[sound_nblocks] = sizeof (struct synth_operations);
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+
+  if (midi_devs[midi2]->converter == NULL)
+    {
+      printk (KERN_WARNING "Loop Back MIDI: Failed to allocate memory\n");
+      sound_unload_mididev(midi1);
+      sound_unload_mididev(midi2);
+      return;
+    }
+
+  std_midi_synth.midi_dev = midi2;
+  memcpy ((char *) midi_devs[midi2]->converter, (char *) &std_midi_synth,
+         sizeof (struct synth_operations));
+
+  midi_devs[midi2]->converter->id = "V_MIDI 2";
+
+  sequencer_init();
+  /* printk("Attached v_midi device\n"); */
+
+}
+
+int
+probe_v_midi(struct address_info *hw_config)
+{
+       return(1);      /* always OK */
+}
+
+
+void
+unload_v_midi(struct address_info *hw_config)
+{
+      sound_unload_mididev(midi1);
+      sound_unload_mididev(midi2);
+;
+}
+
+#endif
diff --git a/drivers/sound/v_midi.h b/drivers/sound/v_midi.h
new file mode 100644 (file)
index 0000000..ae759dc
--- /dev/null
@@ -0,0 +1,15 @@
+typedef struct vmidi_devc {
+          int dev;
+
+       /* State variables */
+          int opened;
+
+       
+       /* MIDI fields */
+          int my_mididev;
+          int pair_mididev;
+          int input_opened;
+          int intr_active;
+          void (*midi_input_intr) (int dev, unsigned char data);
+       } vmidi_devc;
+
index f8e87b9a182740989ab157aadccabe71e6d8a8fa..fe26011ff55308025349c0ee2290de99b29bed36 100644 (file)
@@ -25,10 +25,6 @@ if [ "$CONFIG_INET" = "y" ]; then
   tristate 'NFS filesystem support' CONFIG_NFS_FS
   if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
     bool '   Root file system on NFS' CONFIG_ROOT_NFS
-    if [ "$CONFIG_ROOT_NFS" = "y" ]; then
-      bool '      BOOTP support' CONFIG_RNFS_BOOTP
-      bool '      RARP support' CONFIG_RNFS_RARP
-    fi
   fi
   tristate 'NFS server support' CONFIG_NFSD
   if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
index e4ab414a3d958fcbb1dc2676ee6e8154a388a11a..5bb5dcc1ea70e242c9f155e97407caf563aea743 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -41,8 +41,8 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
                if ((current->fsuid != inode->i_uid) && !fsuser())
                        goto error;
                /* Also check the setgid bit! */
-               if (!fsuser() && !in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
-                                            inode->i_gid))
+               if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
+                               inode->i_gid) && !fsuser())
                        attr->ia_mode &= ~S_ISGID;
        }
 
@@ -75,7 +75,7 @@ void inode_setattr(struct inode * inode, struct iattr * attr)
                inode->i_ctime = attr->ia_ctime;
        if (ia_valid & ATTR_MODE) {
                inode->i_mode = attr->ia_mode;
-               if (!fsuser() && !in_group_p(inode->i_gid))
+               if (!in_group_p(inode->i_gid) && !fsuser())
                        inode->i_mode &= ~S_ISGID;
        }
        mark_inode_dirty(inode);
index 23bbe18320003a984f83f273b8602f9526a0f3c8..b39698acd0cee3f2c2630782b773415675578a3b 100644 (file)
@@ -1150,8 +1150,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        notes[0].datasz = sizeof(prstatus);
        notes[0].data = &prstatus;
        prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
-       prstatus.pr_sigpend = current->signal;
-       prstatus.pr_sighold = current->blocked;
+       prstatus.pr_sigpend = current->signal.sig[0];
+       prstatus.pr_sighold = current->blocked.sig[0];
        psinfo.pr_pid = prstatus.pr_pid = current->pid;
        psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
        psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
index 941580f3ecbb703d9cd3019c280afddaeeed3099..bf3ad59cf194c6b57f2b98f34409b98e389c42a0 100644 (file)
@@ -263,6 +263,17 @@ void sync_dev(kdev_t dev)
        sync_inodes(dev);
        sync_buffers(dev, 0);
        sync_dquots(dev, -1);
+       /* 
+        * FIXME(eric) we need to sync the physical devices here. 
+        * This is because some (scsi) controllers have huge amounts of
+        * cache onboard (hundreds of Mb), and we need to instruct
+        * them to commit all of the dirty memory to disk, and we should
+        * not return until this has happened.
+        *
+        * This would need to get implemented by going through the assorted
+        * layers so that each block major number can be synced, and this
+        * would call down into the upper and mid-layer scsi.
+        */
 }
 
 int fsync_dev(kdev_t dev)
index 4118fdc6149d3a23d939a006858172cd3752c790..0a4140745ab04b64cd7f6447c765c9c6ec5e9bca 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 O_TARGET := coda.o
-O_OBJS   := psdev.o upcall.o cnode.o super.o dir.o coda_linux.o symlink.o pioctl.o file.o namecache.o\
-           sysctl.o 
+O_OBJS   := psdev.o cache.o cnode.o super.o dir.o file.o upcall.o coda_linux.o\
+            symlink.o pioctl.o sysctl.o
 M_OBJS   := $(O_TARGET)
 
 # If you want debugging output, please uncomment the following line
index abf8a855f2e2ce70cf8c28525e2a8ca8b37028d1..5f180b04afdaab76bf23744767e795c6e1c9f557 100644 (file)
 
 extern int coda_debug;
 extern int coda_print_entry;
-extern int coda_fetch_inode(struct inode *inode, struct coda_vattr *attr);
 
 /* cnode.c */
-struct cnode *coda_cnode_alloc(void);
-void coda_cnode_free(struct cnode *);
-int  coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb);
+static struct cnode *coda_cnode_alloc(void);
 
 /* return pointer to new empty cnode */
-struct cnode *coda_cnode_alloc(void)
+static struct cnode *coda_cnode_alloc(void)
 {
         struct cnode *result = NULL;
 
@@ -31,7 +28,8 @@ struct cnode *coda_cnode_alloc(void)
         }
 
         memset(result, 0, (int) sizeof(struct cnode));
-        return result;
+        INIT_LIST_HEAD(&(result->c_cnhead));
+       return result;
 }
 
 /* release cnode memory */
@@ -39,7 +37,30 @@ void coda_cnode_free(struct cnode *cinode)
 {
         CODA_FREE(cinode, sizeof(struct cnode));
 }
+
               
+static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
+{
+        CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
+
+        if (coda_debug & D_SUPER ) 
+               print_vattr(attr);
+
+        coda_vattr_to_iattr(inode, attr);
+
+        if (S_ISREG(inode->i_mode))
+                inode->i_op = &coda_file_inode_operations;
+        else if (S_ISDIR(inode->i_mode))
+                inode->i_op = &coda_dir_inode_operations;
+        else if (S_ISLNK(inode->i_mode))
+                inode->i_op = &coda_symlink_inode_operations;
+        else {
+                printk ("coda_read_inode: what's this? i_mode = %o\n", 
+                       inode->i_mode);
+                inode->i_op = NULL;
+        }
+}
+
 /* this is effectively coda_iget:
    - get attributes (might be cached)
    - get the inode for the fid using vfs iget
@@ -97,15 +118,9 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
        }
        CHECK_CNODE(cnp);
 
-       /* refresh the attributes */
-        error = coda_fetch_inode(*inode, &attr);
-        if ( error ) {
-                printk("coda_cnode_make: fetch_inode returned %d\n", error);
-               clear_inode(*inode);
-               coda_cnode_free(cnp);
-                return -error;
-        }
-               CDEBUG(D_CNODE, "Done linking: ino %ld,  at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode), (int) cnp, (int)cnp->c_vnode);
+       /* fill in the inode attributes */
+        coda_fill_inode(*inode, &attr);
+       CDEBUG(D_CNODE, "Done linking: ino %ld,  at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode), (int) cnp, (int)cnp->c_vnode);
 
         EXIT;
         return 0;
@@ -122,49 +137,31 @@ inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
 }
 
  
-/* compute the inode number from the FID
-   same routine as in vproc.cc (venus)
-   XXX look at the exceptional case of root fids etc
-*/
-static ino_t
-coda_fid2ino(ViceFid *fid)
-{
-       u_long ROOT_VNODE = 1;
-       u_long ROOT_UNIQUE = 1;
-       ViceFid nullfid = { 0, 0, 0};
-
-       if ( coda_fideq(fid, &nullfid) ) {
-               printk("coda_fid2ino: called with NULL Fid!\n");
-               return 0;
-       }
-
-       /* what do we return for the root fid */
-
-       /* Other volume root.  We need the relevant mount point's 
-       fid, but we don't know what that is! */
-       if (fid->Vnode == ROOT_VNODE && fid->Unique == ROOT_UNIQUE) {
-               return(0);
-       }
-
-       /* Non volume root. */
-       return(fid->Unique + (fid->Vnode << 10) + (fid->Volume << 20));
-}     
 
 /* convert a fid to an inode. Avoids having a hash table
    such as present in the Mach minicache */
-struct inode *
-coda_fid2inode(ViceFid *fid, struct super_block *sb) {
+struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) {
        ino_t nr;
        struct inode *inode;
        struct cnode *cnp;
-       
-       nr = coda_fid2ino(fid);
+       char str[50];
+ENTRY;
+
+       CDEBUG(D_INODE, "%s\n", coda_f2s(fid, str));
+       nr = coda_f2i(fid);
        inode = iget(sb, nr);
 
+       if ( !inode ) {
+               printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n",
+                      sb, nr);
+               return NULL;
+       }
+
        /* check if this inode is linked to a cnode */
        cnp = (struct cnode *) inode->u.generic_ip;
        if ( cnp == NULL ) {
                iput(inode);
+               EXIT;
                return NULL;
        }
        /* make sure fid is the one we want */
index ea595c35bc87702ac509eb946b884781f3fb3918..0a1d425682fdbb73a5f6c0ad632b796338d60ca9 100644 (file)
 #include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_cache.h>
 
 /* initialize the debugging variables */
-int coda_debug =815;
-int coda_print_entry = 1
+int coda_debug = 0;
+int coda_print_entry = 0
 int coda_access_cache = 1;
 
 /* caller must allocate 36 byte string ! */
@@ -39,6 +39,14 @@ char * coda_f2s(ViceFid *f, char *s)
        return s;
 }
 
+int coda_iscontrol(const char *name, size_t length)
+{
+       if ((CFS_CONTROLLEN == length) && 
+           (strncmp(name, CFS_CONTROL, CFS_CONTROLLEN) == 0))
+               return 1;
+       return 0;
+}
+
 int coda_isroot(struct inode *i)
 {
     if ( i->i_sb->s_root->d_inode == i ) {
@@ -47,11 +55,10 @@ int coda_isroot(struct inode *i)
        return 0;
     }
 }
+
        
-void coda_load_creds(struct CodaCred *cred)
+void coda_load_creds(struct coda_cred *cred)
 {
-        int i;
-
         cred->cr_uid = (vuid_t) current->uid;
         cred->cr_euid = (vuid_t) current->euid;
         cred->cr_suid = (vuid_t) current->suid;
@@ -61,10 +68,211 @@ void coda_load_creds(struct CodaCred *cred)
         cred->cr_egid = (vgid_t) current->egid;
         cred->cr_sgid = (vgid_t) current->sgid;
         cred->cr_fsgid = (vgid_t) current->fsgid;
+}
+
+int coda_cred_ok(struct coda_cred *cred)
+{
+       return(current->fsuid == cred->cr_fsuid);
+}
+
+int coda_cred_eq(struct coda_cred *cred1, struct coda_cred *cred2)
+{
+       return (cred1->cr_fsuid == cred2->cr_fsuid);
+}
+
+unsigned short coda_flags_to_cflags(unsigned short flags)
+{
+       unsigned short coda_flags = 0;
+
+       if ( flags & (O_RDONLY | O_RDWR) )
+               coda_flags |= C_O_READ;
+
+       if ( flags & (O_WRONLY | O_RDWR) )
+               coda_flags |= C_O_WRITE;
 
-        for ( i = 0 ; i < NGROUPS ; ++i ) {
-                cred->cr_groups[i] = (vgid_t) current->groups[i];
+       if ( flags & O_TRUNC ) 
+               coda_flags |= C_O_TRUNC;
+
+       return coda_flags;
+}
+
+
+/* utility functions below */
+void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
+{
+        int inode_type;
+        /* inode's i_dev, i_flags, i_ino are set by iget 
+           XXX: is this all we need ??
+           */
+        switch (attr->va_type) {
+        case C_VNON:
+                inode_type  = 0;
+                break;
+        case C_VREG:
+                inode_type = S_IFREG;
+                break;
+        case C_VDIR:
+                inode_type = S_IFDIR;
+                break;
+        case C_VLNK:
+                inode_type = S_IFLNK;
+                break;
+        default:
+                inode_type = 0;
         }
+       inode->i_mode |= inode_type;
 
+       if (attr->va_mode != (u_short) -1)
+               inode->i_mode = attr->va_mode | inode_type;
+        if (attr->va_uid != -1) 
+               inode->i_uid = (uid_t) attr->va_uid;
+        if (attr->va_gid != -1)
+               inode->i_gid = (gid_t) attr->va_gid;
+       if (attr->va_nlink != -1)
+               inode->i_nlink = attr->va_nlink;
+       if (attr->va_size != -1)
+               inode->i_size = attr->va_size;
+       /*  XXX This needs further study */
+       /*
+        inode->i_blksize = attr->va_blocksize;
+       inode->i_blocks = attr->va_size/attr->va_blocksize 
+         + (attr->va_size % attr->va_blocksize ? 1 : 0); 
+         */
+       if (attr->va_atime.tv_sec != -1) 
+               inode->i_atime = attr->va_atime.tv_sec;
+       if (attr->va_mtime.tv_sec != -1)
+               inode->i_mtime = attr->va_mtime.tv_sec;
+        if (attr->va_ctime.tv_sec != -1)
+               inode->i_ctime = attr->va_ctime.tv_sec;
 }
+/* 
+ * BSD sets attributes that need not be modified to -1. 
+ * Linux uses the valid field to indicate what should be
+ * looked at.  The BSD type field needs to be deduced from linux 
+ * mode.
+ * So we have to do some translations here.
+ */
+
+void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
+{
+        umode_t mode;
+        unsigned int valid;
+
+        /* clean out */        
+        vattr->va_mode = (umode_t) -1;
+        vattr->va_uid = (vuid_t) -1; 
+        vattr->va_gid = (vgid_t) -1;
+        vattr->va_size = (off_t) -1;
+       vattr->va_atime.tv_sec = (time_t) -1;
+        vattr->va_mtime.tv_sec  = (time_t) -1;
+       vattr->va_ctime.tv_sec  = (time_t) -1;
+       vattr->va_atime.tv_nsec =  (time_t) -1;
+        vattr->va_mtime.tv_nsec = (time_t) -1;
+       vattr->va_ctime.tv_nsec = (time_t) -1;
+        vattr->va_type = C_VNON;
+       vattr->va_fileid = (long)-1;
+       vattr->va_gen = (long)-1;
+       vattr->va_bytes = (long)-1;
+       vattr->va_nlink = (short)-1;
+       vattr->va_blocksize = (long)-1;
+       vattr->va_rdev = (dev_t)-1;
+        vattr->va_flags = 0;
+
+        /* determine the type */
+        mode = iattr->ia_mode;
+                if ( S_ISDIR(mode) ) {
+                vattr->va_type = C_VDIR; 
+        } else if ( S_ISREG(mode) ) {
+                vattr->va_type = C_VREG;
+        } else if ( S_ISLNK(mode) ) {
+                vattr->va_type = C_VLNK;
+        } else {
+                /* don't do others */
+                vattr->va_type = C_VNON;
+        }
 
+        /* set those vattrs that need change */
+        valid = iattr->ia_valid;
+        if ( valid & ATTR_MODE ) {
+                vattr->va_mode = iattr->ia_mode;
+       }
+        if ( valid & ATTR_UID ) {
+                vattr->va_uid = (vuid_t) iattr->ia_uid;
+       }
+        if ( valid & ATTR_GID ) {
+                vattr->va_gid = (vgid_t) iattr->ia_gid;
+       }
+        if ( valid & ATTR_SIZE ) {
+                vattr->va_size = iattr->ia_size;
+       }
+        if ( valid & ATTR_ATIME ) {
+                vattr->va_atime.tv_sec = iattr->ia_atime;
+                vattr->va_atime.tv_nsec = 0;
+       }
+        if ( valid & ATTR_MTIME ) {
+                vattr->va_mtime.tv_sec = iattr->ia_mtime;
+                vattr->va_mtime.tv_nsec = 0;
+       }
+        if ( valid & ATTR_CTIME ) {
+                vattr->va_ctime.tv_sec = iattr->ia_ctime;
+                vattr->va_ctime.tv_nsec = 0;
+       }
+        
+}
+  
+
+void print_vattr(struct coda_vattr *attr)
+{
+    char *typestr;
+
+    switch (attr->va_type) {
+    case C_VNON:
+       typestr = "C_VNON";
+       break;
+    case C_VREG:
+       typestr = "C_VREG";
+       break;
+    case C_VDIR:
+       typestr = "C_VDIR";
+       break;
+    case C_VBLK:
+       typestr = "C_VBLK";
+       break;
+    case C_VCHR:
+       typestr = "C_VCHR";
+       break;
+    case C_VLNK:
+       typestr = "C_VLNK";
+       break;
+    case C_VSOCK:
+       typestr = "C_VSCK";
+       break;
+    case C_VFIFO:
+       typestr = "C_VFFO";
+       break;
+    case C_VBAD:
+       typestr = "C_VBAD";
+       break;
+    default:
+       typestr = "????";
+       break;
+    }
+
+
+    printk("attr: type %s (%o)  mode %o uid %d gid %d rdev %d\n",
+          typestr, (int)attr->va_type, (int)attr->va_mode, 
+          (int)attr->va_uid, (int)attr->va_gid, (int)attr->va_rdev);
+    
+    printk("      fileid %d nlink %d size %d blocksize %d bytes %d\n",
+             (int)attr->va_fileid, (int)attr->va_nlink, 
+             (int)attr->va_size,
+             (int)attr->va_blocksize,(int)attr->va_bytes);
+    printk("      gen %ld flags %ld\n",
+             attr->va_gen, attr->va_flags);
+    printk("      atime sec %d nsec %d\n",
+             (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec);
+    printk("      mtime sec %d nsec %d\n",
+             (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec);
+    printk("      ctime sec %d nsec %d\n",
+             (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec);
+}
index cfc10dc839e5eb5ce27074315f3dc88898fb1ef0..a0c0cc6346b26ae08f0648f4d3ef1187f897af53 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Direcotry operations for Coda filesystem
+ * Directory operations for Coda filesystem
  * Original version: (C) 1996 P. Braam and M. Callahan
  * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
  * 
@@ -22,7 +22,7 @@
 #include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_cache.h>
 
 /* dir inode-ops */
 static int coda_create(struct inode *dir, struct dentry *new, int mode);
@@ -43,8 +43,15 @@ static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
 /* support routines */
 static int coda_venus_readdir(struct file *filp, void *dirent, 
                              filldir_t filldir);
+int coda_fsync(struct file *, struct dentry *dentry);
 
-
+struct dentry_operations coda_dentry_operations =
+{
+       NULL, /* revalidate */
+       NULL, /* hash */
+       NULL,
+       coda_dentry_delete
+};
 
 struct inode_operations coda_dir_inode_operations =
 {
@@ -80,7 +87,10 @@ struct file_operations coda_dir_operations = {
         NULL,                   /* mmap */
         coda_open,              /* open */
         coda_release,           /* release */
-        NULL,                   /* fsync */
+       coda_fsync,             /* fsync */
+        NULL,                   
+       NULL,
+       NULL
 };
 
 
@@ -88,9 +98,10 @@ struct file_operations coda_dir_operations = {
 /* acces routines: lookup, readlink, permission */
 static int coda_lookup(struct inode *dir, struct dentry *entry)
 {
-        struct cnode *dircnp, *savedcnp;
+        struct cnode *dircnp;
        struct inode *res_inode = NULL;
        struct ViceFid resfid;
+       int dropme = 0; /* to indicate entry should not be cached */
        int type;
        int error = 0;
        const char *name = entry->d_name.name;
@@ -110,78 +121,56 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
        CHECK_CNODE(dircnp);
 
        if ( length > CFS_MAXNAMLEN ) {
-               printk("name too long: lookup, %s (%s)\n", 
-                      coda_f2s(&dircnp->c_fid, str), name);
+               printk("name too long: lookup, %s (%*s)\n", 
+                      coda_f2s(&dircnp->c_fid, str), length, name);
                return -ENAMETOOLONG;
        }
        
-       CDEBUG(D_INODE, "lookup: %s in %s\n", name, 
+       CDEBUG(D_INODE, "lookup: %*s in %s\n", length, name, 
               coda_f2s(&dircnp->c_fid, str));
 
         /* control object, create inode on the fly */
-        if ( coda_isroot(dir) && (CFS_CONTROLLEN == length) && 
-            (strncmp(name, CFS_CONTROL, CFS_CONTROLLEN) == 0) ) {
+        if (coda_isroot(dir) && coda_iscontrol(name, length)) {
                error = coda_cnode_makectl(&res_inode, dir->i_sb);
                CDEBUG(D_SPECIAL, 
-                      "Lookup on CTL object; iput of ino %ld, count %d\n", 
+                      "Lookup on CTL object; dir ino %ld, count %d\n", 
                       dir->i_ino, dir->i_count);
                 goto exit;
         }
 
-        /* do we have it already in name cache */
-       if ( (savedcnp = cfsnc_lookup(dircnp, name, length)) != NULL ) {
-               CHECK_CNODE(savedcnp);
-               res_inode = CTOI(savedcnp);
-               iget(res_inode->i_sb, res_inode->i_ino);
-               CDEBUG(D_INODE, "cache hit for ino: %ld, count: %d!\n",
-                      res_inode->i_ino, res_inode->i_count);
-               goto exit;
-       }
-       CDEBUG(D_INODE, "name not found in cache!\n");
-
-        /* name not cached */
         error = venus_lookup(dir->i_sb, &(dircnp->c_fid), 
-                               (const char *)name, length, &type, &resfid);
+                            (const char *)name, length, &type, &resfid);
 
        res_inode = NULL;
-       if (!error) {
+       if (!error || (error == -CFS_NOCACHE) ) {
+               if (error == -CFS_NOCACHE) 
+                       dropme = 1;
                error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
                if (error)
-                       return -EACCES;
-               /* put the thing in the name cache */
-               savedcnp = ITOC(res_inode);
-               CHECK_CNODE(savedcnp);
-               CDEBUG(D_INODE, "ABOUT to enter into cache.\n");
-               cfsnc_enter(dircnp, name, length, savedcnp);
-               CDEBUG(D_INODE, "entered in cache\n");
+                       return -error;
        } else if (error != -ENOENT) {
-               CDEBUG(D_INODE, "error for %s(%s)%d\n",
-                      coda_f2s(&dircnp->c_fid, str), name, error);
+               CDEBUG(D_INODE, "error for %s(%*s)%d\n",
+                      coda_f2s(&dircnp->c_fid, str), length, name, error);
                return error;
        }
-       CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d\n",
-              name, coda_f2s(&resfid, str), type, error);
-
-       /* at last we have our inode number from Venus, 
-          now allocate storage for
-          the cnode and do iget, and fill in the attributes */
-
+       CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d, dropme %d\n",
+              name, coda_f2s(&resfid, str), type, error, dropme);
 
 exit:
        entry->d_time = 0;
-       entry->d_op = NULL;
+       entry->d_op = &coda_dentry_operations;
        d_add(entry, res_inode);
+       if ( dropme ) 
+               d_drop(entry);
         EXIT;
         return 0;
 }
 
 
-
 int coda_permission(struct inode *inode, int mask)
 {
         struct cnode *cp;
         int error;
-        int mode = inode->i_mode;
        char str[50];
  
         ENTRY;
@@ -191,16 +180,10 @@ int coda_permission(struct inode *inode, int mask)
                 return 0;
         }
 
-        /* we should be able to trust what is in the mode
-           although Venus should be told to return the 
-           correct modes to the kernel */
-        if ( coda_access_cache == 1 ) { 
-            if (current->fsuid == inode->i_uid)
-                mode >>= 6;
-               else if (in_group_p(inode->i_gid))
-                mode >>= 3;
-               if (((mode & mask & 0007) == mask) )
-                return 0;
+       if ( coda_access_cache == 1 ) {
+               if ( coda_cache_check(inode, mask) ) {
+                       return 0; 
+               }
        }
 
         cp = ITOC(inode);
@@ -212,6 +195,10 @@ int coda_permission(struct inode *inode, int mask)
         CDEBUG(D_INODE, "fid: %s, ino: %ld (mask: %o) error: %d\n", 
               coda_f2s(&(cp->c_fid), str), inode->i_ino, mask, error);
 
+       if ( error == 0 ) {
+               coda_cache_enter(inode, mask);
+       }
+
         return error; 
 }
 
@@ -235,6 +222,10 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
                 printk("coda_create: inode is null or not a directory\n");
                 return -ENOENT;
         }
+
+       if (coda_isroot(dir) && coda_iscontrol(name, length))
+               return -EPERM;
+
        dircnp = ITOC(dir);
         CHECK_CNODE(dircnp);
 
@@ -263,7 +254,7 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
 
        /* invalidate the directory cnode's attributes */
        dircnp->c_flags &= ~C_VATTR;
-       cfsnc_zapfid(&(dircnp->c_fid));
+/*     cfsnc_zapfid(&(dircnp->c_fid)); */
 
        d_instantiate(de, result);
         return 0;
@@ -280,15 +271,18 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
        struct ViceFid newfid;
        char fidstr[50];
 
+
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk("coda_mkdir: inode is NULL or not a directory\n");
                return -ENOENT;
        }
-        dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
-
         if ( len > CFS_MAXNAMLEN )
                 return -ENAMETOOLONG;
+       if (coda_isroot(dir) && coda_iscontrol(name, len))
+               return -EPERM;
+
+        dircnp = ITOC(dir);
+        CHECK_CNODE(dircnp);
 
        CDEBUG(D_INODE, "mkdir %s (len %d) in %s, mode %o.\n", 
               name, len, coda_f2s(&(dircnp->c_fid), fidstr), mode);
@@ -312,7 +306,7 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
        
        /* invalidate the directory cnode's attributes */
        dircnp->c_flags &= ~C_VATTR;
-       cfsnc_zapfid(&(dircnp->c_fid));
+/*     cfsnc_zapfid(&(dircnp->c_fid)); */
 
        dir->i_nlink++;
        d_instantiate(de, inode);
@@ -330,6 +324,9 @@ static int coda_link(struct inode *inode, struct inode *dir_inode,
 
         ENTRY;
 
+       if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
+               return -EPERM;
+
         dir_cnp = ITOC(dir_inode);
         CHECK_CNODE(dir_cnp);
         cnp = ITOC(inode);
@@ -350,8 +347,8 @@ static int coda_link(struct inode *inode, struct inode *dir_inode,
 
        if (  ! error ) { 
              dir_cnp->c_flags &= ~C_VATTR;
-             cfsnc_zapfid(&(dir_cnp->c_fid));
-             cfsnc_zapfid(&(cnp->c_fid));
+/*           cfsnc_zapfid(&(dir_cnp->c_fid)); */
+/*           cfsnc_zapfid(&(cnp->c_fid)); */
 
              inode->i_nlink++;
              d_instantiate(de, inode);
@@ -362,9 +359,8 @@ static int coda_link(struct inode *inode, struct inode *dir_inode,
 }
 
 
-static int 
-coda_symlink(struct inode *dir_inode, struct dentry *de,
-             const char *symname)
+static int coda_symlink(struct inode *dir_inode, struct dentry *de,
+                       const char *symname)
 {
         const char *name = de->d_name.name;
        int len = de->d_name.len;
@@ -374,23 +370,23 @@ coda_symlink(struct inode *dir_inode, struct dentry *de,
         
         ENTRY;
 
-       error = -ENAMETOOLONG;
-       if ( len > CFS_MAXNAMLEN ) { 
-               return error;
-       }
+       if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
+               return -EPERM;
+
+       if ( len > CFS_MAXNAMLEN )
+                return -ENAMETOOLONG;
 
        symlen = strlen(symname);
-       if ( symlen > CFS_MAXNAMLEN ) { 
-               return error;
-       }
+       if ( symlen > CFS_MAXPATHLEN )
+                return -ENAMETOOLONG;
+
         CDEBUG(D_INODE, "symname: %s, length: %d\n", symname, symlen);
 
        error = venus_symlink(dir_inode->i_sb, &(dir_cnp->c_fid), name, len, 
                              symname, symlen);
 
-       if ( !error ) {
-         d_drop(de);
-       }
+       if ( !error )
+               d_drop(de);
 
         CDEBUG(D_INODE, "in symlink result %d\n",error);
         EXIT;
@@ -416,7 +412,7 @@ int coda_unlink(struct inode *dir, struct dentry *de)
               coda_f2s(&(dircnp->c_fid), fidstr), dir->i_ino);
 
         /* this file should no longer be in the namecache! */
-        cfsnc_zapfile(dircnp, (const char *)name, len);
+/*         cfsnc_zapfile(dircnp, (const char *)name, len); */
 
         error = venus_remove(dir->i_sb, &(dircnp->c_fid), name, len);
 
@@ -427,7 +423,7 @@ int coda_unlink(struct inode *dir, struct dentry *de)
 
         /* cache management */
        dircnp->c_flags &= ~C_VATTR;
-       cfsnc_zapfid(&(dircnp->c_fid));
+/*     cfsnc_zapfid(&(dircnp->c_fid)); */
        
        de->d_inode->i_nlink--;
        d_delete(de);
@@ -452,8 +448,15 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
        if (len > CFS_MAXNAMLEN)
                return -ENAMETOOLONG;
 
-        /* this directory name should no longer be in the namecache */
-        cfsnc_zapfile(dircnp, (const char *)name, len);
+       error = -EBUSY;
+       if (de->d_count > 1) {
+               /* Attempt to shrink child dentries ... */
+               shrink_dcache_parent(de);
+               if (de->d_count > 1)
+                       return error;
+       }
+       /* Drop the dentry to force a new lookup */
+       d_drop(de);
 
        error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
 
@@ -462,9 +465,6 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
                 return error;
         }
 
-       dircnp->c_flags &= ~C_VATTR;
-       cfsnc_zapfid(&(dircnp->c_fid));
-
        dir->i_nlink--;
        d_delete(de);
 
@@ -496,8 +496,8 @@ ENTRY;
         }
 
         /* the old file should go from the namecache */
-        cfsnc_zapfile(old_cnp, (const char *)old_name, old_length);
-        cfsnc_zapfile(new_cnp, (const char *)new_name, new_length);
+/*         cfsnc_zapfile(old_cnp, (const char *)old_name, old_length); */
+/*         cfsnc_zapfile(new_cnp, (const char *)new_name, new_length); */
 
         /* cross directory moves */
        if (new_dir != old_dir  &&
@@ -585,19 +585,17 @@ int coda_open(struct inode *i, struct file *f)
         int error = 0;
         struct inode *cont_inode = NULL;
         unsigned short flags = f->f_flags;
+       unsigned short coda_flags = coda_flags_to_cflags(flags);
 
         ENTRY;
         
         CDEBUG(D_SPECIAL, "OPEN inode number: %ld, flags %o.\n", 
               f->f_dentry->d_inode->i_ino, flags);
 
-        if ( flags & O_CREAT ) {
-                flags &= ~O_EXCL; /* taken care of by coda_create ?? */
-        }
         cnp = ITOC(i);
         CHECK_CNODE(cnp);
 
-       error = venus_open(i->i_sb, &(cnp->c_fid), flags, &ino, &dev); 
+       error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev); 
        if (error) {
                CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n",
                       dev, ino, error);
@@ -618,14 +616,13 @@ int coda_open(struct inode *i, struct file *f)
                 CDEBUG(D_FILE, "GRAB: coda_inode_grab: ino %ld, ops at %x\n", 
                       cont_inode->i_ino, (int)cont_inode->i_op);
                 cnp->c_ovp = cont_inode; 
-               cnp->c_odentry.d_inode = cont_inode;
         } 
         cnp->c_ocount++;
 
         /* if opened for writing flush cache entry.  */
-        if ( flags & (O_WRONLY | O_RDWR) ) {
-               cfsnc_zapfid(&(cnp->c_fid));
-       } 
+/*         if ( flags & (O_WRONLY | O_RDWR) ) { */
+/*             cfsnc_zapfid(&(cnp->c_fid)); */
+/*     }  */
 
         CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n", 
               error, i->i_count, i->i_ino);
@@ -641,6 +638,7 @@ int coda_release(struct inode *i, struct file *f)
         struct cnode *cnp;
         int error;
         unsigned short flags = f->f_flags;
+       unsigned short cflags = coda_flags_to_cflags(flags);
 
         ENTRY;
 
@@ -664,7 +662,7 @@ int coda_release(struct inode *i, struct file *f)
                 --cnp->c_owrite;
         }
 
-       error = venus_release(i->i_sb, &(cnp->c_fid), flags);
+       error = venus_release(i->i_sb, &(cnp->c_fid), cflags);
 
         CDEBUG(D_FILE, "coda_release: result: %d\n", error);
         return error;
@@ -693,6 +691,7 @@ static int coda_venus_readdir(struct file *filp, void *getdent,
         struct venus_dirent *vdirent;
         struct getdents_callback *dents_callback;
         int string_offset;
+       int size;
         char debug[255];
 
         ENTRY;        
@@ -703,8 +702,8 @@ static int coda_venus_readdir(struct file *filp, void *getdent,
 
         dents_callback = (struct getdents_callback *) getdent;
 
-        count =  dents_callback->count;
-        CODA_ALLOC(buff, void *, count);
+        size = count =  dents_callback->count;
+        CODA_ALLOC(buff, void *, size);
         if ( ! buff ) { 
                 printk("coda_venus_readdir: out of memory.\n");
                 return -ENOMEM;
@@ -764,6 +763,6 @@ CDEBUG(D_FILE, "ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d,
         } 
 
 exit:
-        CODA_FREE(buff, count);
+        CODA_FREE(buff, size);
         return error;
 }
index 225ca881a923265904236331a4869ffc91ac0d8b..b6f068e911d4f165ded1a1a8c94f1998bd3837ca 100644 (file)
 #include <linux/string.h>
 #include <asm/uaccess.h>
 
-#include <linux/coda_namecache.h>
 #include <linux/coda.h>
 #include <linux/coda_linux.h>
 #include <linux/coda_cnode.h>
 #include <linux/coda_psdev.h>
+#include <linux/coda_cache.h>
 
 /* file operations */
 static int coda_readpage(struct inode * inode, struct page * page);
@@ -31,6 +31,8 @@ static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, lo
 static int coda_file_mmap(struct file * file, struct vm_area_struct * vma);
 
 /* exported from this file */
+int coda_fsync(struct file *, struct dentry *dentry);
+
 struct inode_operations coda_file_inode_operations = {
        &coda_file_operations,  /* default file operations */
        NULL,                   /* create */
@@ -64,7 +66,11 @@ struct file_operations coda_file_operations = {
        coda_file_mmap,         /* mmap */
        coda_open,              /* open */
        coda_release,           /* release */
-       NULL,                   /* fsync */
+       coda_fsync,             /* fsync */
+       NULL,                   /* fasync */
+       NULL,                   /* check_media_change */
+       NULL,                   /* revalidate */
+       NULL                    /* lock */
 };
 
 /*  File file operations */
@@ -181,8 +187,44 @@ static ssize_t coda_file_write(struct file *coda_file, const char *buff,
         return result;
 }
 
+int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
+{
+        struct cnode *cnp;
+       struct inode *coda_inode = coda_dentry->d_inode;
+        struct inode *cont_inode = NULL;
+        struct file  cont_file;
+       struct dentry cont_dentry;
+        int result = 0;
+        ENTRY;
+
+       if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
+             S_ISLNK(coda_inode->i_mode)))
+               return -EINVAL;
+
+        cnp = ITOC(coda_inode);
+        CHECK_CNODE(cnp);
+
+        cont_inode = cnp->c_ovp;
+        if ( cont_inode == NULL ) {
+                printk("coda_file_write: cached inode is 0!\n");
+                return -1; 
+        }
+
+        coda_prepare_openfile(coda_inode, coda_file, cont_inode, 
+                             &cont_file, &cont_dentry);
+
+       down(&cont_inode->i_sem);
+
+        result = file_fsync(&cont_file ,&cont_dentry);
+       if ( result == 0 ) {
+               result = venus_fsync(coda_inode->i_sb, &(cnp->c_fid));
+       }
 
+       up(&cont_inode->i_sem);
 
+        coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
+        return result;
+}
 /* 
  * support routines
  */
diff --git a/fs/coda/namecache.c b/fs/coda/namecache.c
deleted file mode 100644 (file)
index 08f1ee9..0000000
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- * Cache operations for Coda.
- * Original version: (C) 1996 Peter Braam 
- * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon encourages users of this code to contribute improvements
- * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
- */
-
-/*
- * This module contains the routines to implement the CFS name cache. The
- * purpose of this cache is to reduce the cost of translating pathnames 
- * into Vice FIDs. Each entry in the cache contains the name of the file,
- * the vnode (FID) of the parent directory, and the cred structure of the
- * user accessing the file.
- *
- * The first time a file is accessed, it is looked up by the local Venus
- * which first insures that the user has access to the file. In addition
- * we are guaranteed that Venus will invalidate any name cache entries in
- * case the user no longer should be able to access the file. For these
- * reasons we do not need to keep access list information as well as a
- * cred structure for each entry.
- *
- * The table can be accessed through the routines cnc_init(), cnc_enter(),
- * cnc_lookup(), cnc_rmfidcred(), cnc_rmfid(), cnc_rmcred(), and cnc_purge().
- * There are several other routines which aid in the implementation of the
- * hash table.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <asm/segment.h>
-#include <linux/string.h>
-
-#include <linux/coda.h>
-#include <linux/coda_linux.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
-
-int cfsnc_use;
-
-static struct cfscache * cfsnc_find(struct cnode *dcp, const char * name, int namelen, int hash);
-static void cfsnc_remove(struct cfscache *cncp);
-static inline int  nchash(const char *, int, struct cnode *);
-static inline int ncmatch(struct cfscache *, const char *, int, 
-                          struct cnode *);
-static inline void hashins(struct cfscache *a, struct cfscache *pred);
-static inline void hashrem(struct cfscache *a);
-static inline void hashnull(struct cfscache *);
-static inline void lrurem(struct cfscache *a);
-static inline void lruins(struct cfscache *a, struct cfscache *pred);
-static void cfsnc_gather_stats(void);
-
-
-/* externals */
-extern int coda_fideq(ViceFid *fid1, ViceFid *fid2);
-extern int coda_debug;
-extern int coda_print_entry;
-extern struct super_block *coda_super_block;
-
-
-
-/* 
- * Declaration of the name cache data structure.
- */
-
-int    cfsnc_use = 0;                   /* Indicate use of CFS Name Cache */
-int    cfsnc_size = CFSNC_CACHESIZE;    /* size of the cache */
-int    cfsnc_hashsize = CFSNC_HASHSIZE; /* size of the primary hash */
-int     cfsnc_flushme = 0;
-int     cfsnc_procsize = 0;
-static  int cfsnc_force = 0;
-
-struct cfshash {
-       struct cfscache *hash_next, *hash_prev;
-       int              length;
-};
-
-struct cfslruhead {
-        struct cfscache *dummy1, *dummy2;
-        struct cfscache *lru_next, *lru_prev;
-};
-
-struct         cfscache *cfsncheap;    /* pointer to the cache entries */
-struct cfshash  *cfsnchash;    /* hash table of cfscache pointers */
-struct cfslruhead  cfsnc_lru;  /* head of lru chain; prev = lru */
-
-struct cfsnc_statistics cfsnc_stat;    /* Keep various stats */
-
-#define TOTAL_CACHE_SIZE       (sizeof(struct cfscache) * cfsnc_size)
-#define TOTAL_HASH_SIZE        (sizeof(struct cfshash)  * cfsnc_hashsize)
-int cfsnc_initialized = 0;      /* Initially the cache has not been initialized */
-
-/* 
- * for testing purposes
- */
-int cfsnc_debug = 1;
-
-
-/*
- * Auxillary routines -- shouldn't be entry points
- */
-
-
-/*
- * Hash function for the primary hash.
- * First try -- (first + last letters + length + (int)cp) mod size
- * 2nd try -- same, except dir fid.vnode instead of cp
- */
-static inline int  
-nchash(const char *name, int namelen, struct cnode *cp)
-{
-    return ((name[0] + name[namelen-1] + 
-             namelen + (int)(cp)) & (cfsnc_hashsize-1));   
-}
-
-/* matching function */
-static inline int ncmatch(struct cfscache *cp, const char *name, int namelen,
-                          struct cnode *dcp)
-{
-    return     ((namelen == cp->namelen) && (dcp == cp->dcp) && 
-                (memcmp(cp->name,name,namelen) == 0));
-}
-
-/* insert  a  behind  pred */
-static inline void hashins(struct cfscache *a, struct cfscache *pred)
-{
-       a->hash_next = pred->hash_next;
-       pred->hash_next->hash_prev= a;
-       pred->hash_next = a;
-       a->hash_prev = pred;
-}
-
-static inline void hashrem(struct cfscache *a) 
-{
-       a->hash_prev->hash_next = a->hash_next;
-       a->hash_next->hash_prev = a->hash_prev;
-}
-
-static inline void hashnull(struct cfscache *elem) {
-       elem->hash_next = elem;
-       elem->hash_prev = elem;
-}
-
-static inline void lrurem(struct cfscache *a) 
-{
-       a->lru_prev->lru_next = a->lru_next;
-       a->lru_next->lru_prev = a->lru_prev;
-}
-
-static inline void lruins(struct cfscache *a, struct cfscache *pred)
-{
-       pred->lru_next->lru_prev= a;
-       a->lru_next = pred->lru_next;
-       
-       a->lru_prev = pred;
-       pred->lru_next = a;
-}
-
-static struct cfscache *
-cfsnc_find(struct cnode *dcp, const char * name, int namelen, int hash)
-{
-       /* 
-        * hash to find the appropriate bucket, look through the chain
-        * for the right entry 
-        */
-       register struct cfscache *cncp;
-       int count = 1;
-
-       CDEBUG(D_CACHE, "dcp 0x%x, name %s, len %d, hash %d\n",
-                          (int)dcp, name, namelen, hash);
-
-       for (cncp  = cfsnchash[hash].hash_next; 
-            cncp != (struct cfscache *)&cfsnchash[hash];
-            cncp  = cncp->hash_next, count++) 
-       {
-
-           if (ncmatch(cncp, name, namelen, dcp))
-           { 
-               cfsnc_stat.Search_len += count;
-               CDEBUG(D_CACHE, "dcp 0x%x,found.\n", (int) dcp);
-               return(cncp);
-                       
-           }
-       }
-       CDEBUG(D_CACHE, "dcp 0x%x,not found.\n", (int) dcp);
-       return((struct cfscache *)0);
-}
-
-static void
-cfsnc_remove(struct cfscache *cncp)
-{
-       /* 
-        * remove an entry -- VN_RELE(cncp->dcp, cp), crfree(cred),
-        * remove it from it's hash chain, and
-        * place it at the head of the lru list.
-        */
-    CDEBUG(D_CACHE, "remove %s from parent %lx.%lx.%lx\n",
-           cncp->name, (cncp->dcp)->c_fid.Volume,
-           (cncp->dcp)->c_fid.Vnode, (cncp->dcp)->c_fid.Unique);
-
-       hashrem(cncp);
-       hashnull(cncp);         /* have it be a null chain */
-
-       /* VN_RELE(CTOV(cncp->dcp));  */
-       iput(CTOI(cncp->cp)); 
-       /* crfree(cncp->cred);  */
-
-       memset(DATA_PART(cncp), 0 ,DATA_SIZE);
-       cncp->cp = NULL;
-       cncp->dcp = (struct cnode *) 0;
-
-       /* Put the null entry just after the least-recently-used entry */
-       lrurem(cncp);
-       lruins(cncp, cfsnc_lru.lru_prev);
-}
-
-
-/*
- * Entry points for the CFS Name Cache
- */
-
-/*  
- * Initialize the cache, the LRU structure and the Hash structure(s)
- */
-void
-cfsnc_init(void)
-{
-    register int i;
-
-    /* zero the statistics structure */
-    cfsnc_procsize =  10000 * cfsnc_hashsize + cfsnc_size;
-    memset(&cfsnc_stat, 0, (sizeof(struct cfsnc_statistics)));
-    
-    CODA_ALLOC(cfsncheap, struct cfscache *, TOTAL_CACHE_SIZE);
-    CODA_ALLOC(cfsnchash, struct cfshash *, TOTAL_HASH_SIZE);
-    
-    cfsnc_lru.lru_next = cfsnc_lru.lru_prev = (struct cfscache *)&cfsnc_lru; 
-    
-    /* initialize the heap */
-    for (i=0; i < cfsnc_size; i++) {   
-       lruins(&cfsncheap[i], (struct cfscache *) &cfsnc_lru);
-       hashnull(&cfsncheap[i]);
-       cfsncheap[i].cp = cfsncheap[i].dcp = (struct cnode *)0;
-    }
-    
-    for (i=0; i < cfsnc_hashsize; i++) {       /* initialize the hashtable */
-       hashnull((struct cfscache *)&cfsnchash[i]);
-       cfsnchash[i].length=0;  /* bucket length */
-    }
-    
-    cfsnc_initialized = 1;
-    CDEBUG(D_CACHE, "cfsnc_initialized is now 1.\n");
-}
-
-/*
- * Enter a new (dir cnode, name) pair into the cache, updating the
- * LRU and Hash as needed.
- */
-
-void
-cfsnc_enter(struct cnode *dcp, register const char *name, int namelen, struct cnode *cp)
-{
-    register struct cfscache *cncp;
-    register int hash;
-    
-    if (cfsnc_use == 0)                        /* Cache is off */
-       return;
-    
-    CDEBUG(D_CACHE, "dcp 0x%x cp 0x%x name %s, ind 0x%x \n",
-          (int)dcp, (int)cp, name, (int)cp->c_vnode); 
-       
-    if (namelen > CFSNC_NAMELEN) {
-        CDEBUG(D_CACHE, "long name enter %s\n",name);
-           cfsnc_stat.long_name_enters++;      /* record stats */
-       return;
-    }
-    
-    hash = nchash(name, namelen, dcp);
-       CDEBUG(D_CACHE, "Calling find with name %s, dcp %d, hash %d\n",
-              name, (int) dcp, (int) hash);
-
-    cncp = cfsnc_find(dcp, name, namelen, hash);
-    if (cncp != (struct cfscache *) 0) {       
-       printk("cfsnc_enter: Duplicate cache entry; tell Peter.\n");
-       cfsnc_stat.dbl_enters++;                /* duplicate entry */
-       return;
-    }
-    
-    cfsnc_stat.enters++;               /* record the enters statistic */
-    
-    /* Grab the lru element in the lru chain */
-    cncp = cfsnc_lru.lru_prev;
-    
-    lrurem(cncp);      /* remove it from the lists */
-    
-    /* if cncp is on hash list remove it */
-    if ( cncp->dcp != (struct cnode *) 0 ) {
-       /* We have to decrement the appropriate hash bucket length
-          here, so we have to find the hash bucket */
-       cfsnchash[nchash(cncp->name, cncp->namelen, cncp->dcp)].length--;
-       cfsnc_stat.lru_rm++;    /* zapped a valid entry */
-       hashrem(cncp);
-       iput(CTOI(cncp->cp));
-       /* VN_RELE(CTOV(cncp->dcp));  */
-       /* crfree(cncp->cred); */
-    }
-    /*
-     * Put a hold on the current vnodes and fill in the cache entry.
-     */
-    iget((CTOI(cp))->i_sb, CTOI(cp)->i_ino);
-    /* VN_HOLD(CTOV(dcp)); */
-    /* XXXX crhold(cred); */
-    cncp->dcp = dcp;
-    cncp->cp = cp;
-    cncp->namelen = namelen;
-    /* cncp->cred = cred; */
-    
-    memcpy(cncp->name, name, (unsigned)namelen);
-    
-    /* Insert into the lru and hash chains. */
-    
-    lruins(cncp, (struct cfscache *) &cfsnc_lru);
-    hashins(cncp, (struct cfscache *)&cfsnchash[hash]);
-    cfsnchash[hash].length++;                      /* Used for tuning */
-    CDEBUG(D_CACHE, "Entering:\n");
-    coda_print_ce(cncp);
-}
-
-/*
- * Find the (dir cnode, name) pair in the cache, if it's cred
- * matches the input, return it, otherwise return 0
- */
-
-struct cnode *
-cfsnc_lookup(struct cnode *dcp, register const char *name, int namelen)
-{
-       register int hash;
-       register struct cfscache *cncp;
-        /* this should go into a callback funcntion for /proc/sys
-           don't know how at the moment? */  
-       if (cfsnc_flushme == 1) {
-               cfsnc_flush();
-               cfsnc_flushme = 0;
-       }
-       
-       if (cfsnc_procsize != 10000*cfsnc_hashsize + cfsnc_size ) {
-               int hsh = cfsnc_procsize/10000;
-               int siz = cfsnc_procsize%10000;
-               int rc;
-               
-               if ( (hsh > 1) && (siz > 2) ) {
-                       rc = cfsnc_resize(hsh, siz);
-                       if ( !rc ) {
-                               printk("Coda:cache size (hash,size) (%d,%d)\n",
-                                       hsh, siz);
-                       } else {
-                               printk("Coda: cache resize failed\n");
-                       }
-               }
-       }
-
-       if (cfsnc_use == 0)                     /* Cache is off */
-               return((struct cnode *) 0);
-
-       if (namelen > CFSNC_NAMELEN) {
-        CDEBUG(D_CACHE,"long name lookup %s\n",name);
-               cfsnc_stat.long_name_lookups++;         /* record stats */
-               return((struct cnode *) 0);
-       }
-
-       /* Use the hash function to locate the starting point,
-          then the search routine to go down the list looking for
-          the correct cred.
-        */
-
-       hash = nchash(name, namelen, dcp);
-       CDEBUG(D_CACHE, "Calling find with name %s, dcp %d, hash %d\n",
-              name, (int) dcp, (int) hash);
-       cncp = cfsnc_find(dcp, name, namelen, hash);
-       if (cncp == (struct cfscache *) 0) {
-               cfsnc_stat.misses++;                    /* record miss */
-               return((struct cnode *) 0);
-       }
-
-       cfsnc_stat.hits++;
-
-       /* put this entry at the mru end of the LRU */
-       lrurem(cncp);
-       lruins(cncp, (struct cfscache *) &cfsnc_lru);
-
-       /* move it to the front of the hash chain */
-       /* don't need to change the hash bucket length */
-       hashrem(cncp);
-       hashins(cncp, (struct cfscache *) &cfsnchash[hash]);
-
-       CDEBUG(D_CACHE, "lookup: dcp 0x%x, name %s,  cp 0x%x\n",
-           (int) dcp, name,  (int) cncp->cp);
-
-       return(cncp->cp);
-}
-
-/*
- * Remove all entries with a parent which has the input fid.
- */
-
-void
-cfsnc_zapParentfid(ViceFid *fid)
-{
-       /* To get to a specific fid, we might either have another hashing
-          function or do a sequential search through the cache for the
-          appropriate entries. The later may be acceptable since I don't
-          think callbacks or whatever Case 1 covers are frequent occurences.
-        */
-       register struct cfscache *cncp, *ncncp;
-       register int i;
-
-       if (cfsnc_use == 0)                     /* Cache is off */
-               return;
-
-       CDEBUG(D_CACHE, " fid 0x%lx, 0x%lx, 0x%lx \n",
-           fid->Volume, fid->Vnode, fid->Unique);
-
-       cfsnc_stat.zapPfids++;
-
-       for (i = 0; i < cfsnc_hashsize; i++) {
-
-               /*
-                * Need to save the hash_next pointer in case we remove the
-                * entry. remove causes hash_next to point to itself.
-                */
-
-               for (cncp = cfsnchash[i].hash_next; 
-                    cncp != (struct cfscache *) &cfsnchash[i];
-                    cncp = ncncp) {
-                       ncncp = cncp->hash_next;
-                       if ( coda_fideq(&cncp->dcp->c_fid, fid) ) {
-                               cfsnchash[i].length--;   /* Used for tuning */
-                               cfsnc_remove(cncp); 
-                           }
-                    }
-       }
-}
-
-/*
- * Remove all entries which have the same fid as the input
- */
-void
-cfsnc_zapfid(ViceFid *fid)
-{
-       /* See comment for zapParentfid. This routine will be used
-          if attributes are being cached. 
-        */
-       register struct cfscache *cncp, *ncncp;
-       register int i;
-
-       if (cfsnc_use == 0)                     /* Cache is off */
-               return;
-
-       CDEBUG(D_CACHE, "Zapfid: fid 0x%lx, 0x%lx, 0x%lx \n",
-           fid->Volume, fid->Vnode, fid->Unique);
-
-       cfsnc_stat.zapFids++;
-
-       for (i = 0; i < cfsnc_hashsize; i++) {
-               for (cncp = cfsnchash[i].hash_next; 
-                    cncp != (struct cfscache *) &cfsnchash[i];
-                    cncp = ncncp) {
-                       ncncp = cncp->hash_next;
-                       if (coda_fideq(&(cncp->cp->c_fid), fid)) {
-                               CDEBUG(D_CACHE, "Found cncp: name %s\n", cncp->name);
-                               cfsnchash[i].length--;   /* Used for tuning */
-                               cfsnc_remove(cncp); 
-                           }
-                    }
-       }
-}
-
-
-/*
- * Remove all entries which have the (dir vnode, name) pair
- */
-void
-cfsnc_zapfile(struct cnode *dcp, register const char *name, int length)
-{
-       /* use the hash function to locate the file, then zap all
-          entries of it regardless of the cred.
-        */
-       register struct cfscache *cncp;
-       int hash;
-
-       if (cfsnc_use == 0)                     /* Cache is off */
-               return;
-
-       CDEBUG(D_CACHE,"Zapfile: dcp 0x%x name %s \n",
-           (int) dcp, name);
-
-       if (length > CFSNC_NAMELEN) {
-               cfsnc_stat.long_remove++;               /* record stats */
-               return;
-       }
-
-       cfsnc_stat.zapFile++;
-
-       hash = nchash(name, length,  dcp);
-    /* remove entries: remember they might exist for more than a 
-       single cred */
-       while ( (cncp = cfsnc_find(dcp, name, length, hash)) != NULL ) {
-         cfsnchash[hash].length--;       
-         cfsnc_remove(cncp);
-       }
-}
-
-/* 
- * Remove all the entries for a particular user. Used when tokens expire.
- * A user is determined by his/her effective user id (id_uid).
- */
-
-void
-cfsnc_purge_user(struct CodaCred *cred)
-{
-       /* I think the best approach is to go through the entire cache
-          via HASH or whatever and zap all entries which match the
-          input cred. Or just flush the whole cache.
-          It might be best to go through on basis of LRU since cache
-          will almost always be full and LRU is more straightforward.
-        */
-
-       register struct cfscache *cncp;
-       int hash;
-
-       if (cfsnc_use == 0)                     /* Cache is off */
-               return;
-
-       CDEBUG(D_CACHE,"ZapDude: uid %ld\n",cred->cr_uid);
-       cfsnc_stat.zapUsers++;
-
-       for (cncp = cfsnc_lru.lru_next;
-            cncp != (struct cfscache *) &cfsnc_lru;
-            cncp = cncp->lru_next) {
-
-               if ((CFSNC_VALID(cncp)) &&
-                  ((cncp->cred)->cr_uid == cred->cr_uid)) {
-                       /* Seems really ugly, but we have to decrement the appropriate
-                          hash bucket length here, so we have to find the hash bucket
-                          */
-                       hash = nchash(cncp->name, cncp->namelen, cncp->dcp);
-                       cfsnchash[hash].length--;     /* For performance tuning */
-
-                       cfsnc_remove(cncp); 
-               }
-       }
-}
-
-/*
- * Flush the entire name cache. In response to a flush of the Venus cache.
- */
-
-void
-cfsnc_flush(void)
-{
-       /* One option is to deallocate the current name cache and
-          call init to start again. Or just deallocate, then rebuild.
-          Or again, we could just go through the array and zero the 
-          appropriate fields. 
-        */
-       
-       /* 
-        * Go through the whole lru chain and kill everything as we go.
-        * I don't use remove since that would rebuild the lru chain
-        * as it went and that seemed unneccesary.
-        */
-       register struct cfscache *cncp;
-       int i;
-
-       if ((cfsnc_use == 0 || cfsnc_initialized == 0) && (cfsnc_force == 0) )
-               return;
-
-       cfsnc_stat.Flushes++;
-
-       for (cncp = cfsnc_lru.lru_next;
-            cncp != (struct cfscache *) &cfsnc_lru;
-            cncp = cncp->lru_next) {
-               if ( cncp->cp ) {
-                       hashrem(cncp);  /* only zero valid nodes */
-                       hashnull(cncp);
-                       iput(CTOI(cncp->cp));  
-                       /* crfree(cncp->cred);  */
-                       memset(DATA_PART(cncp), 0, DATA_SIZE);
-               }
-       }
-
-       for (i = 0; i < cfsnc_hashsize; i++)
-         cfsnchash[i].length = 0;
-}
-
-/*
- * This routine replaces a ViceFid in the name cache with another.
- * It is added to allow Venus during reintegration to replace 
- * locally allocated temp fids while disconnected with global fids 
- * even when the reference count on those fids are not zero.
- */
-void
-cfsnc_replace(ViceFid *f1, ViceFid *f2)
-{
-        /* 
-        * Replace f1 with f2 throughout the name cache
-        */
-       int hash;
-       register struct cfscache *cncp;
-
-       CDEBUG(D_CACHE, 
-    "cfsnc_replace fid_1 = (%lx.%lx.%lx) and fid_2 = (%lx.%lx.%lx)\n",
-           f1->Volume, f1->Vnode, f1->Unique, 
-           f2->Volume, f2->Vnode, f2->Unique);
-
-       for (hash = 0; hash < cfsnc_hashsize; hash++) {
-               for (cncp = cfsnchash[hash].hash_next; 
-                    cncp != (struct cfscache *) &cfsnchash[hash];
-                    cncp = cncp->hash_next) {
-                       if (!memcmp(&cncp->cp->c_fid, f1, sizeof(ViceFid))) {
-                           memcpy(&cncp->cp->c_fid, f2, sizeof(ViceFid));
-                           continue;   /* no need to check cncp->dcp now */
-                       }
-                       if (!memcmp(&cncp->dcp->c_fid, f1, sizeof(ViceFid)))
-                           memcpy(&cncp->dcp->c_fid, f2, sizeof(ViceFid));
-                    }
-       }
-}
-
-/*
- * Debugging routines
- */
-
-/* 
- * This routine should print out all the hash chains to the console.
- */
-
-void
-print_cfsnc(void)
-{
-       int hash;
-       register struct cfscache *cncp;
-
-       for (hash = 0; hash < cfsnc_hashsize; hash++) {
-               printk("\nhash %d\n",hash);
-
-               for (cncp = cfsnchash[hash].hash_next; 
-                    cncp != (struct cfscache *)&cfsnchash[hash];
-                    cncp = cncp->hash_next) {
-                       printk("cp 0x%x dcp 0x%x cred 0x%x name %s ino %d count %d dev %d\n",
-                                 (int)cncp->cp, (int)cncp->dcp,
-                                 (int)cncp->cred, cncp->name, CTOI(cncp->cp)->i_count, CTOI(cncp->cp)->i_count, CTOI(cncp->cp)->i_dev);
-                    }
-       }
-}
-
-int
-cfsnc_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
-        int hash;
-        int len=0;
-        off_t pos=0;
-        off_t begin;
-       struct cfscache *cncp;
-        char tmpbuf[80];
-
-        if (offset < 80) 
-              len += sprintf(buffer, "%-79s\n",
-      "hash  len   volume    vnode   unique             name        ino       pino ct");
-       if ( !cfsnc_initialized ) {
-               *start = buffer;
-               return len;
-       }
-        pos = 80;
-       for (hash = 0; hash < cfsnc_hashsize; hash++) {
-               for (cncp = cfsnchash[hash].hash_next; 
-                    cncp != (struct cfscache *)&cfsnchash[hash];
-                    cncp = cncp->hash_next) {
-                       pos += 80;
-                       if (pos < offset)
-                                continue;
-                       sprintf(tmpbuf, "%4d  %3d %8x %8x %8x %16s %10ld %10ld %2d", 
-                               hash, cfsnchash[hash].length, (int) cncp->cp->c_fid.Volume, 
-                               (int) cncp->cp->c_fid.Vnode, (int) cncp->cp->c_fid.Unique , cncp->name, 
-                               CTOI(cncp->cp)->i_ino, 
-                               CTOI(cncp->dcp)->i_ino, 
-                               CTOI(cncp->cp)->i_count);
-                       len += sprintf(buffer+len, "%-79s\n", tmpbuf);
-                       if(len >= length)
-                                break;
-                       }
-                       if(len>= length)
-                               break;
-               }
-        begin = len - (pos - offset);
-        *start = buffer + begin;
-        len -= begin;
-        if(len>length)
-                len = length;
-        return len;
-} 
-
-int
-cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
-        int len=0;
-        off_t begin;
-       
-       cfsnc_gather_stats();
-
-       /* this works as long as we are below 1024 characters! */    
-    len += sprintf(buffer,"Coda minicache statistics\n\n");
-    len += sprintf(buffer+len, "cfsnc_hits : %d\n", cfsnc_stat.hits);
-    len += sprintf(buffer+len, "cfsnc_misses : %d\n", cfsnc_stat.misses);
-    len += sprintf(buffer+len, "cfsnc_enters : %d\n", cfsnc_stat.enters);
-    len += sprintf(buffer+len, "cfsnc_dbl_enters : %d\n", cfsnc_stat.dbl_enters);
-    len += sprintf(buffer+len, "cfsnc_long_name_enters : %d\n", cfsnc_stat.long_name_enters);
-    len += sprintf(buffer+len, "cfsnc_long_name_lookups : %d\n", cfsnc_stat.long_name_lookups);
-    len += sprintf(buffer+len, "cfsnc_long_remove : %d\n", cfsnc_stat.long_remove);
-    len += sprintf(buffer+len, "cfsnc_lru_rm : %d\n", cfsnc_stat.lru_rm);
-    len += sprintf(buffer+len, "cfsnc_zapPfids : %d\n", cfsnc_stat.zapPfids);
-    len += sprintf(buffer+len, "cfsnc_zapFids : %d\n", cfsnc_stat.zapFids);
-    len += sprintf(buffer+len, "cfsnc_zapFile : %d\n", cfsnc_stat.zapFile);
-    len += sprintf(buffer+len, "cfsnc_zapUsers : %d\n", cfsnc_stat.zapUsers);
-    len += sprintf(buffer+len, "cfsnc_Flushes : %d\n", cfsnc_stat.Flushes);
-    len += sprintf(buffer+len, "cfsnc_SumLen : %d\n", cfsnc_stat.Sum_bucket_len);
-    len += sprintf(buffer+len, "cfsnc_Sum2Len : %d\n", cfsnc_stat.Sum2_bucket_len);
-    len += sprintf(buffer+len,  "cfsnc_# 0 len : %d\n", cfsnc_stat.Num_zero_len);
-    len += sprintf(buffer+len,  "cfsnc_MaxLen : %d\n", cfsnc_stat.Max_bucket_len);
-    len += sprintf(buffer+len,  "cfsnc_SearchLen : %d\n", cfsnc_stat.Search_len);
-               begin =  offset;
-               *start = buffer + begin;
-               len -= begin;
-
-        if(len>length)
-                len = length;
-       if (len< 0)
-               len = 0;
-        return len;
-} 
-
-
-
-void
-coda_print_ce(struct cfscache *ce) 
-{
-CDEBUG(D_CACHE, "cp 0x%x, dcp 0x%x, name %s, inod 0x%x, ino %d, count %d, dev %d\n",
-        (int)ce->cp, (int)ce->dcp, ce->name, (int)CTOI(ce->cp),(int)CTOI(ce->cp)->i_ino,  CTOI(ce->cp)->i_count, CTOI(ce->cp)->i_dev);
-}
-
-static void
-cfsnc_gather_stats(void)
-{
-    int i, max = 0, sum = 0, temp, zeros = 0, ave, n;
-
-       for (i = 0; i < cfsnc_hashsize; i++) {
-         if (cfsnchash[i].length) {
-           sum += cfsnchash[i].length;
-         } else {
-           zeros++;
-         }
-
-         if (cfsnchash[i].length > max)
-           max = cfsnchash[i].length;
-       }
-
-/*
- * When computing the Arithmetic mean, only count slots which 
- * are not empty in the distribution.
- */
-        cfsnc_stat.Sum_bucket_len = sum;
-        cfsnc_stat.Num_zero_len = zeros;
-        cfsnc_stat.Max_bucket_len = max;
-
-       if ((n = cfsnc_hashsize - zeros) > 0) 
-         ave = sum / n;
-       else
-         ave = 0;
-
-       sum = 0;
-       for (i = 0; i < cfsnc_hashsize; i++) {
-         if (cfsnchash[i].length) {
-           temp = cfsnchash[i].length - ave;
-           sum += temp * temp;
-         }
-       }
-        cfsnc_stat.Sum2_bucket_len = sum;
-}
-
-/*
- * The purpose of this routine is to allow the hash and cache sizes to be
- * changed dynamically. This should only be used in controlled environments,
- * it makes no effort to lock other users from accessing the cache while it
- * is in an improper state (except by turning the cache off).
- */
-int
-cfsnc_resize(int hashsize, int heapsize)
-{
-    if ( !cfsnc_use )
-           return 0;
-
-    if ((hashsize % 2) || (heapsize % 2)) { /* Illegal hash or cache sizes */
-           return(EINVAL);
-    }                 
-    
-    cfsnc_use = 0;                       /* Turn the cache off */
-    cfsnc_force = 1;                     /* otherwise we can't flush */
-    
-    cfsnc_flush();                       /* free any cnodes in the cache */
-    cfsnc_force = 0;
-    
-    /* WARNING: free must happen *before* size is reset */
-    CODA_FREE(cfsncheap,TOTAL_CACHE_SIZE);
-    CODA_FREE(cfsnchash,TOTAL_HASH_SIZE);
-    
-    cfsnc_hashsize = hashsize;
-    cfsnc_size = heapsize;
-    
-    cfsnc_init();                        /* Set up a cache with the new size */
-    
-    cfsnc_use = 1;                       /* Turn the cache back on */
-    return(0);
-}
-
-
-
index c24008cd668bb0fea29270edeb12de15858f0086..a63abdeaa4d1384f5ebccdff2619c9de274fe770 100644 (file)
 #include <linux/string.h>
 #include <asm/uaccess.h>
 
-#include <linux/coda_namecache.h>
 #include <linux/coda.h>
 #include <linux/coda_linux.h>
 #include <linux/coda_cnode.h>
+#include <linux/coda_cache.h>
 #include <linux/coda_psdev.h>
 
 /* pioctl ops */
index cd591d3e9b6269474bf016dff69bfeeeaff5187a..70842b8fc08dd111f9597de5d11b30fff4e68f12 100644 (file)
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/system.h>
+#include <asm/poll.h>
 #include <asm/uaccess.h>
 
 #include <linux/coda.h>
 #include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_cache.h>
 #include <linux/coda_sysctl.h>
 
 
+/*
+ * Where is the prototype?
+ */
+
+int proc_register_dynamic(struct proc_dir_entry * dir,
+                         struct proc_dir_entry * dp);
+
 /* 
  * Coda stuff
  */
 extern struct file_system_type coda_fs_type;
-extern int coda_downcall(int opcode, struct outputArgs *out);
 extern int init_coda_fs(void);
 extern int cfsnc_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
 extern int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy);
 
 /* statistics */
 struct coda_upcallstats coda_callstats;
-
+int           coda_hard = 0;  /* introduces a timeout on upcalls */
+unsigned long coda_timeout = 10; /* .. secs, then signals will dequeue */
 extern struct coda_sb_info coda_super_info[MAX_CODADEVS];
 struct vcomm psdev_vcomm[MAX_CODADEVS];
 
-/*
- * Device operations
- */
+/* queue stuff for the messages */
+static inline void init_queue(struct queue *head)
+{
+       head->forw = head;
+       head->back = head;
+}
+
+static inline struct vmsg *q_getnext(struct queue *elt)
+{
+       return (struct vmsg *)(elt->forw);
+}
+
+static inline int q_end(struct vmsg *msg, struct queue *queue)
+{
+       return (struct queue *)msg == queue;
+}
+
+static inline int q_empty(struct queue *queue)
+{
+       return queue->forw == queue;
+}
+
+/* insert before head, ie. at the tail */
+void coda_q_insert(struct queue *el, struct queue *head)
+{
+       el->forw = head->back->forw;
+       el->back = head->back;
+       head->back->forw = el;
+       head->back = el;
+}
 
+void coda_q_remove(struct queue *el)
+{
+       el->forw->back = el->back;
+       el->back->forw = el->forw;
+}
 
 static struct vcomm *coda_psdev2vcomm(struct file *file)
 {
@@ -75,6 +115,10 @@ static struct vcomm *coda_psdev2vcomm(struct file *file)
        return vcp;
 }
        
+/*
+ * Device operations
+ */
+
 
 static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
 {
@@ -85,7 +129,7 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
                return -ENXIO;
 
        poll_wait(&(vcp->vc_waitq), wait);
-       if (!EMPTY(vcp->vc_pending))
+       if (!q_empty(&(vcp->vc_pending)))
                 mask |= POLLIN | POLLRDNORM;
 
        return mask;
@@ -101,7 +145,6 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
 {
         struct vcomm *vcp = coda_psdev2vcomm(file);
         struct vmsg *vmp;
-        struct outputArgs *out;
        int error = 0;
        int size;
         u_long uniq;
@@ -111,7 +154,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
         if (!vcp)
                 return -ENXIO;
 
-        /* Peek at the opcode, unique id */
+        /* Peek at the opcode, uniquefier */
        if (copy_from_user(opcodebuf, buf, 2 * sizeof(u_long)))
                return -EFAULT;
        opcode = opcodebuf[0];
@@ -121,67 +164,69 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
               current->pid, opcode, uniq);
 
         if (DOWNCALL(opcode)) {
-                struct outputArgs pbuf;
-
+               struct super_block *sb = NULL;
+                union outputArgs *dcbuf;
+               size = sizeof(*dcbuf);
+
+               sb = vcp->vc_sb;
+               if ( !sb ) {
+                       printk("coda_psdev_write: downcall, no SB!\n");
+                       return count;
+               }
                CDEBUG(D_PSDEV, "handling downcall\n");
 
-              /* get the rest of the data. */
-               size = sizeof(pbuf);
-               if  ( count < sizeof(pbuf) ) {
-                       printk("Coda: downcall opc %ld, uniq %ld, not enough!\n",
+               if  ( count < sizeof(struct cfs_out_hdr) ) {
+                       printk("coda_downcall opc %ld uniq %ld, not enough!\n",
                               opcode, uniq);
-                       size =count;
-               } else if ( count > sizeof(pbuf) ) {
+                       return count;
+               }
+               CODA_ALLOC(dcbuf, union outputArgs *, size);
+               if ( count > size ) {
                        printk("Coda: downcall opc %ld, uniq %ld, too much!",
                               opcode, uniq);
-                       size = sizeof(pbuf);
+                       count = size;
                }
-               if (copy_from_user(&pbuf, buf, size))
+               if (copy_from_user(dcbuf, buf, count))
                        return -EFAULT;
 
-             /* what errors for coda_downcall should be
-             * sent to Venus ? 
-             */
-               error = coda_downcall(opcode, &pbuf);
+               /* what downcall errors does Venus handle ? */
+               error = coda_downcall(opcode, dcbuf, sb);
+
                if ( error) {
                        printk("psdev_write: coda_downcall error: %d\n", 
                               error);
                        return 0;
                }
+               CODA_FREE(dcbuf, size);
                return count;
         }
 
         
         /* Look for the message on the processing queue. */
-        for (vmp = (struct vmsg *)GETNEXT(vcp->vc_processing);
-            !EOQ(vmp, vcp->vc_processing);
-             vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) {
-               if (vmp->vm_unique == uniq) break;
-               CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", uniq);
+        for (vmp = q_getnext(&(vcp->vc_processing));
+            !q_end(vmp, &(vcp->vc_processing));
+             vmp = q_getnext(&(vmp->vm_chain))) {
+               if (vmp->vm_unique == uniq) {
+                       break;
+                       CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", uniq);
+               }
        }
-        if (EOQ(vmp, vcp->vc_processing)) {
+        if (q_end(vmp, &(vcp->vc_processing))) {
                printk("psdev_write: msg (%ld, %ld) not found\n", 
                       opcode, uniq);
                return(-ESRCH);
         }
 
         /* Remove the message from the processing queue */
-        REMQUE(vmp->vm_chain);
+        coda_q_remove(&(vmp->vm_chain));
 
         /* move data into response buffer. */
-        /* Don't need to copy opcode and uniquifier. */
-        out = (struct outputArgs *)vmp->vm_data;
-        /* get the rest of the data. */
         if (vmp->vm_outSize < count) {
-                printk("Coda write: too much outs: %d, cnt: %d, opc: %ld, uniq: %ld.\n",
-                      vmp->vm_outSize, count, opcode, uniq);
-               wake_up_interruptible(&vmp->vm_sleep);  
-               return -EINVAL;
-        } else if (vmp->vm_outSize > count) {
-                printk("Coda write: too much outs: %d, cnt: %d, opc: %ld, uniq: %ld.\n",
+                printk("psdev_write: too much cnt: %d, cnt: %d, opc: %ld, uniq: %ld.\n",
                       vmp->vm_outSize, count, opcode, uniq);
+               count = vmp->vm_outSize; /* don't have more space! */
        }
-        if (copy_from_user(out, buf, count))
+        if (copy_from_user(vmp->vm_data, buf, count))
                return -EFAULT;
 
        /* adjust outsize. is this usefull ?? */
@@ -192,7 +237,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
               "Found! Count %d for (opc,uniq)=(%ld,%ld), vmsg at %x\n", 
                count, opcode, uniq, (int)&vmp);
 
-        wake_up_interruptible(&vmp->vm_sleep);
+        wake_up(&vmp->vm_sleep);
         return(count);  
 }
 
@@ -201,7 +246,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
  */
 
 static ssize_t coda_psdev_read(struct file * file, char * buf, 
-                           size_t count, loff_t *off)
+                              size_t count, loff_t *off)
 {
         struct vcomm *vcp = coda_psdev2vcomm(file);
         struct vmsg *vmp;
@@ -211,41 +256,39 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
               return -ENXIO;
         
         /* Get message at head of request queue. */
-        if (EMPTY(vcp->vc_pending)) {
-              return 0;        /* Nothing to read */
+        if (q_empty(&(vcp->vc_pending))) {
+              return 0;        
         }
     
-        vmp = (struct vmsg *)GETNEXT(vcp->vc_pending);
-        REMQUE(vmp->vm_chain);
+        vmp = q_getnext(&(vcp->vc_pending));
+        coda_q_remove(&(vmp->vm_chain));
 
         /* Move the input args into userspace */
-        
         if (vmp->vm_inSize <= count)
               result = vmp->vm_inSize;
 
         if (count < vmp->vm_inSize) {
-                printk ("psdev_read: warning: venus read %d bytes of %d long 
-                                           message\n",count, vmp->vm_inSize);
+                printk ("psdev_read: Venus read %d bytes of %d in message\n",
+                       count, vmp->vm_inSize);
         }
 
         if ( copy_to_user(buf, vmp->vm_data, result))
                return -EFAULT;
         
         if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
-                coda_panic("coda_psdev_read: bad chain");
+                printk("coda_psdev_read: bad chain");
 
-        /* If request was a signal, free up the message and don't
-           enqueue it in the reply queue. */
+        /* If request was a signal, don't enqueue */
         if (vmp->vm_opcode == CFS_SIGNAL) {
                     CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n", 
                               vmp->vm_opcode, vmp->vm_unique);
-              CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
-              CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
+              CODA_FREE(vmp->vm_data, sizeof(struct cfs_in_hdr));
+              CODA_FREE(vmp, sizeof(struct vmsg));
               return count;
         }
     
         vmp->vm_flags |= VM_READ;
-        INSQUE(vmp->vm_chain, vcp->vc_processing);
+        coda_q_insert(&(vmp->vm_chain), &(vcp->vc_processing));
 
         return result;
 }
@@ -254,22 +297,22 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
 static int coda_psdev_open(struct inode * inode, struct file * file)
 {
         register struct vcomm *vcp = NULL;
-
         ENTRY;
         
-       vcp = coda_psdev2vcomm(file);
+       vcp =coda_psdev2vcomm(file);
 
         if (!vcp)
-              return -ENODEV;
-       memset(vcp, 0, sizeof(struct vcomm));
+               return -ENODEV;
 
-        MOD_INC_USE_COUNT;
+       if (vcp->vc_inuse)
+               return -EBUSY;
 
-        INIT_QUEUE(vcp->vc_pending);
-        INIT_QUEUE(vcp->vc_processing);
+       memset(vcp, 0, sizeof(struct vcomm));
+       vcp->vc_inuse = 1;
+       MOD_INC_USE_COUNT;
 
-       cfsnc_init();
-       CDEBUG(D_PSDEV, "Name cache initialized.\n");
+        init_queue(&(vcp->vc_pending));
+        init_queue(&(vcp->vc_processing));
 
        memset(&coda_callstats, 0, sizeof(struct coda_upcallstats));
        EXIT;
@@ -283,6 +326,7 @@ coda_psdev_release(struct inode * inode, struct file * file)
         struct vcomm *vcp;
         struct vmsg *vmp;
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       ENTRY;
 
         vcp = coda_psdev2vcomm(file);
         
@@ -294,49 +338,43 @@ coda_psdev_release(struct inode * inode, struct file * file)
        
        /* flush the name cache so that we can unmount */
        CDEBUG(D_PSDEV, "Flushing the cache.\n");
-       cfsnc_flush();
-       cfsnc_use = 0;
+       /* cfsnc_flush(); */
+       /* cfsnc_use = 0; */
        CDEBUG(D_PSDEV, "Done.\n");
        
-        /* prevent future operations on this vfs from succeeding by
-         * auto- unmounting any vfs mounted via this device. This
-         * frees user or sysadm from having to remember where all
-         * mount points are located.  Put this before WAKEUPs to avoid
-         * queuing new messages between the WAKEUP and the unmount
-         * (which can happen if we're unlucky) */
-
+       /* if operations are in progress perhaps the kernel
+          can profit from setting the C_DYING flag on the root 
+          cnode of Coda filesystems */
         if (coda_super_info[minor].sbi_root) {
                 struct cnode *cnp = ITOC(coda_super_info[minor].sbi_root);
-                /* Let unmount know this is for real */
                 cnp->c_flags |= C_DYING;
-               /* XXX Could we force an unmount here? */
-        }
+        } else 
+               vcp->vc_inuse = 0;      
        
     
         /* Wakeup clients so they can return. */
-        for (vmp = (struct vmsg *)GETNEXT(vcp->vc_pending);
-             !EOQ(vmp, vcp->vc_pending);
-             vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) {        
+        for (vmp = q_getnext(&(vcp->vc_pending));
+             !q_end(vmp, &(vcp->vc_pending));
+             vmp = q_getnext(&(vmp->vm_chain))) {          
               /* Free signal request messages and don't wakeup cause
                  no one is waiting. */
               if (vmp->vm_opcode == CFS_SIGNAL) {
-                    CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
-                    CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
+                    CODA_FREE(vmp->vm_data, sizeof(struct cfs_in_hdr));
+                    CODA_FREE(vmp, (u_int)sizeof(struct vmsg));
                     continue;
               }
-    
-              wake_up_interruptible(&vmp->vm_sleep);
+              wake_up(&vmp->vm_sleep);
         }
         
-        for (vmp = (struct vmsg *)GETNEXT(vcp->vc_processing);
-             !EOQ(vmp, vcp->vc_processing);
-             vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) {
-               wake_up_interruptible(&vmp->vm_sleep);
+        for (vmp = q_getnext(&(vcp->vc_processing));
+             !q_end(vmp, &(vcp->vc_processing));
+             vmp = q_getnext(&(vmp->vm_chain))) {
+               wake_up(&vmp->vm_sleep);
         }
         
         mark_vcomm_closed(vcp);
-       cfsnc_use = 0;
-        MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
+       EXIT;
        return 0;
 }
 
@@ -358,35 +396,16 @@ static struct file_operations coda_psdev_fops = {
       NULL                   /* lock */
 };
 
-int init_coda_psdev(void)
-{
-        
-       if(register_chrdev(CODA_PSDEV_MAJOR,"coda_psdev", &coda_psdev_fops)) {
-              printk(KERN_ERR "coda_psdev: unable to get major %d\n", 
-                    CODA_PSDEV_MAJOR);
-              return -EIO;
-       }
-        
-       return 0;
-}
-
 
 #ifdef CONFIG_PROC_FS
 
 struct proc_dir_entry proc_coda = {
         0, 4, "coda",
-        S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+        S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, 2, 0, 0,
         0, &proc_net_inode_operations,
 
 };
 
-struct proc_dir_entry proc_coda_cache =  {
-                0 , 10, "coda-cache",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                cfsnc_get_info
-        };
-
 struct proc_dir_entry proc_coda_ncstats =  {
                 0 , 12, "coda-ncstats",
                 S_IFREG | S_IRUGO, 1, 0, 0,
@@ -396,25 +415,48 @@ struct proc_dir_entry proc_coda_ncstats =  {
 
 #endif
 
-#ifdef MODULE
-int init_module(void)
+
+int init_coda_psdev(void)
 {
-  int status;
-  printk(KERN_INFO "Coda Kernel/User communications module 0.04\n");
+       if(register_chrdev(CODA_PSDEV_MAJOR,"coda_psdev", &coda_psdev_fops)) {
+              printk(KERN_ERR "coda_psdev: unable to get major %d\n", 
+                    CODA_PSDEV_MAJOR);
+              return -EIO;
+       }
+       memset(psdev_vcomm, 0, sizeof(psdev_vcomm));
+       memset(coda_super_info, 0, sizeof(coda_super_info));
+       memset(&coda_callstats, 0, sizeof(coda_callstats));
 
 #ifdef CONFIG_PROC_FS
-  proc_register(&proc_root,&proc_coda);
-  proc_register(&proc_coda, &proc_coda_cache);
-  proc_register(&proc_coda, &proc_coda_ncstats);
-  coda_sysctl_init();
+       proc_register(&proc_root,&proc_coda);
+       proc_register(&proc_coda, &proc_coda_ncstats);
+       coda_sysctl_init();
 #endif 
+       return 0;
+}
+
+
+#ifdef MODULE
+
+EXPORT_NO_SYMBOLS;
 
-  init_coda_psdev();
-  
-  if ((status = init_coda_fs()) != 0)
-    {
-      printk("coda: failed in init_coda_fs!\n");
-    }
+MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
+
+int init_module(void)
+{
+  int status;
+  printk(KERN_INFO "Coda Kernel/User communications module 1.0\n");
+
+  status = init_coda_psdev();
+  if ( status ) {
+         printk("Problem (%d) in init_coda_psdev\n", status);
+         return status;
+  }
+
+  status = init_coda_fs();
+  if (status) {
+         printk("coda: failed in init_coda_fs!\n");
+  }
   return status;
 }
 
@@ -425,14 +467,13 @@ void cleanup_module(void)
 
         ENTRY;
 
-        unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
-        
         if ( (err = unregister_filesystem(&coda_fs_type)) != 0 ) {
                 printk("coda: failed to unregister filesystem\n");
         }
+        unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
+
 #if CONFIG_PROC_FS
         coda_sysctl_clean();
-        proc_unregister(&proc_coda, proc_coda_cache.low_ino);
         proc_unregister(&proc_coda, proc_coda_ncstats.low_ino);
        proc_unregister(&proc_root, proc_coda.low_ino);
 #endif 
@@ -440,5 +481,3 @@ void cleanup_module(void)
 
 #endif
 
-
-
index 85a5ccbb3e6875a7cdd29fcb49e407af07afb8f3..87e8f1b6971e3d2a4e89fd8d02a3d202ca861f1a 100644 (file)
@@ -1,9 +1,11 @@
 /*
  * Super block/filesystem wide operations
  *
- * Peter J. Braam <braam@maths.ox.ac.uk>, 
- * Michael Callahan <callahan@maths.ox.ac.uk> Aug 1996
- * Rewritten for Linux 2.1.57 Peter Braam <braam@cs.cmu.edu>
+ * Copryright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and 
+ * Michael Callahan <callahan@maths.ox.ac.uk> 
+ * 
+ * Rewritten for Linux 2.1.?? Peter Braam <braam@cs.cmu.edu>
+ * Copyright (C) Carnegie Mellon University
  */
 
 #define __NO_VERSION__
@@ -33,7 +35,7 @@
 #include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_cache.h>
 
 
 /* VFS super_block ops */
@@ -46,31 +48,11 @@ static void coda_put_super(struct super_block *);
 static int coda_statfs(struct super_block *sb, struct statfs *buf, 
                       int bufsiz);
 
-
 /* helper functions */
-void print_vattr( struct coda_vattr *attr );
-static inline struct coda_sb_info *coda_psinode2sb(struct inode *inode);
 static inline struct vcomm *coda_psinode2vcomm(struct inode *inode);
 static int coda_get_psdev(void *, struct inode **);
-static void coda_vattr_to_iattr(struct inode *, struct coda_vattr *);
-static void coda_iattr_to_vattr(struct iattr *, struct coda_vattr *);
-int coda_fetch_inode(struct inode *, struct coda_vattr *);
-
-extern inline struct vcomm *coda_psdev_vcomm(struct inode *inode);
-extern int coda_cnode_make(struct inode **inode, ViceFid *fid, 
-                          struct super_block *sb);
-extern struct cnode *coda_cnode_alloc(void);
-extern void coda_cnode_free(struct cnode *);
-char *coda_f2s(struct ViceFid *, char *);
-
-extern int cfsnc_initialized;
-extern int coda_debug;
-extern int coda_print_entry;
-
-extern struct inode_operations coda_file_inode_operations;
-extern struct inode_operations coda_dir_inode_operations;
-extern struct inode_operations coda_ioctl_inode_operations;
-extern struct inode_operations coda_symlink_inode_operations;
+static struct coda_sb_info *coda_psinode2sbi(struct inode *inode);
+
 /* exported operations */
 struct super_operations coda_super_operations =
 {
@@ -91,37 +73,38 @@ struct super_operations coda_super_operations =
 struct coda_sb_info coda_super_info[MAX_CODADEVS];
 
 
-
 static struct super_block * coda_read_super(struct super_block *sb, 
                                            void *data, int silent)
 {
         struct inode *psdev = 0, *root = 0; 
        struct coda_sb_info *sbi = NULL;
-       struct vcomm *vc;
+       struct vcomm *vc = NULL;
         ViceFid fid;
        kdev_t dev = sb->s_dev;
         int error;
        char str[50];
 
-ENTRY;
+       ENTRY;
         MOD_INC_USE_COUNT; 
         if (coda_get_psdev(data, &psdev))
-                goto exit;
+                goto error;
 
         vc = coda_psinode2vcomm(psdev);
         if ( !vc )
-               goto exit;
+               goto error;
+       vc->vc_sb = sb;
+       vc->vc_inuse = 1;
 
-       sbi = coda_psinode2sb(psdev);
+       sbi = coda_psinode2sbi(psdev);
        if ( !sbi )
-               goto exit;
-
+               goto error;
         sbi->sbi_psdev = psdev;
        sbi->sbi_vcomm = vc;
+       INIT_LIST_HEAD(&(sbi->sbi_cchead));
 
         lock_super(sb);
         sb->u.generic_sbp = sbi;
-        sb->s_blocksize = 1024;        /* XXXXX */
+        sb->s_blocksize = 1024;        /* XXXXX  what do we put here?? */
         sb->s_blocksize_bits = 10;
         sb->s_magic = CODA_SUPER_MAGIC;
         sb->s_dev = dev;
@@ -129,22 +112,22 @@ ENTRY;
 
        /* get root fid from Venus: this needs the root inode */
        error = venus_rootfid(sb, &fid);
-
        if ( error ) {
-               unlock_super(sb);
                printk("coda_read_super: coda_get_rootfid failed with %d\n",
-                  error);
-               goto exit;
+                      error);
+               sb->s_dev = 0;
+               unlock_super(sb);
+               goto error;
        }         
        printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid, str));
        
+       /* make root inode */
         error = coda_cnode_make(&root, &fid, sb);
         if ( error || !root ) {
            printk("Failure of coda_cnode_make for root: error %d\n", error);
-           unlock_super(sb);
            sb->s_dev = 0;
-           root = NULL;
-           goto exit;
+           unlock_super(sb);
+           goto error;
        } 
 
        printk("coda_read_super: rootinode is %ld dev %d\n", 
@@ -152,13 +135,20 @@ ENTRY;
        sbi->sbi_root = root;
        sb->s_root = d_alloc_root(root, NULL);
        unlock_super(sb);
+       EXIT;  
         return sb;
-EXIT;  
 
-exit:
+error:
+EXIT;  
        MOD_DEC_USE_COUNT;
-       sbi->sbi_vcomm = NULL;
-       sbi->sbi_root = NULL;
+       if (sbi) {
+               sbi->sbi_vcomm = NULL;
+               sbi->sbi_root = NULL;
+       }
+       if ( vc ) {
+               vc->vc_sb = NULL;
+               vc->vc_inuse = 0;
+       }
         if (root) {
                 iput(root);
                 coda_cnode_free(ITOC(root));
@@ -167,7 +157,6 @@ exit:
         return NULL;
 }
 
-
 static void coda_put_super(struct super_block *sb)
 {
         struct coda_sb_info *sb_info;
@@ -177,27 +166,31 @@ static void coda_put_super(struct super_block *sb)
         lock_super(sb);
 
         sb->s_dev = 0;
+       coda_cache_clear_all(sb);
        sb_info = coda_sbp(sb);
+       sb_info->sbi_vcomm->vc_inuse = 0;
+       sb_info->sbi_vcomm->vc_sb = NULL;
+       printk("Coda: Bye bye.\n");
        memset(sb_info, 0, sizeof(* sb_info));
 
         unlock_super(sb);
         MOD_DEC_USE_COUNT;
-EXIT;
+       EXIT;
 }
+
 /* all filling in of inodes postponed until lookup */
 static void coda_read_inode(struct inode *inode)
 {
-        inode->u.generic_ip = NULL;
-       /*      inode->i_blksize = inode->i_sb->s_blocksize;
-       inode->i_mode = 0;
-       inode->i_op = NULL;
-       NFS_CACHEINV(inode); */
+       ENTRY;
+       inode->u.generic_ip =  NULL;
+       return;
 }
 
-static void coda_put_inode(struct inode *inode
+static void coda_put_inode(struct inode *in) 
 {
-        CDEBUG(D_INODE,"ino: %ld, cnp: %x\n", inode->i_ino,
-              (int) inode->u.generic_ip);
+       ENTRY;
+
+        CDEBUG(D_INODE,"ino: %ld, cnp: %p\n", in->i_ino, in->u.generic_ip);
 }
 
 static void coda_delete_inode(struct inode *inode)
@@ -215,19 +208,20 @@ static void coda_delete_inode(struct inode *inode)
        }
 
         cnp = ITOC(inode);
-
         open_inode = cnp->c_ovp;
         if ( open_inode ) {
                 CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n",  
                       open_inode->i_ino,  open_inode->i_count);
                 cnp->c_ovp = NULL;
-               cnp->c_odentry.d_inode = NULL;
-                iput( open_inode );
+                iput(open_inode);
         }
+       
+       coda_cache_clear_cnp(cnp);
+
        inode->u.generic_ip = NULL;
         coda_cnode_free(cnp);
         clear_inode(inode);
-EXIT;
+       EXIT;
 }
 
 static int  coda_notify_change(struct inode *inode, struct iattr *iattr)
@@ -235,20 +229,21 @@ static int  coda_notify_change(struct inode *inode, struct iattr *iattr)
         struct cnode *cnp;
         struct coda_vattr vattr;
         int error;
-ENTRY;
+       
+       ENTRY;
         memset(&vattr, 0, sizeof(vattr)); 
         cnp = ITOC(inode);
         CHECK_CNODE(cnp);
 
         coda_iattr_to_vattr(iattr, &vattr);
-        vattr.va_type = VNON; /* cannot set type */
+        vattr.va_type = C_VNON; /* cannot set type */
        CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode);
 
         error = venus_setattr(inode->i_sb, &cnp->c_fid, &vattr);
 
         if ( !error ) {
                coda_vattr_to_iattr(inode, &vattr); 
-               cfsnc_zapfid(&(cnp->c_fid));
+               coda_cache_clear_cnp(cnp);
         }
        CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", 
               inode->i_mode, error);
@@ -257,14 +252,12 @@ ENTRY;
         return error;
 }
 
-/*  we need _something_ */
+/*  we need _something_ for this routine. Let's mimic AFS */
 static int coda_statfs(struct super_block *sb, struct statfs *buf, 
                       int bufsiz)
 {
        struct statfs tmp;
 
-#define NB_SFS_SIZ 0x895440
-
        tmp.f_type = CODA_SUPER_MAGIC;
        tmp.f_bsize = 1024;
        tmp.f_blocks = 9000000;
@@ -284,278 +277,38 @@ struct file_system_type coda_fs_type = {
    "coda", 0, coda_read_super, NULL
 };
 
-
-
-
 int init_coda_fs(void)
 {
        return register_filesystem(&coda_fs_type);
 }
 
+/* MODULE stuff is in psdev.c */
 
-/* utility functions below */
-static void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
-{
-        int inode_type;
-        /* inode's i_dev, i_flags, i_ino are set by iget 
-           XXX: is this all we need ??
-           */
-        switch (attr->va_type) {
-        case VNON:
-                inode_type  = 0;
-                break;
-        case VREG:
-                inode_type = S_IFREG;
-                break;
-        case VDIR:
-                inode_type = S_IFDIR;
-                break;
-        case VLNK:
-                inode_type = S_IFLNK;
-                break;
-        default:
-                inode_type = 0;
-        }
-       inode->i_mode |= inode_type;
-
-       if (attr->va_mode != (u_short) -1)
-               inode->i_mode = attr->va_mode | inode_type;
-        if (attr->va_uid != -1) 
-               inode->i_uid = (uid_t) attr->va_uid;
-        if (attr->va_gid != -1)
-               inode->i_gid = (gid_t) attr->va_gid;
-       if (attr->va_nlink != -1)
-               inode->i_nlink = attr->va_nlink;
-       if (attr->va_size != -1)
-               inode->i_size = attr->va_size;
-       /*  XXX This needs further study */
-       /*
-        inode->i_blksize = attr->va_blocksize;
-       inode->i_blocks = attr->va_size/attr->va_blocksize 
-         + (attr->va_size % attr->va_blocksize ? 1 : 0); 
-         */
-       if (attr->va_atime.tv_sec != -1) 
-               inode->i_atime = attr->va_atime.tv_sec;
-       if (attr->va_mtime.tv_sec != -1)
-               inode->i_mtime = attr->va_mtime.tv_sec;
-        if (attr->va_ctime.tv_sec != -1)
-               inode->i_ctime = attr->va_ctime.tv_sec;
-}
-/* 
- * BSD sets attributes that need not be modified to -1. 
- * Linux uses the valid field to indicate what should be
- * looked at.  The BSD type field needs to be deduced from linux 
- * mode.
- * So we have to do some translations here.
- */
-
-void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
-{
-        umode_t mode;
-        unsigned int valid;
-
-        /* clean out */        
-        vattr->va_mode = (umode_t) -1;
-        vattr->va_uid = (vuid_t) -1; 
-        vattr->va_gid = (vgid_t) -1;
-        vattr->va_size = (off_t) -1;
-       vattr->va_atime.tv_sec = (time_t) -1;
-        vattr->va_mtime.tv_sec  = (time_t) -1;
-       vattr->va_ctime.tv_sec  = (time_t) -1;
-       vattr->va_atime.tv_nsec =  (time_t) -1;
-        vattr->va_mtime.tv_nsec = (time_t) -1;
-       vattr->va_ctime.tv_nsec = (time_t) -1;
-        vattr->va_type = VNON;
-       vattr->va_fileid = (long)-1;
-       vattr->va_gen = (long)-1;
-       vattr->va_bytes = (long)-1;
-       vattr->va_fsid = (long)-1;
-       vattr->va_nlink = (short)-1;
-       vattr->va_blocksize = (long)-1;
-       vattr->va_rdev = (dev_t)-1;
-        vattr->va_flags = 0;
-
-        /* determine the type */
-        mode = iattr->ia_mode;
-                if ( S_ISDIR(mode) ) {
-                vattr->va_type = VDIR; 
-        } else if ( S_ISREG(mode) ) {
-                vattr->va_type = VREG;
-        } else if ( S_ISLNK(mode) ) {
-                vattr->va_type = VLNK;
-        } else {
-                /* don't do others */
-                vattr->va_type = VNON;
-        }
-
-        /* set those vattrs that need change */
-        valid = iattr->ia_valid;
-        if ( valid & ATTR_MODE ) {
-                vattr->va_mode = iattr->ia_mode;
-       }
-        if ( valid & ATTR_UID ) {
-                vattr->va_uid = (vuid_t) iattr->ia_uid;
-       }
-        if ( valid & ATTR_GID ) {
-                vattr->va_gid = (vgid_t) iattr->ia_gid;
-       }
-        if ( valid & ATTR_SIZE ) {
-                vattr->va_size = iattr->ia_size;
-       }
-        if ( valid & ATTR_ATIME ) {
-                vattr->va_atime.tv_sec = iattr->ia_atime;
-                vattr->va_atime.tv_nsec = 0;
-       }
-        if ( valid & ATTR_MTIME ) {
-                vattr->va_mtime.tv_sec = iattr->ia_mtime;
-                vattr->va_mtime.tv_nsec = 0;
-       }
-        if ( valid & ATTR_CTIME ) {
-                vattr->va_ctime.tv_sec = iattr->ia_ctime;
-                vattr->va_ctime.tv_nsec = 0;
-       }
-        
-}
-  
-
-void print_vattr(struct coda_vattr *attr)
-{
-    char *typestr;
-
-    switch (attr->va_type) {
-    case VNON:
-       typestr = "VNON";
-       break;
-    case VREG:
-       typestr = "VREG";
-       break;
-    case VDIR:
-       typestr = "VDIR";
-       break;
-    case VBLK:
-       typestr = "VBLK";
-       break;
-    case VCHR:
-       typestr = "VCHR";
-       break;
-    case VLNK:
-       typestr = "VLNK";
-       break;
-    case VSOCK:
-       typestr = "VSCK";
-       break;
-    case VFIFO:
-       typestr = "VFFO";
-       break;
-    case VBAD:
-       typestr = "VBAD";
-       break;
-    default:
-       typestr = "????";
-       break;
-    }
-
-
-    printk("attr: type %s (%o)  mode %o uid %d gid %d fsid %d rdev %d\n",
-             typestr, (int)attr->va_type, (int)attr->va_mode, (int)attr->va_uid, 
-             (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev);
-    
-    printk("      fileid %d nlink %d size %d blocksize %d bytes %d\n",
-             (int)attr->va_fileid, (int)attr->va_nlink, 
-             (int)attr->va_size,
-             (int)attr->va_blocksize,(int)attr->va_bytes);
-    printk("      gen %ld flags %ld vaflags %d\n",
-             attr->va_gen, attr->va_flags, attr->va_vaflags);
-    printk("      atime sec %d nsec %d\n",
-             (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec);
-    printk("      mtime sec %d nsec %d\n",
-             (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec);
-    printk("      ctime sec %d nsec %d\n",
-             (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec);
-}
-
-/*   */
-int coda_fetch_inode (struct inode *inode, struct coda_vattr *attr)
-{
-        struct cnode *cp;
-        int ino, error=0;
-        CDEBUG(D_SUPER, "fetch for ino: %ld\n", inode->i_ino);
-
-        ino = inode->i_ino;
-        if (!ino)
-                printk("coda_fetch_inode: inode called with i_ino = 0 (don't worry)\n");
-
-        inode->i_op = NULL;
-        inode->i_mode = 0;
-
-        cp = ITOC(inode);
-        CHECK_CNODE(cp);
-
-        /* root inode  */
-        if (cp->c_fid.Volume == 0 &&
-            cp->c_fid.Vnode == 0 &&
-            cp->c_fid.Unique == 0) {
-               inode->i_ino = 1;
-               inode->i_op = NULL;
-               return 0;
-        }
-        
-        if (IS_CTL_FID( &(cp->c_fid) )) {
-                /* This is the special magic control file.  
-                  Venus doesn't want
-                   to hear a GETATTR about this! */
-                inode->i_op = &coda_ioctl_inode_operations;
-                return 0;
-        }
-
-        if ( ! attr ) {
-                printk("coda_fetch_inode: called with NULL vattr, ino %ld\n",
-                      inode->i_ino);
-                return -1; /* XXX */
-        }
-
-        if (coda_debug & D_SUPER ) print_vattr(attr);
-        coda_vattr_to_iattr(inode, attr);
-
-        if (S_ISREG(inode->i_mode))
-                inode->i_op = &coda_file_inode_operations;
-        else if (S_ISDIR(inode->i_mode))
-                inode->i_op = &coda_dir_inode_operations;
-        else if (S_ISLNK(inode->i_mode))
-                inode->i_op = &coda_symlink_inode_operations;
-        else {
-                printk ("coda_read_inode: what kind of inode is this? i_mode = %o\n", inode->i_mode);
-                inode->i_op = NULL;
-        }
-        return error;
-}
-
-static inline struct vcomm *
-coda_psinode2vcomm(struct inode *inode) 
+/*  helpers */
+static inline struct vcomm *coda_psinode2vcomm(struct inode *inode) 
 {
         
        unsigned int minor = MINOR(inode->i_rdev);
-CDEBUG(D_PSDEV,"minor %d\n", minor);
+       CDEBUG(D_PSDEV,"minor %d\n", minor);
        if ( minor < MAX_CODADEVS ) 
              return &(psdev_vcomm[minor]);
        else
              return NULL;
 }
 
-static inline struct coda_sb_info *
-coda_psinode2sb(struct inode *inode) 
+static struct coda_sb_info *coda_psinode2sbi(struct inode *inode) 
 {
        unsigned int minor = MINOR(inode->i_rdev);
 
-CDEBUG(D_PSDEV,"minor %d\n", minor);
-       if ( minor < MAX_CODADEVS 
+       CDEBUG(D_PSDEV,"minor %d\n", minor);
+       if ( (minor >= 0) && (minor < MAX_CODADEVS)
                return &(coda_super_info[minor]);
        else
                return NULL;
 }
 
-static int 
-coda_get_psdev(void *data, struct inode **res_dev)
+/* name lookup for psdev passed in by mount */
+static int coda_get_psdev(void *data, struct inode **res_dev)
 {
         char **psdev_path;
         struct inode *psdev = 0;
@@ -563,50 +316,46 @@ coda_get_psdev(void *data, struct inode **res_dev)
 
  
        if ( ! data ) { 
-               printk("coda_read_super: no data!\n");
-               goto error;
-       } else {
-               psdev_path = data;
-       }
+               printk("coda_get_psdev: no data!\n");
+               return 1;
+       } 
+
+       psdev_path = data;
         ent = namei((char *) *psdev_path);
         if (IS_ERR(ent)) {
                printk("namei error %ld for %d\n", PTR_ERR(ent), 
                       (int) psdev_path);
-               goto error;
+               return 1;
         }
        psdev = ent->d_inode;
-        
 
         if (!S_ISCHR(psdev->i_mode)) {
                printk("not a character device\n");
-               goto error;
+               return 1;
         }
-CDEBUG(D_PSDEV,"major %d, minor %d, count %d\n", MAJOR(psdev->i_rdev), 
-       MINOR(psdev->i_rdev), psdev->i_count);
+       CDEBUG(D_PSDEV,"major %d, minor %d, count %d\n", 
+              MAJOR(psdev->i_rdev), 
+              MINOR(psdev->i_rdev), psdev->i_count);
         
         if (MAJOR(psdev->i_rdev) != CODA_PSDEV_MAJOR) {
                printk("device %d not a Coda PSDEV device\n", 
                       MAJOR(psdev->i_rdev));
-               goto error;
+               return 1;
         }
 
         if (MINOR(psdev->i_rdev) >= MAX_CODADEVS) { 
                printk("minor %d not an allocated Coda PSDEV\n", 
                       psdev->i_rdev);
-               goto error;
+               return 1;
         }
 
         if (psdev->i_count < 1) {
                printk("coda device minor %d not open (i_count = %d)\n", 
                       MINOR(psdev->i_rdev), psdev->i_count);
-               goto error;
+               return 1;
         }
         
         *res_dev = psdev;
-
+       EXIT;  
         return 0;
-      
-EXIT;  
-error:
-        return 1;
 }
index 432b806f80b8d9966730a2368edcbd84dfdfe27e..8b8d71edfab23b18f3a7f2145045bf5510e58d2a 100644 (file)
 #include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_cache.h>
 
 static int coda_readlink(struct inode *inode, char *buffer, int length);
+static struct dentry *coda_follow_link(struct inode *, struct dentry *);
 
 struct inode_operations coda_symlink_inode_operations = {
        NULL,                   /* no file-operations */
@@ -38,7 +39,7 @@ struct inode_operations coda_symlink_inode_operations = {
        NULL,                   /* mknod */
        NULL,                   /* rename */
        coda_readlink,          /* readlink */
-       NULL,                   /* follow_link */
+       coda_follow_link,       /* follow_link */
        NULL,                   /* readpage */
        NULL,                   /* writepage */
        NULL,                   /* bmap */
@@ -76,7 +77,43 @@ static int coda_readlink(struct inode *inode, char *buffer, int length)
                copy_to_user(buffer, buf, len);
                put_user('\0', buffer + len);
                error = len;
-               CODA_FREE(buf, len);
        }
+       if ( buf )
+               CODA_FREE(buf, len);
        return error;
 }
+
+static struct dentry *coda_follow_link(struct inode *inode, 
+                                      struct dentry *base)
+{
+       int error;
+       struct cnode *cnp;
+       unsigned int len;
+       char mem[CFS_MAXPATHLEN];
+       char *path;
+ENTRY;
+       CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino);
+       
+        cnp = ITOC(inode);
+        CHECK_CNODE(cnp);
+
+       len = CFS_MAXPATHLEN;
+       error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len);
+
+       if (error) {
+               dput(base);
+               return ERR_PTR(error);
+       }
+       len = strlen(mem);
+       path = kmalloc(len + 1, GFP_KERNEL);
+       if (!path) {
+               dput(base);
+               return ERR_PTR(-ENOMEM);
+       }
+       memcpy(path, mem, len);
+       path[len] = 0;
+
+       base = lookup_dentry(path, base, 1);
+       kfree(path);
+       return base;
+}
index 04523a38346f5bcd171dd83cde75145e31ccb66a..29aa2dba3cf8a47ce73a7c47697f97c8c051c36a 100644 (file)
@@ -8,6 +8,7 @@
  */
 /* sysctl entries for Coda! */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <asm/uaccess.h>
 #include <linux/utsname.h>
 
-#include <linux/coda_namecache.h>
+#include <linux/coda.h>
+#include <linux/coda_linux.h>
+#include <linux/coda_cnode.h>
+#include <linux/coda_psdev.h>
+#include <linux/coda_cache.h>
 #include <linux/coda_sysctl.h>
 extern int coda_debug;
-extern int cfsnc_use;
+/* extern int cfsnc_use; */
 extern int coda_print_entry;
-extern int cfsnc_flushme;
+/* extern int cfsnc_flushme; */
 extern int cfsnc_procsize;
-extern void cfsnc_flush(void);
+/* extern void cfsnc_flush(void); */
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
 
@@ -38,20 +43,20 @@ int coda_dointvec(ctl_table *table, int write, struct file *filp,
 struct ctl_table_header *fs_table_header, *coda_table_header;
 #define FS_CODA         1       /* Coda file system */
 
-#define CODA_DEBUG     1           /* control debugging */
-#define CODA_ENTRY         2       /* control enter/leave pattern */
-#define CODA_FLUSH      3       /* flush the cache on next lookup */
-#define CODA_MC         4       /* use/do not use the minicache */
-#define CODA_PROCSIZE   5       /* resize the cache on next lookup */
+#define CODA_DEBUG      1       /* control debugging */
+#define CODA_ENTRY      2       /* control enter/leave pattern */
+#define CODA_TIMEOUT    3       /* timeout on upcalls to become intrble */
+#define CODA_MC         4       /* use/do not use the access cache */
+#define CODA_HARD       5       /* mount type "hard" or "soft" */
 
 
 
 static ctl_table coda_table[] = {
        {CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &coda_dointvec},
        {CODA_ENTRY, "printentry", &coda_print_entry, sizeof(int), 0644, NULL, &coda_dointvec},
-       {CODA_MC, "minicache", &cfsnc_use, sizeof(int), 0644, NULL, &coda_dointvec},
-       {CODA_FLUSH, "flushme", &cfsnc_flushme, sizeof(int), 0644, NULL, &coda_dointvec},
-       {CODA_PROCSIZE, "resize", &cfsnc_procsize, sizeof(int), 0644, NULL, &coda_dointvec},
+       {CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &coda_dointvec}, 
+       {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &coda_dointvec},
+       {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &coda_dointvec},
        { 0 }
 };
 
index 43536f6220e2cf4a19e292a53a6d761aef01a09e..e0ab86d8b64ebfc4e1f123d2a78e5ff2dec5d985 100644 (file)
 #include <linux/coda_linux.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_cache.h>
+
+#define UPARG(op)\
+do {\
+       CODA_ALLOC(inp, union inputArgs *, insize);\
+       outp = (union outputArgs *) (inp);\
+        inp->ih.opcode = (op);\
+       inp->ih.pid = current->pid;\
+       inp->ih.pgid = current->pgrp;\
+       coda_load_creds(&(inp->ih.cred));\
+        outsize = insize;\
+} while (0)
+
+static inline int max(int a, int b) 
+{
+       if ( a > b )
+               return a; 
+       else
+               return b;
+}
 
+#define INSIZE(tag) sizeof(struct cfs_ ## tag ## _in)
+#define OUTSIZE(tag) sizeof(struct cfs_ ## tag ## _out)
+#define SIZE(tag)  max(INSIZE(tag), OUTSIZE(tag))
 
-static vcsize = (sizeof(struct inputArgs) > sizeof(struct outputArgs)) ?
-                sizeof(struct inputArgs): sizeof(struct outputArgs);
 
 /* the upcalls */
 int venus_rootfid(struct super_block *sb, ViceFid *fidp)
 {
-        struct inputArgs *inp;
-       struct outputArgs *outp;
-       int error=0;
-       int size;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
 ENTRY;
 
-        UPARG(vcsize, CFS_ROOT);
-       error = coda_upcall(coda_sbp(sb), VC_IN_NO_DATA, &size, inp);
+        insize = SIZE(root);
+        UPARG(CFS_ROOT);
+       error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
        
        if (error) {
                printk("coda_get_rootfid: error %d\n", error);
        } else {
-               *fidp = (ViceFid) outp->d.cfs_root.VFid;
+               *fidp = (ViceFid) outp->cfs_root.VFid;
                CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
                       fidp->Volume, fidp->Vnode);
        }
 
-       if (inp)  CODA_FREE(inp, VC_IN_NO_DATA);
+       if (inp)  CODA_FREE(inp, insize);
         EXIT;
        return -error;
 }
@@ -69,19 +89,19 @@ ENTRY;
 int venus_getattr(struct super_block *sb, struct ViceFid *fid, 
                     struct coda_vattr *attr) 
 {
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        int size, error;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
 ENTRY;
-
-       UPARG(vcsize, CFS_GETATTR);
-        inp->d.cfs_getattr.VFid = *fid;
-        error = coda_upcall(coda_sbp(sb), vcsize, &size, inp);
+        insize = SIZE(getattr); 
+       UPARG(CFS_GETATTR);
+        inp->cfs_getattr.VFid = *fid;
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
        
        if ( !error )
-               *attr = (struct coda_vattr) outp->d.cfs_getattr.attr;
+               *attr = outp->cfs_getattr.attr;
 
-        if (inp) CODA_FREE(inp, sizeof(struct inputArgs));
+        if (inp) CODA_FREE(inp, insize);
         EXIT;
         return -error;
 }
@@ -89,19 +109,20 @@ ENTRY;
 int  venus_setattr(struct super_block *sb, struct ViceFid *fid, 
                      struct coda_vattr *vattr)
 {
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        int error, size;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
        
-       UPARG(vcsize, CFS_SETATTR);
+       insize= SIZE(setattr);
+       UPARG(CFS_SETATTR);
 
-        inp->d.cfs_setattr.VFid = *fid;
-       inp->d.cfs_setattr.attr = *vattr;
+        inp->cfs_setattr.VFid = *fid;
+       inp->cfs_setattr.attr = *vattr;
 
-        error = coda_upcall(coda_sbp(sb), vcsize, &size, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-        CDEBUG(D_SUPER, " result %ld\n", outp->result); 
-        if ( inp ) CODA_FREE(inp, vcsize);
+        CDEBUG(D_SUPER, " result %d\n", error); 
+        if ( inp ) CODA_FREE(inp, insize);
         return -error;
 }
 
@@ -109,26 +130,26 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid,
                    const char *name, int length, int * type, 
                    struct ViceFid *resfid)
 {
-        struct inputArgs *inp;
-       struct outputArgs *outp;
-       int insize, size, error=0, payload_offset;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+       int offset;
 
-        insize =  VC_INSIZE(cfs_lookup_in) + CFS_MAXNAMLEN +1;
-       UPARG(insize, CFS_LOOKUP);
+       offset = INSIZE(lookup);
+        insize =  max(offset + length +1, OUTSIZE(lookup));
+       UPARG(CFS_LOOKUP);
 
-        inp->d.cfs_lookup.VFid = *fid;
+        inp->cfs_lookup.VFid = *fid;
+       inp->cfs_lookup.name = offset;
         /* send Venus a null terminated string */
-        payload_offset = VC_INSIZE(cfs_lookup_in);
-        inp->d.cfs_lookup.name = (char *) payload_offset;
-        memcpy((char *)inp + payload_offset, name, length);
-        *((char *)inp + payload_offset + length) = '\0';
+        memcpy((char *)(inp) + offset, name, length);
+        *((char *)inp + offset + length) = '\0';
 
-        size = payload_offset + length + 1;
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
        if ( !error ) {
-               *resfid = outp->d.cfs_lookup.VFid;
-               *type = outp->d.cfs_lookup.vtype;
+               *resfid = outp->cfs_lookup.VFid;
+               *type = outp->cfs_lookup.vtype;
        }
        if (inp) CODA_FREE(inp, insize);
                
@@ -138,53 +159,48 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid,
 
 int venus_release(struct super_block *sb, struct ViceFid *fid, int flags)
 {
-        struct inputArgs *inp;
-       struct outputArgs *outp;
-       int size = sizeof(struct outputArgs);
-       int error = 0;
-
-       CODA_ALLOC(inp, struct inputArgs *, sizeof(struct inputArgs));
-        outp = (struct outputArgs *)inp;
-        INIT_IN(inp, CFS_CLOSE);
-        coda_load_creds(&(inp->cred));
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+       
+       insize = SIZE(close);
+       UPARG(CFS_CLOSE);
 
-        inp->d.cfs_close.VFid = *fid;
-        inp->d.cfs_close.flags = flags;
+        inp->cfs_close.VFid = *fid;
+        inp->cfs_close.flags = flags;
 
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-        if (inp) CODA_FREE(inp, sizeof(struct inputArgs));
+        if (inp) 
+               CODA_FREE(inp, insize);
         return -error;
 }
 
 int venus_open(struct super_block *sb, struct ViceFid *fid,
                  int flags, ino_t *ino, dev_t *dev)
 {
-        struct inputArgs *inp = NULL;
-       struct outputArgs *outp = NULL;
-       int size = sizeof(struct inputArgs);
-       int error = 0;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+       
+       insize = SIZE(open);
+       UPARG(CFS_OPEN);
 
-        CODA_ALLOC(inp, struct inputArgs *, sizeof(struct inputArgs));
-        outp = (struct outputArgs *)inp;
-        INIT_IN(inp, CFS_OPEN);
-        coda_load_creds(&(inp->cred));
+        inp->cfs_open.VFid = *fid;
+        inp->cfs_open.flags = flags;
 
-        inp->d.cfs_open.VFid = *fid;
-        inp->d.cfs_open.flags = flags;
-
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
        if ( !error ) {
-               *ino = outp->d.cfs_open.inode;
-               *dev = outp->d.cfs_open.dev;
+               *ino = outp->cfs_open.inode;
+               *dev = outp->cfs_open.dev;
        } else {
                *ino = 0;
                *dev = 0;
        }
 
         if (inp) 
-                CODA_FREE(inp, sizeof(struct inputArgs));
+                CODA_FREE(inp, insize);
 
        return -error;
 }      
@@ -193,69 +209,69 @@ int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
                   const char *name, int length, 
                   struct ViceFid *newfid, struct coda_vattr *attrs)
 {
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        int error=0, size, payload_offset;
-
-        payload_offset = VC_INSIZE(cfs_mkdir_in);
-       size = CFS_MAXNAMLEN + payload_offset;
-       UPARG(size, CFS_MKDIR);
-
-        inp->d.cfs_mkdir.VFid = *dirfid;
-        inp->d.cfs_mkdir.attr = *attrs;
-        inp->d.cfs_mkdir.name = (char *) payload_offset;
-
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+        int offset;
+
+       offset = INSIZE(mkdir);
+       insize = max(offset + length + 1, OUTSIZE(mkdir));
+       UPARG(CFS_MKDIR);
+
+        inp->cfs_mkdir.VFid = *dirfid;
+        inp->cfs_mkdir.attr = *attrs;
+       inp->cfs_mkdir.name = offset;
         /* Venus must get null terminated string */
-        memcpy((char *)inp + payload_offset, name, length);
-        *((char *)inp + payload_offset + length) = '\0';
-        size = payload_offset + length + 1;
+        memcpy((char *)(inp) + offset, name, length);
+        *((char *)inp + offset + length) = '\0';
         
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-       *attrs = outp->d.cfs_mkdir.attr;
-       *newfid = outp->d.cfs_mkdir.VFid;
+       *attrs = outp->cfs_mkdir.attr;
+       *newfid = outp->cfs_mkdir.VFid;
 
        if (inp) 
-               CODA_FREE(inp, size);
+               CODA_FREE(inp, insize);
        return -error;        
 }
 
 
 int venus_rename(struct super_block *sb, struct ViceFid *old_fid, 
                 struct ViceFid *new_fid, size_t old_length, 
-                size_t new_length, const char *old_name, const char *new_name)
+                size_t new_length, const char *old_name, 
+                const char *new_name)
 {
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-       int error, offset, size, s;
+       union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error; 
+       int offset, s;
        
-       size = 2*CFS_MAXNAMLEN + VC_INSIZE(cfs_rename_in) +8;
-       UPARG(size, CFS_RENAME);
+       offset = INSIZE(rename);
+       insize = max(offset + new_length + old_length + 8,
+                    OUTSIZE(rename)); 
+       UPARG(CFS_RENAME);
 
-        inp->d.cfs_rename.sourceFid = *old_fid;
-        inp->d.cfs_rename.destFid =  *new_fid;
-
-        offset = VC_INSIZE(cfs_rename_in);
+        inp->cfs_rename.sourceFid = *old_fid;
+        inp->cfs_rename.destFid =  *new_fid;
+        inp->cfs_rename.srcname = offset;
 
         /* Venus must receive an null terminated string */
-        inp->d.cfs_rename.srcname = (char *)offset;
         s = ( old_length & ~0x3) +4; /* round up to word boundary */
-        memcpy((char *)inp + offset, old_name, old_length);
+        memcpy((char *)(inp) + offset, old_name, old_length);
         *((char *)inp + offset + old_length) = '\0';
 
         /* another null terminated string for Venus */
         offset += s;
-        inp->d.cfs_rename.destname = (char *)offset;
+        inp->cfs_rename.destname = offset;
         s = ( new_length & ~0x3) +4; /* round up to word boundary */
-        memcpy((char *)inp + offset, new_name, new_length);
+        memcpy((char *)(inp) + offset, new_name, new_length);
         *((char *)inp + offset + new_length) = '\0';
 
-        size += s;
         CDEBUG(D_INODE, "destname in packet: %s\n", 
-              (char *)inp + (int) inp->d.cfs_rename.destname);
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+              (char *)inp + (int) inp->cfs_rename.destname);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-       if (inp) CODA_FREE(inp, size);
+       if (inp) CODA_FREE(inp, insize);
        return -error;
 }
 
@@ -263,131 +279,138 @@ int venus_create(struct super_block *sb, struct ViceFid *dirfid,
                    const char *name, int length, int excl, int mode, 
                    struct ViceFid *newfid, struct coda_vattr *attrs) 
 {
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        int error=0, size, payload_offset;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+        int offset;
 
-        payload_offset = VC_INSIZE(cfs_create_in);
-       size = CFS_MAXNAMLEN + payload_offset;
-       UPARG(size, CFS_CREATE);
+        offset = INSIZE(create);
+       insize = max(offset + length + 1, OUTSIZE(create));
+       UPARG(CFS_CREATE);
 
-        inp->d.cfs_create.VFid = *dirfid;
-        inp->d.cfs_create.attr.va_mode = mode;
-       inp->d.cfs_create.excl = excl;
-        inp->d.cfs_create.mode = mode;
-        inp->d.cfs_create.name = (char *) payload_offset;
+        inp->cfs_create.VFid = *dirfid;
+        inp->cfs_create.attr.va_mode = mode;
+       inp->cfs_create.excl = excl;
+        inp->cfs_create.mode = mode;
+        inp->cfs_create.name = offset;
 
         /* Venus must get null terminated string */
-        memcpy((char *)inp + payload_offset, name, length);
-        *((char *)inp + payload_offset + length) = '\0';
-        size = payload_offset + length + 1;
-        
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+        memcpy((char *)(inp) + offset, name, length);
+        *((char *)inp + offset + length) = '\0';
+                
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-       *attrs = outp->d.cfs_create.attr;
-       *newfid = outp->d.cfs_create.VFid;
+       *attrs = outp->cfs_create.attr;
+       *newfid = outp->cfs_create.VFid;
 
        if (inp) 
-               CODA_FREE(inp, size);
+               CODA_FREE(inp, insize);
        return -error;        
 }
 
 int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid, 
                    const char *name, int length)
 {
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        int error=0, size, payload_offset;
-
-        payload_offset = VC_INSIZE(cfs_rmdir_in);
-       size = CFS_MAXNAMLEN + payload_offset;
-       UPARG(size, CFS_RMDIR);
-
-        inp->d.cfs_rmdir.VFid = *dirfid;
-        inp->d.cfs_rmdir.name = (char *) payload_offset;
-        memcpy((char *)inp + payload_offset, name, size);
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+        int offset;
+
+        offset = INSIZE(rmdir);
+       insize = max(offset + length + 1, OUTSIZE(rmdir));
+       UPARG(CFS_RMDIR);
+
+        inp->cfs_rmdir.VFid = *dirfid;
+        inp->cfs_rmdir.name = offset;
+        memcpy((char *)(inp) + offset, name, length);
+       *((char *)inp + offset + length) = '\0';
         
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
        if ( inp ) 
-               CODA_FREE(inp, size);
+               CODA_FREE(inp, insize);
        return -error;
 }
 
 int venus_remove(struct super_block *sb, struct ViceFid *dirfid, 
                    const char *name, int length)
 {
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        int error=0, size, payload_offset;
-
-        payload_offset = VC_INSIZE(cfs_remove_in);
-       size = CFS_MAXNAMLEN + payload_offset;
-       UPARG(size, CFS_REMOVE);
-
-        inp->d.cfs_remove.VFid = *dirfid;
-        inp->d.cfs_remove.name = (char *)payload_offset;
-        memcpy((char *)inp + payload_offset, name, size);
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int error=0, insize, outsize, offset;
+
+        offset = INSIZE(remove);
+       insize = max(offset + length + 1, OUTSIZE(remove));
+       UPARG(CFS_REMOVE);
+
+        inp->cfs_remove.VFid = *dirfid;
+        inp->cfs_remove.name = offset;
+        memcpy((char *)(inp) + offset, name, length);
+       *((char *)inp + offset + length) = '\0';
         
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
        if ( inp ) 
-               CODA_FREE(inp, size);
+               CODA_FREE(inp, insize);
        return -error;
 }
 
 int venus_readlink(struct super_block *sb, struct ViceFid *fid, 
                      char *buffer, int *length)
 { 
-        int error, size, retlen;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+        int retlen;
         char *result;
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        char *buf=NULL; /*[CFS_MAXNAMLEN + VC_INSIZE(cfs_readlink_in)];*/
         
-       size = CFS_MAXPATHLEN + VC_INSIZE(cfs_readlink_in);
-       UPARG(size, CFS_READLINK);
-        inp->d.cfs_readlink.VFid = *fid;
+       insize = max(INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
+       UPARG(CFS_READLINK);
+
+        inp->cfs_readlink.VFid = *fid;
     
-        error =  coda_upcall(coda_sbp(sb), size, &size, inp);
+        error =  coda_upcall(coda_sbp(sb), insize, &outsize, inp);
        
        if (! error) {
-                retlen = outp->d.cfs_readlink.count;
+                retlen = outp->cfs_readlink.count;
                if ( retlen > *length )
                        retlen = *length;
                *length = retlen;
-               result =  (char *)outp + (int)outp->d.cfs_readlink.data;
+               result =  (char *)outp + (int)outp->cfs_readlink.data;
                memcpy(buffer, result, retlen);
+               *(buffer + retlen) = '\0';
        }
         
-        if (inp) CODA_FREE(buf, size);
+        if (inp) CODA_FREE(inp, insize);
         CDEBUG(D_INODE, " result %d\n",error);
         EXIT;
         return -error;
 }
 
+
+
 int venus_link(struct super_block *sb, struct ViceFid *fid, 
                  struct ViceFid *dirfid, const char *name, int len )
 {
-        int error, payload_offset, size;
-        struct inputArgs *inp;
-        struct outputArgs *outp;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+        int offset;
 
-       size = CFS_MAXNAMLEN + sizeof(struct inputArgs);
-        UPARG(size, CFS_LINK);
+       offset = INSIZE(link);
+       insize = max(offset  + len + 1, OUTSIZE(link));
+        UPARG(CFS_LINK);
 
-        payload_offset = (VC_INSIZE(cfs_link_in));
-        inp->d.cfs_link.sourceFid = *fid;
-        inp->d.cfs_link.destFid = *dirfid;
-        inp->d.cfs_link.tname = (char *)payload_offset;
+        inp->cfs_link.sourceFid = *fid;
+        inp->cfs_link.destFid = *dirfid;
+        inp->cfs_link.tname = offset;
 
         /* make sure strings are null terminated */
-        memcpy((char *)inp + payload_offset, name, len);
-        *((char *)inp + payload_offset + len) = '\0';
-        size = payload_offset + len + 1;
+        memcpy((char *)(inp) + offset, name, len);
+        *((char *)inp + offset + len) = '\0';
         
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
         if (inp) 
-               CODA_FREE(inp, size);
+               CODA_FREE(inp, insize);
         CDEBUG(D_INODE, " result %d\n",error);
         EXIT;
         return -error;
@@ -397,62 +420,73 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid,
                     const char *name, int len,
                     const char *symname, int symlen)
 {
-        int error, payload_offset, size, s;
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        
-
-        /* 
-         * allocate space for regular input, 
-         * plus 1 path and 1 name, plus padding 
-         */        
-       size = sizeof(struct inputArgs) + CFS_MAXNAMLEN + CFS_MAXNAMLEN + 8;
-       UPARG(size, CFS_SYMLINK);
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+        int offset, s;
+
+        offset = INSIZE(symlink);
+       insize = max(offset + len + symlen + 8, OUTSIZE(symlink));
+       UPARG(CFS_SYMLINK);
         
-        /*        inp->d.cfs_symlink.attr = *tva; XXXXXX */ 
-        inp->d.cfs_symlink.VFid = *fid;
-
-        payload_offset = VC_INSIZE(cfs_symlink_in);
-        inp->d.cfs_symlink.srcname =(char*) payload_offset;
-    
-        s = ( symlen  & ~0x3 ) + 4; /* Round up to word boundary. */
-    
-        /* don't forget to copy out the null termination */
-        memcpy((char *)inp + payload_offset, symname, symlen);
-        *((char *)inp + payload_offset + symlen) = '\0';
+        /*        inp->cfs_symlink.attr = *tva; XXXXXX */ 
+        inp->cfs_symlink.VFid = *fid;
+
+       /* Round up to word boundary and null terminate */
+        inp->cfs_symlink.srcname = offset;
+        s = ( symlen  & ~0x3 ) + 4; 
+        memcpy((char *)(inp) + offset, symname, symlen);
+        *((char *)inp + offset + symlen) = '\0';
         
-        payload_offset += s;
-        inp->d.cfs_symlink.tname = (char *) payload_offset;
-        s = (len & ~0x3) + 4;  /* Round up to word boundary. */
-        memcpy((char *)inp + payload_offset, name, len);
-        *((char *)inp + payload_offset + len) = '\0';
+       /* Round up to word boundary and null terminate */
+        offset += s;
+        inp->cfs_symlink.tname = offset;
+        s = (len & ~0x3) + 4;
+        memcpy((char *)(inp) + offset, name, len);
+        *((char *)inp + offset + len) = '\0';
 
-        size = payload_offset + s;
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+       error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
         if (inp) 
-               CODA_FREE(inp, size);
+               CODA_FREE(inp, insize);
         CDEBUG(D_INODE, " result %d\n",error);
         EXIT;
         return -error;
 }
 
+int venus_fsync(struct super_block *sb, struct ViceFid *fid)
+{
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
+       
+       insize=SIZE(fsync);
+       UPARG(CFS_FSYNC);
+
+        inp->cfs_fsync.VFid = *fid;
+        error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs), 
+                            &outsize, inp);
+
+       if ( inp ) 
+               CODA_FREE(inp, insize);
+       return -error;
+}
+
 int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
 {
-        struct inputArgs *inp;
-        struct outputArgs *outp;
-        int size;
-        int error;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
 
-       size = sizeof(struct inputArgs);
-       UPARG(size, CFS_ACCESS);
+       insize = SIZE(access);
+       UPARG(CFS_ACCESS);
 
-        inp->d.cfs_access.VFid = *fid;
-        inp->d.cfs_access.flags = mask << 6;
+        inp->cfs_access.VFid = *fid;
+        inp->cfs_access.flags = mask;
 
-       error = coda_upcall(coda_sbp(sb), size, &size, inp);
+       error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-       if (inp) CODA_FREE(inp, sizeof(struct inputArgs));
+       if (inp) CODA_FREE(inp, insize);
         EXIT;
        return -error;
 }
@@ -461,41 +495,46 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
 int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
                 unsigned int cmd, struct PioctlData *data)
 {
-        struct inputArgs *inp;
-       struct outputArgs *outp;
-       int size, error = 0;
+        union inputArgs *inp;
+        union outputArgs *outp;
+        int insize, outsize, error;
        int iocsize;
        char str[50];
 
-       size = VC_MAXMSGSIZE;
-       UPARG(size, CFS_IOCTL);
+       insize = VC_MAXMSGSIZE;
+       UPARG(CFS_IOCTL);
 
         /* build packet for Venus */
-        if (data->vi.in_size > VC_DATASIZE) {
+        if (data->vi.in_size > VC_MAXDATASIZE) {
                error = EINVAL;
                goto exit;
         }
 
-        inp->d.cfs_ioctl.VFid = *fid;
+        inp->cfs_ioctl.VFid = *fid;
     
         /* the cmd field was mutated by increasing its size field to
          * reflect the path and follow args. We need to subtract that
          * out before sending the command to Venus.  */
-        inp->d.cfs_ioctl.cmd = (cmd & ~(IOCPARM_MASK << 16));  
-        iocsize = ((cmd >> 16) & IOCPARM_MASK) - sizeof(char *) - sizeof(int);
-        inp->d.cfs_ioctl.cmd |= (iocsize & IOCPARM_MASK) <<    16;     
+        inp->cfs_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
+        iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
+        inp->cfs_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<     16;     
     
-        /* in->d.cfs_ioctl.rwflag = flag; */
-        inp->d.cfs_ioctl.len = data->vi.in_size;
-        inp->d.cfs_ioctl.data = (char *)(VC_INSIZE(cfs_ioctl_in));
+        /* in->cfs_ioctl.rwflag = flag; */
+        inp->cfs_ioctl.len = data->vi.in_size;
+        inp->cfs_ioctl.data = (char *)(INSIZE(ioctl));
      
         /* get the data out of user space */
-        if ( copy_from_user((char*)inp + (int)inp->d.cfs_ioctl.data,
+#ifdef L20
+        memcpy_fromfs((char*)inp + (int)inp->cfs_ioctl.data,
+                      data->vi.in, data->vi.in_size);
+#else
+        if ( copy_from_user((char*)inp + (int)inp->cfs_ioctl.data,
                            data->vi.in, data->vi.in_size) ) {
                error = EINVAL;
                goto exit;
        }
-        error = coda_upcall(coda_sbp(sb), size, &size, inp);
+#endif
+        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
         
         if (error) {
                printk("coda_pioctl: Venus returns: %d for %s\n", 
@@ -504,23 +543,32 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
        }
         
        /* Copy out the OUT buffer. */
-        if (outp->d.cfs_ioctl.len > data->vi.out_size) {
+        if (outp->cfs_ioctl.len > data->vi.out_size) {
                 CDEBUG(D_FILE, "return len %d <= request len %d\n",
-                      outp->d.cfs_ioctl.len, 
+                      outp->cfs_ioctl.len, 
                       data->vi.out_size);
                 error = EINVAL;
         } else {
-                if (copy_to_user(data->vi.out, 
-                                (char *)outp + (int)outp->d.cfs_ioctl.data, 
+               error = verify_area(VERIFY_WRITE, data->vi.out, 
+                                    data->vi.out_size);
+               if ( error ) goto exit;
+#ifdef L20
+                memcpy_tofs(data->vi.out, 
+                            (char *)outp + (int)outp->cfs_ioctl.data, 
+                            data->vi.out_size);                
+#else
+               if (copy_to_user(data->vi.out, 
+                                (char *)outp + (int)outp->cfs_ioctl.data, 
                                 data->vi.out_size)) {
                        error = EINVAL;
                        goto exit;
                }
+#endif
         }
 
  exit:
         if (inp) 
-               CODA_FREE(inp, VC_MAXMSGSIZE);
+               CODA_FREE(inp, insize);
        return -error;
 }
 
@@ -535,11 +583,38 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
  * reply and return Venus' error, also POSITIVE. 
  * 
  */
+static inline void coda_waitfor_upcall(struct vmsg *vmp)
+{
+       struct wait_queue       wait = { current, NULL };
+
+       vmp->vm_posttime = jiffies;
+
+       add_wait_queue(&vmp->vm_sleep, &wait);
+       for (;;) {
+               if ( coda_hard == 0 ) 
+                       current->state = TASK_INTERRUPTIBLE;
+               else
+                       current->state = TASK_UNINTERRUPTIBLE;
+
+               if ( vmp->vm_flags & VM_WRITE )
+                       break;
+               if (signal_pending(current) &&
+                   (jiffies > vmp->vm_posttime + coda_timeout * HZ) )
+                       break;
+               schedule();
+       }
+       remove_wait_queue(&vmp->vm_sleep, &wait);
+       current->state = TASK_RUNNING;
+
+       return;
+}
+
+
 int coda_upcall(struct coda_sb_info *sbi, int inSize, int *outSize, 
-               struct inputArgs *buffer) 
+               union inputArgs *buffer) 
 {
        struct vcomm *vcommp;
-       struct outputArgs *out;
+       union outputArgs *out;
        struct vmsg *vmp;
        int error = 0;
 
@@ -550,7 +625,7 @@ ENTRY;
        }
        vcommp = sbi->sbi_vcomm;
 
-       clstats(((struct inputArgs *)buffer)->opcode);
+       clstats(((union inputArgs *)buffer)->ih.opcode);
 
        if (!vcomm_open(vcommp))
                 return(ENODEV);
@@ -561,16 +636,15 @@ ENTRY;
        vmp->vm_flags = 0;
        vmp->vm_inSize = inSize;
        vmp->vm_outSize = *outSize ? *outSize : inSize;
-       vmp->vm_opcode = ((struct inputArgs *)buffer)->opcode;
+       vmp->vm_opcode = ((union inputArgs *)buffer)->ih.opcode;
        vmp->vm_unique = ++vcommp->vc_seq;
         vmp->vm_sleep = NULL;
        
        /* Fill in the common input args. */
-       ((struct inputArgs *)buffer)->unique = vmp->vm_unique;
+       ((union inputArgs *)buffer)->ih.unique = vmp->vm_unique;
 
        /* Append msg to pending queue and poke Venus. */
-
-       INSQUE(vmp->vm_chain, vcommp->vc_pending);
+       coda_q_insert(&(vmp->vm_chain), &(vcommp->vc_pending));
        CDEBUG(D_UPCALL, 
               "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %x.zzz.\n",
               current->pid, vmp->vm_opcode, vmp->vm_unique, (int)vmp);
@@ -582,13 +656,15 @@ ENTRY;
         * read but before the reply, we dequeue, send a signal
         * message, and return. If it occurs after the reply we ignore
         * it. In no case do we want to restart the syscall.  If it
-        * was interrupted by a venus shutdown (vcclose), return
+        * was interrupted by a venus shutdown (psdev_close), return
         * ENODEV.  */
 
-       /* Ignore return, We have to check anyway */
+       /* Go to sleep.  Wake up on signals only after the timeout. */
+       coda_waitfor_upcall(vmp);
 
-
-       interruptible_sleep_on(&vmp->vm_sleep);
+       CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
+              vmp->vm_opcode, jiffies - vmp->vm_posttime, 
+              vmp->vm_unique, vmp->vm_outSize);
        CDEBUG(D_UPCALL, 
               "..process %d woken up by Venus for vmp at 0x%x, data at %x\n", 
               current->pid, (int)vmp, (int)vmp->vm_data);
@@ -596,60 +672,61 @@ ENTRY;
            /* Op went through, interrupt or not... */
            if (vmp->vm_flags & VM_WRITE) {
                error = 0;
-               out = (struct outputArgs *)vmp->vm_data;
-               error = out->result;
+               out = (union outputArgs *)vmp->vm_data;
+               error = out->oh.result;
                CDEBUG(D_UPCALL, 
-                      "upcall: (u,o,r) (%ld, %ld, %ld) out at %x\n", 
-                      out->unique, out->opcode, out->result, (int)out);
+                      "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n", 
+                      out->oh.unique, out->oh.opcode, out->oh.result, out);
                *outSize = vmp->vm_outSize;
                goto exit;
-           } 
-           if (!(vmp->vm_flags & VM_READ)) { 
+           }
+           if ( !(vmp->vm_flags & VM_READ) && signal_pending(current)) { 
                /* Interrupted before venus read it. */
                CDEBUG(D_UPCALL, 
                       "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
                       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
-               REMQUE(vmp->vm_chain);
-               error = ERESTARTSYS;
+               coda_q_remove(&(vmp->vm_chain));
+               error = ERESTARTNOHAND;
                goto exit;
            } 
-           if ( vmp->vm_flags & VM_READ) {     
+           if ( (vmp->vm_flags & VM_READ) && signal_pending(current) ) {
                /* interrupted after Venus did its read, send signal */
-               struct inputArgs *dog;
+               union inputArgs *dog;
                struct vmsg *svmp;
                
                CDEBUG(D_UPCALL, 
                       "Sending Venus a signal: op = %d.%d, flags = %x\n",
                       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
                
-               REMQUE(vmp->vm_chain);
-               error = ERESTARTSYS;
+               coda_q_remove(&(vmp->vm_chain));
+               error = ERESTARTNOHAND;
                
                CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
-               CODA_ALLOC((svmp->vm_data), char *, VC_IN_NO_DATA);
+               CODA_ALLOC((svmp->vm_data), char *, sizeof(struct cfs_in_hdr));
 
+               dog = (union inputArgs *)svmp->vm_data;
+               dog->ih.opcode = CFS_SIGNAL;
+               dog->ih.unique = vmp->vm_unique;
+               
+               svmp->vm_flags = 0;
+               svmp->vm_opcode = dog->ih.opcode;
+               svmp->vm_unique = dog->ih.unique;
+               svmp->vm_inSize = sizeof(struct cfs_in_hdr);
+               svmp->vm_outSize = sizeof(struct cfs_in_hdr);
                CDEBUG(D_UPCALL, 
                       "coda_upcall: enqueing signal msg (%d, %d)\n",
                       svmp->vm_opcode, svmp->vm_unique);
-               dog = (struct inputArgs *)svmp->vm_data;
-               dog->opcode = CFS_SIGNAL;
-               dog->unique = vmp->vm_unique;
-               
-               svmp->vm_flags = 0;
-               svmp->vm_opcode = dog->opcode;
-               svmp->vm_unique = dog->unique;
-               svmp->vm_inSize = VC_IN_NO_DATA;
-               svmp->vm_outSize = VC_IN_NO_DATA;
                
                /* insert at head of queue! */
-               INSQUE(svmp->vm_chain, vcommp->vc_pending);
+               coda_q_insert(&(svmp->vm_chain), vcommp->vc_pending.forw);
                wake_up_interruptible(&vcommp->vc_waitq);
+           } else {
+                   printk("Coda: Strange interruption..\n");
+                   error = EINTR;
            }
        } else {        /* If venus died i.e. !VC_OPEN(vcommp) */
-               printk("coda_upcall: Venus dead upon (op,un) (%d.%d) flags %d\n",
+               printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
                       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
-               
-               /* if (! (vmp->vm_flags & VM_WRITE) ) */
                error = ENODEV;
        }
 
@@ -670,78 +747,106 @@ ENTRY;
  * CFS_FLUSH     -- flush all entries from the name cache and the cnode cache.
  * CFS_PURGEUSER -- flush all entries from the name cache for a specific user
  *                  This call is a result of token expiration.
- *                  Linux does a cfsnc_flush since cred's are not maintained.
  *
  * The next arise as the result of callbacks on a file or directory.
  * CFS_ZAPDIR    -- flush the attributes for the dir from its cnode.
  *                  Zap all children of this directory from the namecache.
  * CFS_ZAPFILE   -- flush the cached attributes for a file.
- * CFS_ZAPVNODE  -- in linux the same as zap file (no creds).
+ * CFS_ZAPVNODE  -- intended to be a zapfile for just one cred. Not used?
  *
  * The next is a result of Venus detecting an inconsistent file.
  * CFS_PURGEFID  -- flush the attribute for the file
- *                  If it is a dir (odd vnode), purge its 
- *                  children from the namecache
- *                  remove the file from the namecache.
+ *                  purge it and its children from the dcache
  *
  * The last  allows Venus to replace local fids with global ones
  * during reintegration.
  *
  * CFS_REPLACE -- replace one ViceFid with another throughout the name cache */
 
-int coda_downcall(int opcode, struct outputArgs * out)
+int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 {
 
     /* Handle invalidate requests. */
     switch (opcode) {
-      case CFS_FLUSH : {
-             clstats(CFS_FLUSH);
-             cfsnc_flush();
-             return(0);
-      }
-      case CFS_PURGEUSER : {
-             clstats(CFS_PURGEUSER);
-             cfsnc_flush();
-             return(0);
-      }
-      case CFS_ZAPDIR : {
-             ViceFid *fid = &out->d.cfs_zapdir.CodaFid;
-             clstats(CFS_ZAPDIR);
-             cfsnc_zapfid(fid);
-             cfsnc_zapParentfid(fid);     
-             CDEBUG(D_UPCALL, "zapdir: fid = (%lx.%lx.%lx), \n",fid->Volume, 
-                                         fid->Vnode, 
-                                         fid->Unique);
-             return(0);
-      }
-      case CFS_ZAPVNODE : {
-              clstats(CFS_ZAPVNODE);
-             cfsnc_zapfid(&out->d.cfs_zapvnode.VFid);
-             return(0);
-      }        
-      case CFS_ZAPFILE : {
-              clstats(CFS_ZAPFILE);
-             cfsnc_zapfid(&out->d.cfs_zapfile.CodaFid);
-             return 0;
-      }
-      case CFS_PURGEFID : {
-             ViceFid *fid = &out->d.cfs_purgefid.CodaFid;
-              clstats(CFS_PURGEFID);
-             cfsnc_zapfid(fid);
-             cfsnc_zapParentfid(fid);     
-             CDEBUG(D_UPCALL, "purgefid: fid = (%lx.%lx.%lx)\n", 
-                                            fid->Volume, fid->Vnode,
-                                            fid->Unique);
-             return 0;
-      }
-      case CFS_REPLACE : {
-              clstats(CFS_REPLACE);
-             cfsnc_replace(&out->d.cfs_replace.OldFid, 
-                           &out->d.cfs_replace.NewFid);
-             return (0);
-      }                           
+    case CFS_FLUSH : {
+           clstats(CFS_FLUSH);
+           CDEBUG(D_DOWNCALL, "CFS_FLUSH\n");
+           coda_cache_clear_all(sb);
+           shrink_dcache_sb(sb);
+           return(0);
+    }
+    case CFS_PURGEUSER : {
+           struct coda_cred *cred = &out->cfs_purgeuser.cred;
+           CDEBUG(D_DOWNCALL, "CFS_PURGEUSER\n");
+           if ( !cred ) {
+                   printk("PURGEUSER: null cred!\n");
+                   return 0;
+           }
+           clstats(CFS_PURGEUSER);
+           coda_cache_clear_cred(sb, cred);
+           return(0);
+    }
+    case CFS_ZAPDIR : {
+           ViceFid *fid = &out->cfs_zapdir.CodaFid;
+           char str[50];
+           if ( !fid ) {
+                   printk("ZAPDIR: Null fid\n");
+                   return 0;
+           }
+           CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid, str));
+           clstats(CFS_ZAPDIR);
+           coda_zapfid(fid, sb, C_ZAPDIR);
+           return(0);
+    }
+    case CFS_ZAPVNODE : {
+           ViceFid *fid = &out->cfs_zapvnode.VFid;
+           char str[50];
+           struct coda_cred *cred = &out->cfs_zapvnode.cred;
+           if ( !fid || !cred ) {
+                   printk("ZAPVNODE: Null fid or cred\n");
+                   return 0;
+           }
+           CDEBUG(D_DOWNCALL, "zapvnode: fid = %s\n", coda_f2s(fid, str));
+           coda_zapfid(fid, sb, C_ZAPFID);
+           coda_cache_clear_cred(sb, cred);
+           clstats(CFS_ZAPVNODE);
+           return(0);
+    }
+    case CFS_ZAPFILE : {
+           struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
+           char str[50];
+           clstats(CFS_ZAPFILE);
+           if ( !fid ) {
+                   printk("ZAPFILE: Null fid\n");
+                   return 0;
+           }
+           CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid, str));
+           coda_zapfid(fid, sb, C_ZAPFID);
+           return 0;
+    }
+    case CFS_PURGEFID : {
+           ViceFid *fid = &out->cfs_purgefid.CodaFid;
+           char str[50];
+           if ( !fid ) {
+                   printk("PURGEFID: Null fid\n");
+                   return 0;
+           }
+           CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid, str));
+           clstats(CFS_PURGEFID);
+           coda_zapfid(fid, sb, C_ZAPDIR);
+           return 0;
+    }
+    case CFS_REPLACE : {
+           printk("CFS_REPLACCE\n");
+           clstats(CFS_REPLACE);
+           CDEBUG(D_DOWNCALL, "CFS_REPLACE\n");
+           coda_cache_clear_all(sb);
+           shrink_dcache_sb(sb);
+           return (0);
+    }                     
     }
       return 0;
 }
 
 
+                
index ba3707f0dafe4ffb92675ec1a6679de32a1334ff..7555b9a6f5b6e3eadd15bc8ac64c952eea107bd5 100644 (file)
@@ -39,11 +39,7 @@ int ext2_permission (struct inode * inode, int mask)
         */
        if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
                return -EACCES;
-       /*
-        * Special case, access is always granted for root
-        */
-       if (fsuser())
-               return 0;
+
        /*
         * If no ACL, checks using the file mode
         */
@@ -51,7 +47,11 @@ int ext2_permission (struct inode * inode, int mask)
                mode >>= 6;
        else if (in_group_p (inode->i_gid))
                mode >>= 3;
-       if (((mode & mask & S_IRWXO) == mask))
+       /*
+        * Access is always granted for root. We now check last,
+         * though, for BSD process accounting correctness
+        */
+       if (((mode & mask & S_IRWXO) == mask) || fsuser())
                return 0;
        else
                return -EACCES;
index 7e159e7d286d80ff68cc4b3f60023368e6fc39ec..4f2e65bfc994e690b69dac8b6696139d7639cbf3 100644 (file)
@@ -295,9 +295,9 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
        lock_super (sb);
        es = sb->u.ext2_sb.s_es;
        if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
-           (!fsuser() && (sb->u.ext2_sb.s_resuid != current->fsuid) &&
+           ((sb->u.ext2_sb.s_resuid != current->fsuid) &&
             (sb->u.ext2_sb.s_resgid == 0 ||
-             !in_group_p (sb->u.ext2_sb.s_resgid)))) {
+             !in_group_p (sb->u.ext2_sb.s_resgid)) && !fsuser())) {
                unlock_super (sb);
                return 0;
        }
index 0fa14cfe1d6926812601b0c51450eac8ccd418c4..42df76bdaf5faf3fd8a1100013782f371b5384d9 100644 (file)
@@ -640,7 +640,7 @@ int ext2_notify_change(struct inode *inode, struct iattr *iattr)
             (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
            (inode->u.ext2_i.i_flags &
             (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
-               if (!fsuser() || securelevel > 0)
+               if (securelevel > 0 || !fsuser())
                        return -EPERM;
        } else
                if ((current->fsuid != inode->i_uid) && !fsuser())
index a907785f3ddf17c34f5fd9601c1d827d57cd46d5..8edc480ac52b9ffd823da856d679c5f75efd0cca 100644 (file)
@@ -566,7 +566,7 @@ int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
        tmp.f_bavail = free;
        tmp.f_files = 0;
        tmp.f_ffree = 0;
-       tmp.f_namelen = 12;
+       tmp.f_namelen = MSDOS_SB(sb)->options.isvfat ? 260 : 12;
        return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
index 5964fefd79a68b84631a53209a3123b22fa7dc22..0fd10bc573223c4cc4caf7bd3bb51db9d1b7cc93 100644 (file)
@@ -86,6 +86,10 @@ __initfunc(static void do_sys_setup(void))
        init_nfs_fs();
 #endif
 
+#ifdef CONFIG_CODA_FS
+       init_coda_fs();
+#endif
+
 #ifdef CONFIG_SMB_FS
        init_smb_fs();
 #endif
index dbd9e9ce4e6616303b78fa821ddc56f65b3efa43..91902542170b99b342815c0dc3b20ce621a35b48 100644 (file)
@@ -414,9 +414,9 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry)
        retval = -EPERM;
        inode = dentry->d_inode;
 
-        if ((dir->i_mode & S_ISVTX) && !fsuser() &&
+        if ((dir->i_mode & S_ISVTX) &&
             current->fsuid != inode->i_uid &&
-            current->fsuid != dir->i_uid)
+            current->fsuid != dir->i_uid && !fsuser())
                goto end_rmdir;
        if (inode->i_dev != dir->i_dev)
                goto end_rmdir;
@@ -480,9 +480,9 @@ repeat:
                schedule();
                goto repeat;
        }
-       if ((dir->i_mode & S_ISVTX) && !fsuser() &&
+       if ((dir->i_mode & S_ISVTX) &&
            current->fsuid != inode->i_uid &&
-           current->fsuid != dir->i_uid)
+           current->fsuid != dir->i_uid && !fsuser())
                goto end_unlink;
        if (de->inode != inode->i_ino) {
                retval = -ENOENT;
index ab8d6089e75a2f5fd974c3299b29255d074de99b..d55e5df494c820551ea0e0812f5050687e0dcf6b 100644 (file)
@@ -843,6 +843,9 @@ static inline int do_rmdir(const char * name)
        if (dir->d_inode->i_sb && dir->d_inode->i_sb->dq_op)
                dir->d_inode->i_sb->dq_op->initialize(dir->d_inode, -1);
 
+       if (dentry->d_count > 1)
+               shrink_dcache_parent(dentry);
+
        error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry);
 
 exit_lock:
index aaf17187bbe82dd762ef51bd0026cc4c91d321da..73663574d9e6f5a718209391ac9db6b4b12c47b7 100644 (file)
@@ -439,7 +439,8 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
         */
        if (list_empty(&dentry->d_hash) && dentry->d_inode) {
                struct inode *inode = dentry->d_inode;
-               if (inode->i_count > 1) {
+               int max_count = (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink);
+               if (inode->i_count > max_count) {
 printk("nfs_dentry_delete: %s/%s: ino=%ld, count=%d, nlink=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name,
 inode->i_ino, inode->i_count, inode->i_nlink);
@@ -499,7 +500,7 @@ static int nfs_lookup(struct inode *dir, struct dentry * dentry)
                inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
                if (inode) {
 #ifdef NFS_PARANOIA
-if (inode->i_count > 1)
+if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink))
 printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name,
 inode->i_ino, inode->i_count, inode->i_nlink);
@@ -511,6 +512,11 @@ inode->i_ino, inode->i_count, inode->i_nlink);
                        error = 0;
                }
        }
+#ifdef NFS_PARANOIA
+if (error)
+printk("nfs_lookup: %s/%s failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
+#endif
 out:
        return error;
 }
@@ -555,7 +561,7 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
        inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
        if (inode) {
 #ifdef NFS_PARANOIA
-if (inode->i_count > 1)
+if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink))
 printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name,
 inode->i_ino, inode->i_count, inode->i_nlink);
@@ -669,8 +675,9 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                return -ENOENT;
        }
 
+       error = -ENAMETOOLONG;
        if (dentry->d_name.len > NFS_MAXNAMLEN)
-               return -ENAMETOOLONG;
+               goto out;
 
        /* For some reason mode doesn't have the S_IFDIR flag ... */
        mode |= S_IFDIR;
@@ -702,6 +709,7 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        drop:
                d_drop(dentry);
        }
+out:
        return error;
 }
 
@@ -876,11 +884,11 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                        goto out;
        } while(sdentry->d_inode != NULL); /* need negative lookup */
 
+       nfs_invalidate_dircache(dir);
        error = nfs_proc_rename(NFS_SERVER(dir),
                                NFS_FH(dir), dentry->d_name.name,
                                NFS_FH(dir), silly);
        if (!error) {
-               nfs_invalidate_dircache(dir);
                nfs_renew_times(dentry);
                d_move(dentry, sdentry);
                dentry->d_flags |= DCACHE_NFSFS_RENAMED;
@@ -1036,10 +1044,10 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
         * can't instantiate the new inode.
         */
        d_drop(dentry);
+       nfs_invalidate_dircache(dir);
        error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
                                dentry->d_name.name, symname, &sattr);
        if (!error) {
-               nfs_invalidate_dircache(dir);
                nfs_renew_times(dentry->d_parent);
        } else if (error == -EEXIST) {
                printk("nfs_proc_symlink: %s/%s already exists??\n",
@@ -1068,10 +1076,10 @@ nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
        if (dentry->d_name.len > NFS_MAXNAMLEN)
                goto out;
 
+       nfs_invalidate_dircache(dir);
        error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode), NFS_FH(dir),
                                dentry->d_name.name);
        if (!error) {
-               nfs_invalidate_dircache(dir);
                inode->i_count ++;
                inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
                d_instantiate(dentry, inode);
@@ -1209,6 +1217,8 @@ do_rename:
                d_drop(new_dentry);
                rehash = update;
        }
+       nfs_invalidate_dircache(new_dir);
+       nfs_invalidate_dircache(old_dir);
        error = nfs_proc_rename(NFS_SERVER(old_dir),
                                NFS_FH(old_dir), old_dentry->d_name.name,
                                NFS_FH(new_dir), new_dentry->d_name.name);
@@ -1221,8 +1231,6 @@ printk("nfs_rename: %s/%s busy after rename, d_count=%d\n",
 new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
 #endif
        if (!error) {
-               nfs_invalidate_dircache(new_dir);
-               nfs_invalidate_dircache(old_dir);
                /* Update the dcache if needed */
                if (update)
                        d_move(old_dentry, new_dentry);
index eb56950eb618508e762830cde28c73a2fda301e8..684a49358d104c4794128d101689b53c90e6a481 100644 (file)
@@ -260,12 +260,8 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
        server->client    = clnt;
 
        /* Fire up rpciod if not yet running */
-#ifdef RPCIOD_RESULT
-       if (rpciod_up())
+       if (rpciod_up() != 0)
                goto out_no_iod;
-#else
-       rpciod_up();
-#endif
 
        /*
         * Keep the super block locked while we try to get 
@@ -290,13 +286,11 @@ out_no_root:
        printk("nfs_read_super: get root inode failed\n");
        iput(root_inode);
        rpciod_down();
-#ifdef RPCIOD_RESULT
        goto out_shutdown;
 
 out_no_iod:
-       printk("nfs_read_super: couldn't start rpciod!\n");
+       printk("NFS: couldn't start rpciod!\n");
 out_shutdown:
-#endif
        rpc_shutdown_client(server->client);
        goto out_unlock;
 
index 0311b7d0b71bf3cd85a74d96e24d4b4f233ff52f..8879e02a853caa947765e7a80e7b259e0940015b 100644 (file)
@@ -564,6 +564,7 @@ static struct {
        { NFSERR_EAGAIN,        EAGAIN          },
        { NFSERR_ACCES,         EACCES          },
        { NFSERR_EXIST,         EEXIST          },
+       { NFSERR_XDEV,          EXDEV           },
        { NFSERR_NODEV,         ENODEV          },
        { NFSERR_NOTDIR,        ENOTDIR         },
        { NFSERR_ISDIR,         EISDIR          },
index 94096d928a76857333285b38efdc932d8542452e..6ef7b9282a051077a363decba355f722f2f44d08 100644 (file)
@@ -584,6 +584,7 @@ static struct {
        { NFSERR_EAGAIN,        EAGAIN          },
        { NFSERR_ACCES,         EACCES          },
        { NFSERR_EXIST,         EEXIST          },
+       { NFSERR_XDEV,          EXDEV           },
        { NFSERR_NODEV,         ENODEV          },
        { NFSERR_NOTDIR,        ENOTDIR         },
        { NFSERR_ISDIR,         EISDIR          },
index b7c7dfba70599750b0ae960aa8fe7d24b95292ef..8c816e2b98d7c39d56c9b87936a5fa4c48228b22 100644 (file)
@@ -1,14 +1,10 @@
 /*
- *  $Id: nfsroot.c,v 1.38 1997/07/17 03:21:06 davem Exp $
+ *  $Id: nfsroot.c,v 1.43 1997/10/16 19:55:27 mj Exp $
  *
  *  Copyright (C) 1995, 1996  Gero Kuhlmann <gero@gkminix.han.de>
  *
- *  For parts of this file:
- *  Copyright (C) 1996, 1997  Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
  *  Allow an NFS filesystem to be mounted as root. The way this works is:
- *     (1) Determine the local IP address via RARP or BOOTP or from the
- *         kernel command line.
+ *     (1) Use the IP autoconfig mechanism to set local IP addresses and routes.
  *     (2) Handle RPC negotiation with the system which replied to RARP or
  *         was reported as a boot server by BOOTP or manually.
  *     (3) The actual mounting is done later, when init() is running.
@@ -47,7 +43,7 @@
  *                             from being used (thanks to Leo Spiekman)
  *     Andy Walker     :       Allow to specify the NFS server in nfs_root
  *                             without giving a path name
- *     Swen Th=FCmmler :       Allow to specify the NFS options in nfs_root
+ *     Swen Thümmler   :       Allow to specify the NFS options in nfs_root
  *                             without giving a path name. Fix BOOTP request
  *                             for domainname (domainname is NIS domain, not
  *                             DNS domain!). Skip dummy devices for BOOTP.
  *     Jakub Jelinek   :       Free used code segment.
  *     Marko Kohtala   :       Fixed some bugs.
  *     Martin Mares    :       Debug message cleanup
- *
+ *     Martin Mares    :       Changed to use the new generic IP layer autoconfig
+ *                             code. BOOTP and RARP moved there.
+ *     Martin Mares    :       Default path now contains host name instead of
+ *                             host IP address (but host name defaults to IP
+ *                             address anyway).
  */
 
-
-/* Define this to allow debugging output */
-#undef NFSROOT_DEBUG
-#undef NFSROOT_BOOTP_DEBUG
-
-
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
-#include <linux/random.h>
-#include <linux/fcntl.h>
 #include <linux/init.h>
-
-#include <asm/param.h>
-#include <linux/utsname.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/inet.h>
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#ifdef CONFIG_AX25
-#include <net/ax25.h>  /* For AX25_P_IP */
-#endif
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/socket.h>
-#include <linux/route.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/in.h>
-#include <net/route.h>
-#include <net/sock.h>
-
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
-#define NFSDBG_FACILITY                NFSDBG_ROOT
-/* Range of privileged ports */
-#define STARTPORT              600
-#define ENDPORT                        1023
-#define NPORTS                 (ENDPORT - STARTPORT + 1)
-
-
-/* Define the timeout for waiting for a RARP/BOOTP reply */
-#define CONF_BASE_TIMEOUT      (HZ*5)  /* Initial timeout: 5 seconds */
-#define CONF_RETRIES           10      /* 10 retries */
-#define CONF_TIMEOUT_RANDOM    (HZ)    /* Maximum amount of randomization */
-#define CONF_TIMEOUT_MULT      *5/4    /* Speed of timeout growth */
-#define CONF_TIMEOUT_MAX       (HZ*30) /* Maximum allowed timeout */
-
-
-/* List of open devices */
-struct open_dev {
-       struct device *dev;
-       unsigned short old_flags;
-       struct open_dev *next;
-};
-
-static struct open_dev *open_base __initdata = NULL;
-
-
-/* IP configuration */
-static struct device *root_dev __initdata = NULL;      /* Device selected for booting */
-static char user_dev_name[IFNAMSIZ] __initdata = { 0, };/* Name of user-selected boot device */
-static __u32 myaddr __initdata = 0;                    /* My IP address */
-static __u32 servaddr __initdata = 0;                  /* Server IP address */
-static __u32 gateway __initdata = 0;                   /* Gateway IP address */
-static __u32 netmask __initdata = 0;                   /* Netmask for local subnet */
+#include <linux/inet.h>
+#include <linux/major.h>
+#include <linux/utsname.h>
+#include <net/ipconfig.h>
 
+/* Define this to allow debugging output */
+#undef NFSROOT_DEBUG
+#define NFSDBG_FACILITY NFSDBG_ROOT
 
-/* BOOTP/RARP variables */
-static int bootp_flag __initdata = 0;          /* User said: Use BOOTP! */
-static int rarp_flag __initdata = 0;           /* User said: Use RARP! */
-static int bootp_dev_count __initdata = 0;     /* Number of devices allowing BOOTP */
-static int rarp_dev_count __initdata = 0;      /* Number of devices allowing RARP */
-static __u32 rarp_serv __initdata = 0;         /* IP address of RARP server */
+/* Default path we try to mount. "%s" gets replaced by our IP address */
+#define NFS_ROOT               "/tftpboot/%s"
+#define NFS_ROOT_NAME_LEN      256
 
-#if defined(CONFIG_RNFS_BOOTP) || defined(CONFIG_RNFS_RARP)
-#define CONFIG_RNFS_DYNAMIC                    /* Enable dynamic IP config */
-static volatile int pkt_arrived __initdata = 0;        /* BOOTP/RARP packet detected */
+/* Parameters passed from the kernel command line */
+static char nfs_root_name[NFS_ROOT_NAME_LEN] __initdata = "default";
 
-#define ARRIVED_BOOTP  1
-#define ARRIVED_RARP   2
-#endif
+/* Address of NFS server */
+static __u32 servaddr __initdata = 0;
 
+/* Name of directory to mount */
+static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, };
 
 /* NFS-related data */
 static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
-static char    nfs_path[NFS_MAXPATHLEN] __initdata = { 0, };/* Name of directory to mount */
-static int     nfs_port __initdata = 0;                /* Port to connect to for NFS */
-static int     mount_port __initdata = 0;              /* Mount daemon port number */
-
-
-/* Yes, we use sys_socket, but there's no include file for it */
-extern asmlinkage int sys_socket(int family, int type, int protocol);
-
-
-
-/***************************************************************************
-
-                       Device Handling Subroutines
-
- ***************************************************************************/
-
-/*
- * Setup and initialize all network devices. If there is a user-preferred
- * interface, ignore all other interfaces.
- */
-__initfunc(static int root_dev_open(void))
-{
-       struct open_dev *openp, **last;
-       struct device *dev;
-       unsigned short old_flags;
-
-       last = &open_base;
-       for (dev = dev_base; dev != NULL; dev = dev->next) {
-               if (dev->type < ARPHRD_SLIP &&
-                   dev->family == AF_INET &&
-                   !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) &&
-                   (0 != strncmp(dev->name, "dummy", 5)) &&
-                   (!user_dev_name[0] || !strcmp(dev->name, user_dev_name))) {
-                       /* First up the interface */
-                       old_flags = dev->flags;
-                       dev->flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
-                       if (!(old_flags & IFF_UP) && dev_open(dev)) {
-                               dev->flags = old_flags;
-                               continue;
-                       }
-                       openp = (struct open_dev *) kmalloc(sizeof(struct open_dev),
-                                               GFP_ATOMIC);
-                       if (openp == NULL)
-                               continue;
-                       openp->dev = dev;
-                       openp->old_flags = old_flags;
-                       *last = openp;
-                       last = &openp->next;
-                       bootp_dev_count++;
-                       if (!(dev->flags & IFF_NOARP))
-                               rarp_dev_count++;
-                       dprintk("Root-NFS: Opened %s\n", dev->name);
-               }
-       }
-       *last = NULL;
-
-       if (!bootp_dev_count && !rarp_dev_count) {
-               printk(KERN_ERR "Root-NFS: Unable to open at least one network device\n");
-               return -1;
-       }
-       return 0;
-}
-
-static inline void
-set_sockaddr(struct sockaddr_in *sin, __u32 addr, __u16 port)
-{
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = addr;
-       sin->sin_port = port;
-}
-
-__initfunc(static int
-root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw))
-{
-       struct rtentry  route;
-       mm_segment_t    oldfs;
-       int             err;
-
-       memset(&route, 0, sizeof(struct rtentry));      /* or else! */
-
-       route.rt_dev = dev->name;
-       route.rt_mtu = dev->mtu;
-       route.rt_flags = RTF_UP;
-       set_sockaddr((struct sockaddr_in *) &route.rt_dst, dest & mask, 0);
-       set_sockaddr((struct sockaddr_in *) &route.rt_genmask, mask, 0);
-
-       if (gw != 0) {
-               set_sockaddr((struct sockaddr_in *) &route.rt_gateway, gw, 0);
-               route.rt_flags |= RTF_GATEWAY;
-               if ((gw ^ myaddr) & netmask) {
-                       printk(KERN_ERR "Root-NFS: Gateway not on local network!\n");
-                       return -ENETUNREACH;
-               }
-       }
-
-       oldfs = get_fs();
-       set_fs(KERNEL_DS);
-       err = ip_rt_ioctl(op, &route);
-       set_fs(oldfs);
-
-#ifdef NFSROOT_DEBUG
-       /* in_ntoa in ipv4/utils.c uses a single static buffer, so
-        * must make multiple printk calls, one for each in_ntoa
-        * invocation...
-        */
-       printk(KERN_NOTICE "%s route ", (op == SIOCADDRT ? "add" : "del"));
-       printk("%s ", in_ntoa(dest));
-       printk("%s ", in_ntoa(mask));
-       printk("%s: res %d\n", in_ntoa(gw), err);
-#endif
-
-       return err;
-}
-
-__initfunc(static int
-root_dev_add_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway))
-{
-       return root_dev_chg_route(SIOCADDRT, dev, dest, mask, gateway);
-}
-
-__initfunc(static int
-root_dev_del_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway))
-{
-       return root_dev_chg_route(SIOCDELRT, dev, dest, mask, gateway);
-}
-
-/*
- *  Restore the state of all devices. However, keep the root device open
- *  for the upcoming mount.
- */
-__initfunc(static void root_dev_close(void))
-{
-       struct open_dev *openp;
-       struct open_dev *nextp;
-
-       openp = open_base;
-       while (openp != NULL) {
-               nextp = openp->next;
-               openp->next = NULL;
-               if (openp->dev != root_dev) {
-                       if (!(openp->old_flags & IFF_UP)) {
-                               dev_close(openp->dev);
-                       }
-
-                       openp->dev->flags = openp->old_flags;
-               }
-               kfree_s(openp, sizeof(struct open_dev));
-               openp = nextp;
-       }
-}
-
-
-
-/***************************************************************************
-
-                             RARP Subroutines
-
- ***************************************************************************/
-
-#ifdef CONFIG_RNFS_RARP
-
-extern void arp_send(int type, int ptype, unsigned long target_ip,
-                    struct device *dev, unsigned long src_ip,
-                    unsigned char *dest_hw, unsigned char *src_hw,
-                    unsigned char *target_hw);
-
-static int root_rarp_recv(struct sk_buff *skb, struct device *dev,
-                         struct packet_type *pt);
-
-
-static struct packet_type rarp_packet_type __initdata = {
-       0,                      /* Should be: __constant_htons(ETH_P_RARP)
-                                * - but this _doesn't_ come out constant! */
-       NULL,                   /* Listen to all devices */
-       root_rarp_recv,
-       NULL,
-       NULL
-};
-
-
-/*
- *  Register the packet type for RARP
- */
-__initfunc(static void root_rarp_open(void))
-{
-       rarp_packet_type.type = htons(ETH_P_RARP);
-       dev_add_pack(&rarp_packet_type);
-}
-
-
-/*
- *  Deregister the RARP packet type
- */
-__initfunc(static void root_rarp_close(void))
-{
-       rarp_packet_type.type = htons(ETH_P_RARP);
-       dev_remove_pack(&rarp_packet_type);
-}
-
-
-/*
- *  Receive RARP packets.
- */
-__initfunc(static int
-root_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt))
-{
-       struct arphdr *rarp = (struct arphdr *)skb->h.raw;
-       unsigned char *rarp_ptr = (unsigned char *) (rarp + 1);
-       unsigned long sip, tip;
-       unsigned char *sha, *tha;               /* s for "source", t for "target" */
-
-       /* If this test doesn't pass, it's not IP, or we should ignore it anyway */
-       if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) {
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-
-       /* If it's not a RARP reply, delete it. */
-       if (rarp->ar_op != htons(ARPOP_RREPLY)) {
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-
-       /* If it's not ethernet or AX25, delete it. */
-       if ((rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) ||
-#ifdef CONFIG_AX25
-          (rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) ||
-#endif
-           rarp->ar_pln != 4) {
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-
-       /* Extract variable width fields */
-       sha = rarp_ptr;
-       rarp_ptr += dev->addr_len;
-       memcpy(&sip, rarp_ptr, 4);
-       rarp_ptr += 4;
-       tha = rarp_ptr;
-       rarp_ptr += dev->addr_len;
-       memcpy(&tip, rarp_ptr, 4);
-
-       /* Discard packets which are not meant for us. */
-       if (memcmp(tha, dev->dev_addr, dev->addr_len)) {
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-       /* Discard packets which are not from specified server. */
-       if (rarp_flag && !bootp_flag &&
-           rarp_serv != INADDR_NONE &&
-           rarp_serv != sip) {
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-
-       /*
-        * The packet is what we were looking for. Setup the global
-        * variables.
-        */
-       cli();
-       if (pkt_arrived) {
-               sti();
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-       pkt_arrived = ARRIVED_RARP;
-       sti();
-       root_dev = dev;
-
-       if (myaddr == INADDR_NONE)
-               myaddr = tip;
-       if (servaddr == INADDR_NONE)
-               servaddr = sip;
-       kfree_skb(skb, FREE_READ);
-       return 0;
-}
-
-
-/*
- *  Send RARP request packet over all devices which allow RARP.
- */
-__initfunc(static void root_rarp_send(void))
-{
-       struct open_dev *openp;
-       struct device *dev;
-       int num = 0;
-
-       for (openp = open_base; openp != NULL; openp = openp->next) {
-               dev = openp->dev;
-               if (!(dev->flags & IFF_NOARP)) {
-                       arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
-                                dev->dev_addr, dev->dev_addr);
-                       num++;
-               }
-       }
-}
-#endif
-
-
-
-/***************************************************************************
-
-                            BOOTP Subroutines
-
- ***************************************************************************/
-
-#ifdef CONFIG_RNFS_BOOTP
-
-static struct device *bootp_dev __initdata = NULL;     /* Device selected as best BOOTP target */
-
-static struct socket *bootp_xmit_sock __initdata = NULL;/* BOOTP send socket */
-static struct socket *bootp_recv_sock __initdata = NULL;/* BOOTP receive socket */
-
-struct bootp_pkt {             /* BOOTP packet format */
-       u8 op;                  /* 1=request, 2=reply */
-       u8 htype;               /* HW address type */
-       u8 hlen;                /* HW address length */
-       u8 hops;                /* Used only by gateways */
-       u32 xid;                /* Transaction ID */
-       u16 secs;               /* Seconds since we started */
-       u16 flags;              /* Just what is says */
-       u32 client_ip;          /* Client's IP address if known */
-       u32 your_ip;            /* Assigned IP address */
-       u32 server_ip;          /* Server's IP address */
-       u32 relay_ip;           /* IP address of BOOTP relay */
-       u8 hw_addr[16];         /* Client's HW address */
-       u8 serv_name[64];       /* Server host name */
-       u8 boot_file[128];      /* Name of boot file */
-       u8 vendor_area[128];    /* Area for extensions */
-};
-
-#define BOOTP_REQUEST 1
-#define BOOTP_REPLY 2
-
-static struct bootp_pkt *xmit_bootp __initdata = NULL; /* Packet being transmitted */
-static struct bootp_pkt *recv_bootp __initdata = NULL; /* Packet being received */
-
-static int bootp_have_route __initdata = 0;    /* BOOTP route installed */
-
-
-/*
- *  Free BOOTP packet buffers
- */
-__initfunc(static void root_free_bootp(void))
-{
-       if (xmit_bootp) {
-               kfree_s(xmit_bootp, sizeof(struct bootp_pkt));
-               xmit_bootp = NULL;
-       }
-       if (recv_bootp) {
-               kfree_s(recv_bootp, sizeof(struct bootp_pkt));
-               recv_bootp = NULL;
-       }
-}
-
-
-/*
- *  Allocate memory for BOOTP packet buffers
- */
-static inline int root_alloc_bootp(void)
-{
-       if (!(xmit_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL)) ||
-           !(recv_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL))) {
-               printk(KERN_ERR "BOOTP: Out of memory!\n");
-               return -1;
-       }
-       return 0;
-}
-
-
-/*
- *  Create default route for BOOTP sending
- */
-__initfunc(static int root_add_bootp_route(void))
-{
-       if (root_dev_add_route(bootp_dev, 0, 0, 0) < 0) {
-               printk(KERN_ERR "BOOTP: Failed to add route\n");
-               return -1;
-       }
-       bootp_have_route = 1;
-       return 0;
-}
-
-
-/*
- *  Delete default route for BOOTP sending
- */
-__initfunc(static int root_del_bootp_route(void))
-{
-       if (bootp_have_route && root_dev_del_route(bootp_dev, 0, 0, 0) < 0) {
-               printk(KERN_ERR "BOOTP: Deleting of route failed!\n");
-               return -1;
-       }
-       bootp_have_route = 0;
-       return 0;
-}
-
-
-/*
- *  Open UDP socket.
- */
-__initfunc(static int root_open_udp_sock(struct socket **sock))
-{
-       int     err;
-
-       if ((err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, sock)) < 0)
-               printk(KERN_ERR "BOOTP: Cannot open UDP socket!\n");
-       return err;
-}
-
-
-/*
- *  Connect UDP socket.
- */
-__initfunc(static int
-root_connect_udp_sock(struct socket *sock, u32 addr, u16 port))
-{
-       struct sockaddr_in sa;
-       int result;
-
-       set_sockaddr(&sa, htonl(addr), htons(port));
-       result = sock->ops->connect(sock, (struct sockaddr *) &sa, sizeof(sa), 0);
-       if (result < 0) {
-               printk(KERN_ERR "BOOTP: connect() failed\n");
-               return -1;
-       }
-       return 0;
-}
-
-
-/*
- *  Bind UDP socket.
- */
-__initfunc(static int
-root_bind_udp_sock(struct socket *sock, u32 addr, u16 port))
-{
-       struct sockaddr_in sa;
-       int result;
-
-       set_sockaddr(&sa, htonl(addr), htons(port));
-       result = sock->ops->bind(sock, (struct sockaddr *) &sa, sizeof(sa));
-       if (result < 0) {
-               printk(KERN_ERR "BOOTP: bind() failed\n");
-               return -1;
-       }
-       return 0;
-}
-
-
-/*
- *  Send UDP packet.
- */
-static inline int root_send_udp(struct socket *sock, void *buf, int size)
-{
-       mm_segment_t oldfs;
-       int result;
-       struct msghdr msg;
-       struct iovec iov;
-
-       oldfs = get_fs();
-       set_fs(get_ds());
-       iov.iov_base = buf;
-       iov.iov_len = size;
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       result = sock_sendmsg(sock, &msg, size);
-       set_fs(oldfs);
-
-       return (result != size);
-}
-
-
-/*
- *  Try to receive UDP packet.
- */
-static inline int root_recv_udp(struct socket *sock, void *buf, int size)
-{
-       mm_segment_t oldfs;
-       int result;
-       struct msghdr msg;
-       struct iovec iov;
-
-       oldfs = get_fs();
-       set_fs(get_ds());
-       iov.iov_base = buf;
-       iov.iov_len = size;
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_flags = MSG_DONTWAIT;
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       result = sock_recvmsg(sock, &msg, size, MSG_DONTWAIT);
-       set_fs(oldfs);
-       return result;
-}
-
-
-/*
- *  Initialize BOOTP extension fields in the request.
- */
-__initfunc(static void root_bootp_init_ext(u8 *e))
-{
-       *e++ = 99;              /* RFC1048 Magic Cookie */
-       *e++ = 130;
-       *e++ = 83;
-       *e++ = 99;
-       *e++ = 1;               /* Subnet mask request */
-       *e++ = 4;
-       e += 4;
-       *e++ = 3;               /* Default gateway request */
-       *e++ = 4;
-       e += 4;
-       *e++ = 12;              /* Host name request */
-       *e++ = 32;
-       e += 32;
-       *e++ = 40;              /* NIS Domain name request */
-       *e++ = 32;
-       e += 32;
-       *e++ = 17;              /* Boot path */
-       *e++ = 32;
-       e += 32;
-       *e = 255;               /* End of the list */
-}
-
-
-/*
- *  Deinitialize the BOOTP mechanism.
- */
-__initfunc(static void root_bootp_close(void))
-{
-       if (bootp_xmit_sock)
-               sock_release(bootp_xmit_sock);
-       if (bootp_recv_sock)
-               sock_release(bootp_recv_sock);
-       root_del_bootp_route();
-       root_free_bootp();
-}
-
-
-/*
- *  Initialize the BOOTP mechanism.
- */
-__initfunc(static int root_bootp_open(void))
-{
-       struct open_dev *openp;
-       struct device *dev, *best_dev;
-
-       /*
-        * Select the best interface for BOOTP. We try to select a first
-        * Ethernet-like interface. It's shame I know no simple way how to send
-        * BOOTP's to all interfaces, but it doesn't apply to usual diskless
-        * stations as they don't have multiple interfaces.
-        */
-
-       best_dev = NULL;
-       for (openp = open_base; openp != NULL; openp = openp->next) {
-               dev = openp->dev;
-               if (dev->flags & IFF_BROADCAST) {
-                       if (!best_dev ||
-                          ((best_dev->flags & IFF_NOARP) && !(dev->flags & IFF_NOARP)))
-                               best_dev = dev;
-                       }
-               }
-
-       if (!best_dev) {
-               printk(KERN_ERR "BOOTP: This cannot happen!\n");
-               return -1;
-       }
-       bootp_dev = best_dev;
-
-       /* Allocate memory for BOOTP packets */
-       if (root_alloc_bootp())
-               return -1;
-
-       /* Construct BOOTP request */
-       memset(xmit_bootp, 0, sizeof(struct bootp_pkt));
-       xmit_bootp->op = BOOTP_REQUEST;
-       get_random_bytes(&xmit_bootp->xid, sizeof(xmit_bootp->xid));
-       xmit_bootp->htype = best_dev->type;
-       xmit_bootp->hlen = best_dev->addr_len;
-       memcpy(xmit_bootp->hw_addr, best_dev->dev_addr, best_dev->addr_len);
-       root_bootp_init_ext(xmit_bootp->vendor_area);
-
-#ifdef NFSROOT_BOOTP_DEBUG
-       {
-               int x;
-               printk(KERN_NOTICE "BOOTP: XID=%08x, DE=%s, HT=%02x, HL=%02x, HA=",
-                       xmit_bootp->xid,
-                       best_dev->name,
-                       xmit_bootp->htype,
-                       xmit_bootp->hlen);
-               for(x=0; x<xmit_bootp->hlen; x++)
-                       printk("%02x", xmit_bootp->hw_addr[x]);
-               printk("\n");
-       }
-#endif
-
-       /* Create default route to that interface */
-       if (root_add_bootp_route())
-               return -1;
-
-       /* Open the sockets */
-       if (root_open_udp_sock(&bootp_xmit_sock) ||
-           root_open_udp_sock(&bootp_recv_sock))
-               return -1;
-
-       /* Bind/connect the sockets */
-       bootp_xmit_sock->sk->broadcast = 1;
-       bootp_xmit_sock->sk->reuse = 1;
-       bootp_recv_sock->sk->reuse = 1;
-       if (root_bind_udp_sock(bootp_recv_sock, INADDR_ANY, 68) ||
-           root_bind_udp_sock(bootp_xmit_sock, INADDR_ANY, 68) ||
-           root_connect_udp_sock(bootp_xmit_sock, INADDR_BROADCAST, 67))
-               return -1;
-
-       return 0;
-}
-
-
-/*
- *  Send BOOTP request.
- */
-__initfunc(static int root_bootp_send(u32 jiffies))
-{
-       xmit_bootp->secs = htons(jiffies / HZ);
-       return root_send_udp(bootp_xmit_sock, xmit_bootp, sizeof(struct bootp_pkt));
-}
-
-
-/*
- *  Copy BOOTP-supplied string if not already set.
- */
-__initfunc(static int
-root_bootp_string(char *dest, char *src, int len, int max))
-{
-       if (*dest || !len)
-               return 0;
-       if (len > max-1)
-               len = max-1;
-       strncpy(dest, src, len);
-       dest[len] = '\0';
-       return 1;
-}
-
-
-/*
- *  Process BOOTP extension.
- */
-__initfunc(static void root_do_bootp_ext(u8 *ext))
-{
-#ifdef NFSROOT_BOOTP_DEBUG
-       u8 *c;
-
-       printk(KERN_DEBUG "BOOTP: Got extension %02x",*ext);
-       for(c=ext+2; c<ext+2+ext[1]; c++)
-               printk(" %02x", *c);
-       printk("\n");
-#endif
-
-       switch (*ext++) {
-               case 1:         /* Subnet mask */
-                       if (netmask == INADDR_NONE)
-                               memcpy(&netmask, ext+1, 4);
-                       break;
-               case 3:         /* Default gateway */
-                       if (gateway == INADDR_NONE)
-                               memcpy(&gateway, ext+1, 4);
-                       break;
-               case 12:        /* Host name */
-                       root_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
-                       break;
-               case 40:        /* NIS Domain name */
-                       root_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN);
-                       break;
-               case 17:        /* Root path */
-                       root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN);
-                       break;
-       }
-}
-
-
-/*
- *  Receive BOOTP request.
- */
-__initfunc(static void root_bootp_recv(void))
-{
-       int len;
-       u8 *ext, *end, *opt;
-
-       len = root_recv_udp(bootp_recv_sock, recv_bootp, sizeof(struct bootp_pkt));
-       if (len < 0)
-               return;
-
-       /* Check consistency of incoming packet */
-       if (len < 300 ||                        /* See RFC 1542:2.1 */
-           recv_bootp->op != BOOTP_REPLY ||
-           recv_bootp->htype != xmit_bootp->htype ||
-           recv_bootp->hlen != xmit_bootp->hlen ||
-           recv_bootp->xid != xmit_bootp->xid) {
-               dprintk("?");
-               return;
-               }
-
-       /* Record BOOTP packet arrival in the global variables */
-       cli();
-       if (pkt_arrived) {
-               sti();
-               return;
-       }
-       pkt_arrived = ARRIVED_BOOTP;
-       sti();
-       root_dev = bootp_dev;
-
-       /* Extract basic fields */
-       myaddr = recv_bootp->your_ip;
-       if (servaddr==INADDR_NONE)
-               servaddr = recv_bootp->server_ip;
-
-       /* Parse extensions */
-       if (recv_bootp->vendor_area[0] == 99 && /* Check magic cookie */
-           recv_bootp->vendor_area[1] == 130 &&
-           recv_bootp->vendor_area[2] == 83 &&
-           recv_bootp->vendor_area[3] == 99) {
-               ext = &recv_bootp->vendor_area[4];
-               end = (u8 *) recv_bootp + len;
-               while (ext < end && *ext != 255) {
-                       if (*ext == 0)          /* Padding */
-                               ext++;
-                       else {
-                               opt = ext;
-                               ext += ext[1] + 2;
-                               if (ext <= end)
-                                       root_do_bootp_ext(opt);
-                       }
-               }
-       }
-}
-#endif
-
-
-
-/***************************************************************************
-
-                       Dynamic configuration of IP.
-
- ***************************************************************************/
-
-#ifdef CONFIG_RNFS_DYNAMIC
-
-/*
- *  Determine client and server IP numbers and appropriate device by using
- *  the RARP and BOOTP protocols.
- */
-__initfunc(static int root_auto_config(void))
-{
-       int retries;
-       unsigned long timeout, jiff;
-       unsigned long start_jiffies;
-
-       /*
-        * If neither BOOTP nor RARP was selected, return with an error. This
-        * routine gets only called when some pieces of information are mis-
-        * sing, and without BOOTP and RARP we are not able to get that in-
-        * formation.
-        */
-       if (!bootp_flag && !rarp_flag) {
-               printk(KERN_ERR "Root-NFS: Neither RARP nor BOOTP selected.\n");
-               return -1;
-       }
-
-#ifdef CONFIG_RNFS_BOOTP
-       if (bootp_flag && !bootp_dev_count) {
-               printk(KERN_ERR "Root-NFS: No suitable device for BOOTP found.\n");
-               bootp_flag = 0;
-       }
-#else
-       bootp_flag = 0;
-#endif
-
-#ifdef CONFIG_RNFS_RARP
-       if (rarp_flag && !rarp_dev_count) {
-               printk(KERN_ERR "Root-NFS: No suitable device for RARP found.\n");
-               rarp_flag = 0;
-       }
-#else
-       rarp_flag = 0;
-#endif
-
-       if (!bootp_flag && !rarp_flag)
-               /* Error message already printed */
-               return -1;
-
-       /*
-        * Setup RARP and BOOTP protocols
-        */
-#ifdef CONFIG_RNFS_RARP
-       if (rarp_flag)
-               root_rarp_open();
-#endif
-#ifdef CONFIG_RNFS_BOOTP
-       if (bootp_flag && root_bootp_open() < 0) {
-               root_bootp_close();
-               return -1;
-       }
-#endif
-
-       /*
-        * Send requests and wait, until we get an answer. This loop
-        * seems to be a terrible waste of CPU time, but actually there is
-        * only one process running at all, so we don't need to use any
-        * scheduler functions.
-        * [Actually we could now, but the nothing else running note still 
-        *  applies.. - AC]
-        */
-       printk(KERN_NOTICE "Sending %s%s%s requests...",
-               bootp_flag ? "BOOTP" : "",
-               bootp_flag && rarp_flag ? " and " : "",
-               rarp_flag ? "RARP" : "");
-       start_jiffies = jiffies;
-       retries = CONF_RETRIES;
-       get_random_bytes(&timeout, sizeof(timeout));
-       timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
-       for(;;) {
-#ifdef CONFIG_RNFS_BOOTP
-               if (bootp_flag && root_bootp_send(jiffies - start_jiffies) < 0) {
-                       printk(" BOOTP failed!\n");
-                       root_bootp_close();
-                       bootp_flag = 0;
-                       if (!rarp_flag)
-                               break;
-               }
-#endif
-#ifdef CONFIG_RNFS_RARP
-               if (rarp_flag)
-                       root_rarp_send();
-#endif
-               printk(".");
-               jiff = jiffies + timeout;
-               while (jiffies < jiff && !pkt_arrived)
-#ifdef CONFIG_RNFS_BOOTP
-                       root_bootp_recv();
-#else
-                       ;
-#endif
-               if (pkt_arrived) {
-                       printk(" OK\n");
-                       break;
-               }
-               if (! --retries) {
-                       printk(" timed out!\n");
-                       break;
-               }
-               timeout = timeout CONF_TIMEOUT_MULT;
-               if (timeout > CONF_TIMEOUT_MAX)
-                       timeout = CONF_TIMEOUT_MAX;
-       }
+static int nfs_port __initdata = 0;            /* Port to connect to for NFS */
+static int mount_port __initdata = 0;          /* Mount daemon port number */
 
-#ifdef CONFIG_RNFS_RARP
-       if (rarp_flag)
-               root_rarp_close();
-#endif
-#ifdef CONFIG_RNFS_BOOTP
-       if (bootp_flag)
-               root_bootp_close();
-#endif
-
-       if (!pkt_arrived)
-               return -1;
-
-       printk(KERN_NOTICE "Root-NFS: Got %s answer from %s, ",
-               (pkt_arrived == ARRIVED_BOOTP) ? "BOOTP" : "RARP",
-               in_ntoa(servaddr));
-       printk("my address is %s\n", in_ntoa(myaddr));
-
-       return 0;
-}
-#endif
-
-/* Get default netmask - used to be exported from net/ipv4 */
-static inline unsigned long
-ip_get_mask(unsigned long addr)
-{
-       if (!addr)
-               return 0;
-       addr = ntohl(addr);
-       if (IN_CLASSA(addr))
-               return htonl(IN_CLASSA_NET);
-       if (IN_CLASSB(addr))
-               return htonl(IN_CLASSB_NET);
-       if (IN_CLASSC(addr))
-               return htonl(IN_CLASSC_NET);
-       return 0;
-}
 
 /***************************************************************************
 
@@ -1054,7 +105,6 @@ ip_get_mask(unsigned long addr)
 
  ***************************************************************************/
 
-
 /*
  *  The following integer options are recognized
  */
@@ -1125,31 +175,32 @@ __initfunc(static int root_nfs_name(char *name))
                        *cp++ = '\0';
                servaddr = in_aton(name);
                name = cp;
+       } else if ((servaddr = root_server_addr) == INADDR_NONE) {
+               printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n");
+               return -1;
        }
 
        /* Clear the nfs_data structure and setup the server hostname */
        memset(&nfs_data, 0, sizeof(nfs_data));
-       strncpy(nfs_data.hostname, in_ntoa(servaddr),
-                                               sizeof(nfs_data.hostname)-1);
+       strncpy(nfs_data.hostname, in_ntoa(servaddr), sizeof(nfs_data.hostname)-1);
        nfs_data.namlen = strlen(nfs_data.hostname);
 
        /* Set the name of the directory to mount */
-       if (nfs_path[0] == '\0' || strncmp(name, "default", 7))
-               strncpy(buf, name, NFS_MAXPATHLEN);
+       if (root_server_path[0] && !strcmp(name, "default"))
+               strncpy(buf, root_server_path, NFS_MAXPATHLEN-1);
        else
-               strncpy(buf, nfs_path, NFS_MAXPATHLEN);
+               strncpy(buf, name, NFS_MAXPATHLEN-1);
+       buf[NFS_MAXPATHLEN-1] = '\0';
        if ((options = strchr(buf, ',')))
                *options++ = '\0';
        if (!strcmp(buf, "default"))
                strcpy(buf, NFS_ROOT);
-       cp = in_ntoa(myaddr);
+       cp = system_utsname.nodename;
        if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
                printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
                return -1;
        }
-       /* update nfs_path with path from nfsroot=... command line parameter */
-       if (*buf)
-               sprintf(nfs_path, buf, cp);
+       sprintf(nfs_path, buf, cp);
 
        /* Set some default values */
        nfs_port          = -1;
@@ -1198,17 +249,6 @@ __initfunc(static int root_nfs_name(char *name))
 #ifdef NFSROOT_DEBUG
 __initfunc(static void root_nfs_print(void))
 {
-#define IN_NTOA(x) (((x) == INADDR_NONE) ? "none" : in_ntoa(x))
-
-       printk(KERN_NOTICE "Root-NFS: IP config: dev=%s, ",
-               root_dev ? root_dev->name : "none");
-       printk("local=%s, ", IN_NTOA(myaddr));
-       printk("server=%s, ", IN_NTOA(servaddr));
-       printk("gw=%s, ", IN_NTOA(gateway));
-       printk("mask=%s, ", IN_NTOA(netmask));
-       printk("host=%s, domain=%s\n",
-               system_utsname.nodename[0] ? system_utsname.nodename : "none",
-               system_utsname.domainname[0] ? system_utsname.domainname : "none");
        printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n",
                nfs_path, nfs_data.hostname);
        printk(KERN_NOTICE "Root-NFS:     rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
@@ -1216,245 +256,25 @@ __initfunc(static void root_nfs_print(void))
        printk(KERN_NOTICE "Root-NFS:     acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n",
                nfs_data.acregmin, nfs_data.acregmax,
                nfs_data.acdirmin, nfs_data.acdirmax);
-       printk(KERN_NOTICE "Root-NFS:     port = %d, flags = %08x\n",
-               nfs_port, nfs_data.flags);
-
-#undef IN_NTOA
+       printk(KERN_NOTICE "Root-NFS:     nfsd port = %d, mountd port = %d, flags = %08x\n",
+               nfs_port, mount_port, nfs_data.flags);
 }
 #endif
 
 
-/*
- *  Decode any IP configuration options in the "nfsaddrs" kernel command
- *  line parameter. It consists of option fields separated by colons in
- *  the following order:
- *
- *  <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<bootp|rarp>
- *
- *  Any of the fields can be empty which means to use a default value:
- *     <client-ip>     - address given by BOOTP or RARP
- *     <server-ip>     - address of host returning BOOTP or RARP packet
- *     <gw-ip>         - none, or the address returned by BOOTP
- *     <netmask>       - automatically determined from <client-ip>, or the
- *                       one returned by BOOTP
- *     <host name>     - <client-ip> in ASCII notation, or the name returned
- *                       by BOOTP
- *     <device>        - use all available devices for RARP and the first
- *                       one for BOOTP
- *     <bootp|rarp>    - use both protocols to determine my own address
- */
-__initfunc(static void root_nfs_addrs(char *addrs))
-{
-       char *cp, *ip, *dp;
-       int num = 0;
-
-       /* Clear all addresses and strings */
-       myaddr = servaddr = rarp_serv = gateway = netmask = INADDR_NONE;
-       system_utsname.nodename[0] = '\0';
-       system_utsname.domainname[0] = '\0';
-       user_dev_name[0] = '\0';
-       bootp_flag = rarp_flag = 1;
-
-       /* The following is just a shortcut for automatic IP configuration */
-       if (!strcmp(addrs, "bootp")) {
-               rarp_flag = 0;
-               return;
-       } else if (!strcmp(addrs, "rarp")) {
-               bootp_flag = 0;
-               return;
-       } else if (!strcmp(addrs, "both")) {
-               return;
-       }
-
-       /* Parse the whole string */
-       ip = addrs;
-       while (ip && *ip) {
-               if ((cp = strchr(ip, ':')))
-                       *cp++ = '\0';
-               if (strlen(ip) > 0) {
-                       dprintk("Root-NFS: Config string num %d is \"%s\"\n",
-                                                               num, ip);
-                       switch (num) {
-                       case 0:
-                               if ((myaddr = in_aton(ip)) == INADDR_ANY)
-                                       myaddr = INADDR_NONE;
-                               break;
-                       case 1:
-                               if ((servaddr = in_aton(ip)) == INADDR_ANY)
-                                       servaddr = INADDR_NONE;
-                               break;
-                       case 2:
-                               if ((gateway = in_aton(ip)) == INADDR_ANY)
-                                       gateway = INADDR_NONE;
-                               break;
-                       case 3:
-                               if ((netmask = in_aton(ip)) == INADDR_ANY)
-                                       netmask = INADDR_NONE;
-                               break;
-                       case 4:
-                               if ((dp = strchr(ip, '.'))) {
-                                       *dp++ = '\0';
-                                       strncpy(system_utsname.domainname, dp, __NEW_UTS_LEN);
-                                       system_utsname.domainname[__NEW_UTS_LEN] = '\0';
-                               }
-                               strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN);
-                               system_utsname.nodename[__NEW_UTS_LEN] = '\0';
-                               break;
-                       case 5:
-                               strncpy(user_dev_name, ip, IFNAMSIZ);
-                               user_dev_name[IFNAMSIZ-1] = '\0';
-                               break;
-                       case 6:
-                               if (!strcmp(ip, "rarp"))
-                                       bootp_flag = 0;
-                               else if (!strcmp(ip, "bootp"))
-                                       rarp_flag = 0;
-                               else if (strcmp(ip, "both"))
-                                       bootp_flag = rarp_flag = 0;
-                               break;
-                       default:
-                               break;
-                       }
-               }
-               ip = cp;
-               num++;
-       }
-       rarp_serv = servaddr;
-}
-
-
-/*
- *  Set the interface address and configure a route to the server.
- */
-__initfunc(static int root_nfs_setup(void))
-{
-       /* Set the default system name in case none was previously found */
-       if (!system_utsname.nodename[0]) {
-               strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN);
-               system_utsname.nodename[__NEW_UTS_LEN] = '\0';
-       }
-
-       /* Set the correct netmask */
-       if (netmask == INADDR_NONE)
-               netmask = ip_get_mask(myaddr);
-
-       /* Setup the device correctly */
-       root_dev->family     = AF_INET;
-       root_dev->pa_addr    = myaddr;
-       root_dev->pa_mask    = netmask;
-       root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask;
-       root_dev->pa_dstaddr = 0;
-
-       /* Sticky situation, but it has a solution.  We opened it earlier,
-        * but before we knew what pa_addr etc. to give to it, thus the
-        * routing code did not add a RTF_LOCAL route for it (how could
-        * it?) so we send the pseudo device state change event now.  -DaveM
-        */
-       ip_rt_event(NETDEV_CHANGE, root_dev);
-
-       /*
-        * Now add a route to the server. If there is no gateway given,
-        * the server is on the same subnet, so we establish only a route to
-        * the local network. Otherwise we create a route to the gateway (the
-        * same local network router as in the former case) and then setup a
-        * gatewayed default route. Note that this gives sufficient network
-        * setup even for full system operation in all common cases.
-        */
-       if (root_dev_add_route(root_dev, myaddr, netmask, 0))
-       {
-               printk(KERN_ERR "Root-NFS: Adding of local route failed!\n");
-               return -1;
-       }
-
-       if (gateway != INADDR_NONE) {   /* Default route */
-               if (root_dev_add_route(root_dev, INADDR_ANY, INADDR_ANY, gateway)) {
-                       printk(KERN_ERR "Root-NFS: Adding of default route failed!\n");
-                       return -1;
-               }
-       } else if ((servaddr ^ myaddr) & netmask) {
-               printk(KERN_ERR "Root-NFS: Boot server not on local network and no default gateway configured!\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-
-/*
- *  Get the necessary IP addresses and prepare for mounting the required
- *  NFS filesystem.
- */
-__initfunc(int nfs_root_init(char *nfsname, char *nfsaddrs))
+__initfunc(int root_nfs_init(void))
 {
 #ifdef NFSROOT_DEBUG
        nfs_debug |= NFSDBG_ROOT;
 #endif
 
-       /*
-        * Decode IP addresses and other configuration info contained
-        * in the nfsaddrs string (which came from the kernel command
-        * line).
-        */
-       root_nfs_addrs(nfsaddrs);
-
-       /*
-        * Setup all network devices
-        */
-       if (root_dev_open() < 0)
-               return -1;
-
-       /*
-        * If the config information is insufficient (e.g., our IP address or
-        * IP address of the boot server is missing or we have multiple network
-        * interfaces and no default was set), use BOOTP or RARP to get the
-        * missing values.
-        *
-        * Note that we don't try to set up correct routes for multiple
-        * interfaces (could be solved by trying icmp echo requests), because
-        * it's only necessary in the rare case of multiple ethernet devices
-        * in the (diskless) system and if the server is on another subnet.
-        * If only one interface is installed, the routing is obvious.
-        */
-       if ((myaddr == INADDR_NONE ||
-            servaddr == INADDR_NONE ||
-            (open_base != NULL && open_base->next != NULL))
-#ifdef CONFIG_RNFS_DYNAMIC
-               && root_auto_config() < 0
-#endif
-          ) {
-               root_dev_close();
-               return -1;
-       }
-       if (root_dev == NULL) {
-               if (open_base != NULL && open_base->next == NULL) {
-                       root_dev = open_base->dev;
-               } else {
-                       printk(KERN_ERR "Root-NFS: Multiple devices and no server\n");
-                       root_dev_close();
-                       return -1;
-               }
-       }
-
-       /*
-        * Close all network devices except the device which connects to
-        * server
-        */
-       root_dev_close();
-
        /*
         * Decode the root directory path name and NFS options from
         * the kernel command line. This has to go here in order to
         * be able to use the client IP address for the remote root
         * directory (necessary for pure RARP booting).
         */
-       if (root_nfs_name(nfsname) < 0)
-               return -1;
-
-       /*
-        * Setup devices and routes. The server directory is actually
-        * mounted after init() has been started.
-        */
-       if (root_nfs_setup() < 0)
+       if (root_nfs_name(nfs_root_name) < 0)
                return -1;
 
 #ifdef NFSROOT_DEBUG
@@ -1465,34 +285,64 @@ __initfunc(int nfs_root_init(char *nfsname, char *nfsaddrs))
 }
 
 
+/*
+ *  Parse NFS server and directory information passed on the kernel
+ *  command line.
+ */
+__initfunc(void nfs_root_setup(char *line, int *ints))
+{
+       ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
+       if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
+               strncpy(nfs_root_name, line, sizeof(nfs_root_name));
+               nfs_root_name[sizeof(nfs_root_name)-1] = '\0';
+       } else {
+               int n = strlen(line) + strlen(NFS_ROOT);
+               if (n >= sizeof(nfs_root_name))
+                       line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
+               sprintf(nfs_root_name, NFS_ROOT, line);
+       }
+}
+
+
 /***************************************************************************
 
               Routines to actually mount the root directory
 
  ***************************************************************************/
+
 /*
- *  Query server portmapper for the port of a daemon program
+ *  Construct sockaddr_in from address and port number.
+ */
+static inline void
+set_sockaddr(struct sockaddr_in *sin, __u32 addr, __u16 port)
+{
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = addr;
+       sin->sin_port = port;
+}
+
+/*
+ *  Query server portmapper for the port of a daemon program.
  */
 __initfunc(static int root_nfs_getport(int program, int version))
 {
-       struct sockaddr_in      sin;
+       struct sockaddr_in sin;
 
        printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n",
                program, version, in_ntoa(servaddr));
-               set_sockaddr(&sin, servaddr, 0);
-               return rpc_getport_external(&sin, program, version, IPPROTO_UDP);
+       set_sockaddr(&sin, servaddr, 0);
+       return rpc_getport_external(&sin, program, version, IPPROTO_UDP);
 }
 
 
 /*
- *  Get portnumbers for mountd and nfsd from server
- *  The RPC layer does support portmapper queries; the only reason to
- *  keep this code is that we may want to use fallback ports. But is there
- *  actually someone who does not run portmap?
+ *  Use portmapper to find mountd and nfsd port numbers if not overriden
+ *  by the user. Use defaults if portmapper is not available.
+ *  XXX: Is there any nfs server with no portmapper?
  */
 __initfunc(static int root_nfs_ports(void))
 {
-       int     port;
+       int port;
 
        if (nfs_port < 0) {
                if ((port = root_nfs_getport(NFS_PROGRAM, NFS_VERSION)) < 0) {
@@ -1510,10 +360,8 @@ __initfunc(static int root_nfs_ports(void))
                                "number from server, using default\n");
                port = NFS_MNT_PORT;
        }
-
        mount_port = htons(port);
-       dprintk("Root-NFS: Portmapper on server returned %d "
-               "as mountd port\n", port);
+       dprintk("Root-NFS: mountd port is %d\n", port);
 
        return 0;
 }
@@ -1521,12 +369,12 @@ __initfunc(static int root_nfs_ports(void))
 
 /*
  *  Get a file handle from the server for the directory which is to be
- *  mounted
+ *  mounted.
  */
 __initfunc(static int root_nfs_get_handle(void))
 {
        struct sockaddr_in sin;
-       int             status;
+       int status;
 
        set_sockaddr(&sin, servaddr, mount_port);
        status = nfs_mount(&sin, nfs_path, &nfs_data.root);
@@ -1539,7 +387,7 @@ __initfunc(static int root_nfs_get_handle(void))
 
 
 /*
- *  Now actually mount the given directory
+ *  Now actually mount the given directory.
  */
 __initfunc(static int root_nfs_do_mount(struct super_block *sb))
 {
@@ -1559,11 +407,10 @@ __initfunc(static int root_nfs_do_mount(struct super_block *sb))
  */
 __initfunc(int nfs_root_mount(struct super_block *sb))
 {
-       if (root_nfs_ports() < 0)
-               return -1;
-       if (root_nfs_get_handle() < 0)
-               return -1;
-       if (root_nfs_do_mount(sb) < 0)
+       if (root_nfs_init() < 0
+        || root_nfs_ports() < 0
+        || root_nfs_get_handle() < 0
+        || root_nfs_do_mount(sb) < 0)
                return -1;
        return 0;
 }
index 53c227e583fa83911cbad1b0e33cac8de4f25a1c..c0db335105b4cbc86fb5b95cbc738ad6b96fed42 100644 (file)
@@ -832,7 +832,7 @@ nfs_wback_lock(struct rpc_task *task)
                req->wb_flags |= NFS_WRITE_WANTLOCK;
 
        if (WB_WANTLOCK(req) && test_and_set_bit(PG_locked, &page->flags)) {
-               dprintk("NFS:      page already locked in writeback_lock!\n");
+               printk("NFS: page already locked in writeback_lock!\n");
                task->tk_timeout = 2 * HZ;
                rpc_sleep_on(&write_queue, task, NULL, NULL);
                return;
index ba0a134e4c5584e08451c71fe7a4a50becc3e557..33e6dfd26fe2cb4cfdfde1036d4b9b64db21313b 100644 (file)
@@ -205,8 +205,10 @@ struct nls_table *find_nls(char *charset)
 struct nls_table *load_nls(char *charset)
 {
        struct nls_table *nls;
+#ifdef CONFIG_KERNELD
        char buf[40];
        int ret;
+#endif
 
        nls = find_nls(charset);
        if (nls) {
index 22c26a07eec507e1da7e033c0e46e3cfee2e0370..90f464795f215d60c8f050f408bba689bb4ba346 100644 (file)
@@ -419,6 +419,11 @@ repeat:
        current->state = TASK_RUNNING;
 }
 
+/*
+ * Note: check the dirty flag before waiting, so we don't
+ * hold up the sync while mounting a device. (The newly
+ * mounted device won't need syncing.)
+ */
 void sync_supers(kdev_t dev)
 {
        struct super_block * sb;
@@ -428,6 +433,9 @@ void sync_supers(kdev_t dev)
                        continue;
                if (dev && sb->s_dev != dev)
                        continue;
+               if (!sb->s_dirt)
+                       continue;
+               /* N.B. Should lock the superblock while writing */
                wait_on_super(sb);
                if (!sb->s_dev || !sb->s_dirt)
                        continue;
@@ -444,13 +452,14 @@ struct super_block * get_super(kdev_t dev)
 
        if (!dev)
                return NULL;
+restart:
        s = 0+super_blocks;
        while (s < NR_SUPER+super_blocks)
                if (s->s_dev == dev) {
                        wait_on_super(s);
                        if (s->s_dev == dev)
                                return s;
-                       s = 0+super_blocks;
+                       goto restart;
                } else
                        s++;
        return NULL;
@@ -494,33 +503,44 @@ static struct super_block * read_super(kdev_t dev,const char *name,int flags,
        struct file_system_type *type;
 
        if (!dev)
-               return NULL;
+               goto out_fail;
        check_disk_change(dev);
        s = get_super(dev);
        if (s)
                return s;
-       if (!(type = get_fs_type(name))) {
+       type = get_fs_type(name);
+       if (!type) {
                printk("VFS: on device %s: get_fs_type(%s) failed\n",
                       kdevname(dev), name);
-               return NULL;
+               goto out_fail;
        }
        for (s = 0+super_blocks ;; s++) {
                if (s >= NR_SUPER+super_blocks)
-                       return NULL;
-               if (!(s->s_dev))
-                       break;
+                       goto out_fail;
+               if (s->s_dev)
+                       continue;
+               if (s->s_lock) {
+                       printk("VFS: empty superblock %p locked!\n", s);
+                       continue;
+               }
+               break;
        }
        s->s_dev = dev;
        s->s_flags = flags;
-       if (!type->read_super(s,data, silent)) {
-               s->s_dev = 0;
-               return NULL;
-       }
-       s->s_dev = dev;
-       s->s_rd_only = 0;
        s->s_dirt = 0;
+       /* N.B. Should lock superblock now ... */
+       if (!type->read_super(s,data, silent))
+               goto fail;
+       s->s_dev = dev; /* N.B. why do this again?? */
+       s->s_rd_only = 0;
        s->s_type = type;
        return s;
+
+       /* N.B. s_dev should be cleared in type->read_super */
+fail:
+       s->s_dev = 0;
+out_fail:
+       return NULL;
 }
 
 /*
@@ -1040,35 +1060,26 @@ __initfunc(static void do_mount_root(void))
        int retval;
   
 #ifdef CONFIG_ROOT_NFS
-       if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR)
-               if (nfs_root_init(nfs_root_name, nfs_root_addrs) < 0) {
-                       printk(KERN_ERR "Root-NFS: Unable to contact NFS "
-                           "server for root fs, using /dev/fd0 instead\n");
-                       ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
-               }
        if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
                ROOT_DEV = 0;
                if ((fs_type = get_fs_type("nfs"))) {
-                       sb = &super_blocks[0];
-                       while (sb->s_dev) sb++;
-                       sb->s_dev = get_unnamed_dev();
-                       sb->s_flags = root_mountflags & ~MS_RDONLY;
-                       if (nfs_root_mount(sb) >= 0) {
-                               sb->s_rd_only = 0;
-                               sb->s_dirt = 0;
-                               sb->s_type = fs_type;
-                               current->fs->root = dget(sb->s_root);
-                               current->fs->pwd = dget(sb->s_root);
-                               ROOT_DEV = sb->s_dev;
-                               printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
-                               vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
-                               if (!vfsmnt)
-                                       panic("VFS: add_vfsmnt failed for NFS root.\n");
-                               vfsmnt->mnt_sb = sb;
-                               vfsmnt->mnt_flags = sb->s_flags;
-                               return;
+                       if ((vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/"))) {
+                               sb = vfsmnt->mnt_sb;
+                               sb->s_dev = get_unnamed_dev();
+                               sb->s_flags = root_mountflags & ~MS_RDONLY;
+                               if (nfs_root_mount(sb) >= 0) {
+                                       sb->s_rd_only = 0;
+                                       sb->s_dirt = 0;
+                                       sb->s_type = fs_type;
+                                       current->fs->root = dget(sb->s_root);
+                                       current->fs->pwd = dget(sb->s_root);
+                                       ROOT_DEV = sb->s_dev;
+                                       printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
+                                       return;
+                               }
+                               sb->s_dev = 0;
+                               put_unnamed_dev(sb->s_dev);
                        }
-                       sb->s_dev = 0;
                }
                if (!ROOT_DEV) {
                        printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
index ff3d7c7aff2e713c68ad55ee8e6b98d29151e40e..f641d1904968ffa62f1010439c873ea1652081c1 100644 (file)
@@ -420,9 +420,9 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry)
        retval = -EPERM;
        inode = dentry->d_inode;
 
-        if ((dir->i_mode & S_ISVTX) && !fsuser() &&
+        if ((dir->i_mode & S_ISVTX) &&
             current->fsuid != inode->i_uid &&
-            current->fsuid != dir->i_uid)
+            current->fsuid != dir->i_uid && !fsuser())
                goto end_rmdir;
        if (inode->i_dev != dir->i_dev)
                goto end_rmdir;
@@ -485,9 +485,9 @@ repeat:
                schedule();
                goto repeat;
        }
-       if ((dir->i_mode & S_ISVTX) && !fsuser() &&
+       if ((dir->i_mode & S_ISVTX) &&
            current->fsuid != inode->i_uid &&
-           current->fsuid != dir->i_uid)
+           current->fsuid != dir->i_uid && !fsuser())
                goto end_unlink;
        if (de->inode != inode->i_ino) {
                retval = -ENOENT;
index b2a1e2e56ae9d00ab21082e7d18baaf24c535939..ddcc3d1247424d446cc4bfadbf62fd77dde72d0e 100644 (file)
@@ -335,16 +335,18 @@ chkstk();
                PRINTK (("ret %d ",ret));
                if (ret == 0){
                        /* check sticky bit on old_dir */
-                       if ( !(old_dir->i_mode & S_ISVTX) || fsuser() ||
+                       if ( !(old_dir->i_mode & S_ISVTX) ||
                            current->fsuid == old_info.entry.uid ||
-                           current->fsuid == old_dir->i_uid ) {
+                           current->fsuid == old_dir->i_uid ||
+                           fsuser()) {
                                /* Does new_name already exist? */
                                PRINTK(("new findentry "));
                                ret = umsdos_findentry(new_dir,&new_info,0);
                                if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
-                                   !(new_dir->i_mode & S_ISVTX) || fsuser() ||
+                                   !(new_dir->i_mode & S_ISVTX) ||
                                    current->fsuid == new_info.entry.uid ||
-                                   current->fsuid == new_dir->i_uid ) {
+                                   current->fsuid == new_dir->i_uid ||
+                                   fsuser()) {
                                        PRINTK (("new newentry "));
                                        umsdos_ren_init(&new_info,&old_info,flags);
                                        ret = umsdos_newentry (new_dir,&new_info);
@@ -885,9 +887,10 @@ int UMSDOS_rmdir(
                                PRINTK (("isempty %d i_count %d ",empty,
                                         atomic_read(&sdir->i_count)));
                                /* check sticky bit */
-                               if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+                               if ( !(dir->i_mode & S_ISVTX) ||
                                    current->fsuid == sdir->i_uid ||
-                                   current->fsuid == dir->i_uid ) {
+                                   current->fsuid == dir->i_uid ||
+                                   fsuser()) {
                                        if (empty == 1){
                                                /* We have to removed the EMD file */
                                                ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
@@ -948,9 +951,10 @@ int UMSDOS_unlink (
                        if (ret == 0){
                                PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
                                /* check sticky bit */
-                               if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+                               if ( !(dir->i_mode & S_ISVTX) ||
                                    current->fsuid == info.entry.uid ||
-                                   current->fsuid == dir->i_uid ) {
+                                   current->fsuid == dir->i_uid ||
+                                   fsuser()) {
                                        if (info.entry.flags & UMSDOS_HLINK){
                                                /* #Specification: hard link / deleting a link
                                                   When we deletes a file, and this file is a link
index 8aacb6dfd0a4d3f1c7229b8382c666c7a1744958..375ef846b5aacda33481aa1afb0e654912d6186a 100644 (file)
@@ -50,9 +50,29 @@ struct vfat_find_info {
        int long_slots;
        ino_t ino;
        int posix;
+       int anycase;
 };
 
 void vfat_read_inode(struct inode *inode);
+static int vfat_valid_shortname(const char *,int, int, int);
+static int vfat_format_name(const char *, int, char *, int, int);
+static int vfat_valid_longname(const char *, int, int, int);
+
+static int strnicmp(const char *s1, const char *s2, int len)
+{
+       int n = 0;
+       while (*s1 && *s2 && (tolower(*s1) == tolower(*s2))) {
+               s1++; s2++; n++;
+               if (n == len) return 0;
+       }
+       if (*s1 == 0 && *s2 == 0) return 0;
+       if (*s1 && *s2) {
+               if (*s1 > *s2) return 1;
+               return -1;
+       }
+       if (*s1) return 1;
+       return -1;
+}
 
 void vfat_put_super(struct super_block *sb)
 {
@@ -138,6 +158,60 @@ static int parse_options(char *options,    struct fat_mount_options *opts)
        return 1;
 }
 
+/*
+ * Compute the hash for the vfat name corresponding to the dentry.
+ * Note: if the name is invalid, we leave the hash code unchanged so
+ * that the existing dentry can be used. The vfat fs routines will
+ * return ENOENT or EINVAL as appropriate.
+ */
+static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
+{
+       const char *name;
+       int len;
+       char c;
+       unsigned long hash;
+
+       len = qstr->len;
+       name = qstr->name;
+       hash = init_name_hash();
+       while (len--) {
+               c = tolower(*name++);
+               hash = partial_name_hash(tolower(c), hash);
+       }
+       qstr->hash = end_name_hash(hash);
+
+       return 0;
+}
+
+/*
+ * Compare two vfat names.
+ */
+static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+       int alen, blen;
+
+       /* A filename cannot end in '.' or we treat it like it has none */
+       alen = a->len;
+       blen = b->len;
+       if (alen != blen) {
+               if (a->name[alen-1] == '.')
+                       alen--;
+               if (b->name[blen-1] == '.')
+                       blen--;
+               if (alen != blen)
+                       return 1;
+       }
+
+       return strnicmp(a->name, b->name, alen);
+}
+
+static struct dentry_operations vfat_dentry_operations = {
+       NULL,           /* d_revalidate */
+       vfat_hash,
+       vfat_cmp,
+       NULL            /* d_delete */
+};
+
 struct super_block *vfat_read_super(struct super_block *sb,void *data,
                                    int silent)
 {
@@ -159,6 +233,9 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data,
                MOD_DEC_USE_COUNT;
        } else {
                MSDOS_SB(sb)->options.dotsOK = 0;
+               if (MSDOS_SB(sb)->options.name_check != 's') {
+                       sb->s_root->d_op = &vfat_dentry_operations;
+               }
        }
 
        return res;
@@ -245,22 +322,6 @@ static int vfat_find(struct inode *dir,struct qstr* name,
                      int find_long,int new_filename,int is_dir,
                      struct slot_info *sinfo_out);
 
-static int strnicmp(const char *s1, const char *s2, int len)
-{
-       int n = 0;
-       while (*s1 && *s2 && (tolower(*s1) == tolower(*s2))) {
-               s1++; s2++; n++;
-               if (n == len) return 0;
-       }
-       if (*s1 == 0 && *s2 == 0) return 0;
-       if (*s1 && *s2) {
-               if (*s1 > *s2) return 1;
-               return -1;
-       }
-       if (*s1) return 1;
-       return -1;
-}
-
 /* Checks the validity of a long MS-DOS filename */
 /* Returns negative number on error, 0 for a normal
  * return, and 1 for . or .. */
@@ -888,7 +949,7 @@ static int vfat_readdir_cb(
 
        s1 = name; s2 = vf->name;
        for (i = 0; i < name_len; i++) {
-               if (vf->new_filename && !vf->posix) {
+               if (vf->anycase || (vf->new_filename && !vf->posix)) {
                        if (tolower(*s1) != tolower(*s2))
                                return 0;
                } else {
@@ -933,6 +994,7 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
        vf.new_filename = new_filename;
        vf.found = 0;
        vf.posix = MSDOS_SB(sb)->options.posixfs;
+       vf.anycase = (MSDOS_SB(sb)->options.name_check != 's');
        res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0);
        PRINTK(("vfat_find: Debug 1\n"));
        if (res < 0) goto cleanup;
@@ -1039,6 +1101,10 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry)
        PRINTK (("vfat_lookup: name=%s, len=%d\n", 
                 dentry->d_name.name, dentry->d_name.len));
 
+       if (MSDOS_SB(dir->i_sb)->options.name_check != 's') {
+               dentry->d_op = &vfat_dentry_operations;
+       }
+
        result = NULL;
        if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0) {
                d_add(dentry,NULL);
index dbfcb66cdea0a225cbb75132bb050801f4761764..755e8b5b07ed4e990a1b6fe5404f578e76bdb41a 100644 (file)
 #define SO_PEERCRED    18
 #define SO_BINDTODEVICE 25
 
-#define SO_BINDTODEVICE        25
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             19
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       20
 #define SO_SECURITY_ENCRYPTION_NETWORK         21
 
-#define SO_BINDTODEVICE                22
-
 #endif /* _ASM_SOCKET_H */
index b7f2e1507201b8978889113dafa17b0387fc5234..0366bf0d0e76fab10904eff38ce1794cfd05f5d5 100644 (file)
 
 __initfunc(static void no_halt(char *s, int *ints))
 {
-       hlt_works_ok = 0;
+       boot_cpu_data.hlt_works_ok = 0;
 }
 
 __initfunc(static void no_387(char *s, int *ints))
 {
-       hard_math = 0;
+       boot_cpu_data.hard_math = 0;
        __asm__("movl %%cr0,%%eax\n\t"
                "orl $0xE,%%eax\n\t"
                "movl %%eax,%%cr0\n\t" : : : "ax");
@@ -49,7 +49,7 @@ __initfunc(static void check_fpu(void))
 {
        unsigned short control_word;
 
-       if (!hard_math) {
+       if (!boot_cpu_data.hard_math) {
 #ifndef CONFIG_MATH_EMULATION
                printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
                printk(KERN_EMERG "Giving up.\n");
@@ -91,9 +91,9 @@ __initfunc(static void check_fpu(void))
                "fistpl %0\n\t"
                "fwait\n\t"
                "fninit"
-               : "=m" (*&fdiv_bug)
+               : "=m" (*&boot_cpu_data.fdiv_bug)
                : "m" (*&x), "m" (*&y));
-       if (!fdiv_bug)
+       if (!boot_cpu_data.fdiv_bug)
                printk("Ok, fpu using exception 16 error reporting.\n");
        else
                printk("Hmm, fpu using exception 16 error reporting with FDIV bug.\n");
@@ -102,7 +102,7 @@ __initfunc(static void check_fpu(void))
 __initfunc(static void check_hlt(void))
 {
        printk(KERN_INFO "Checking 'hlt' instruction... ");
-       if (!hlt_works_ok) {
+       if (!boot_cpu_data.hlt_works_ok) {
                printk("disabled\n");
                return;
        }
@@ -117,7 +117,7 @@ __initfunc(static void check_tlb(void))
         * The 386 chips don't support TLB finegrained invalidation.
         * They will fault when they hit an invlpg instruction.
         */
-       if (x86 == 3) {
+       if (boot_cpu_data.x86 == 3) {
                printk(KERN_EMERG "CPU is a 386 and this kernel was compiled for 486 or better.\n");
                printk("Giving up.\n");
                for (;;) ;
@@ -152,17 +152,53 @@ __initfunc(static void check_popad(void))
  *     misexecution of code under Linux. Owners of such processors should
  *     contact AMD for precise details and a CPU swap.
  *
- *     See     http://www.creaweb.fr/bpc/k6bug_faq.html
+ *     See     http://www.chorus.com/~poulot/k6bug.html
  *             http://www.amd.com/K6/k6docs/revgd.html
+ *
+ *     The following test is erm.. interesting. AMD neglected to up
+ *     the chip setting when fixing the bug but they also tweaked some
+ *     performance at the same time..
  */
  
+extern void vide(void);
+__asm__(".align 4\nvide: ret");
+
 __initfunc(static void check_amd_k6(void))
 {
-       /* B Step AMD K6 */
-       if(x86_model==6 && x86_mask==1 && memcmp(x86_vendor_id, "AuthenticAMD", 12)==0)
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+           boot_cpu_data.x86_model == 6 &&
+           boot_cpu_data.x86_mask == 1)
        {
-               printk(KERN_INFO "AMD K6 stepping B detected - system stability may be impaired. Please see.\n");
-               printk(KERN_INFO "http://www.creaweb.fr/bpc/k6bug_faq.html");
+               int n;
+               void (*f_vide)(void);
+               unsigned long d, d2;
+
+               printk(KERN_INFO "AMD K6 stepping B detected - ");
+
+#define K6_BUG_LOOP 1000000
+
+               /*
+                * It looks like AMD fixed the 2.6.2 bug and improved indirect 
+                * calls at the same time.
+                */
+
+               n = K6_BUG_LOOP;
+               f_vide = vide;
+               __asm__ ("rdtsc" : "=a" (d));
+               while (n--) 
+                       f_vide();
+               __asm__ ("rdtsc" : "=a" (d2));
+               d = d2-d;
+
+               /* Knock these two lines out if it debugs out ok */
+               printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP);
+               printk(KERN_INFO "AMD K6 stepping B detected - ");
+               /* -- cut here -- */
+               if (d > 20*K6_BUG_LOOP) 
+                       printk(KERN_INFO "system stability may be impaired when more than 32 MB are used.\n");
+               else 
+                       printk(KERN_INFO "probably OK (after B9730xxxx).\n");
+               printk(KERN_INFO "Please see http://www.chorus.com/bpc/k6bug.html\n");
        }
 }
 
@@ -171,30 +207,33 @@ __initfunc(static void check_amd_k6(void))
  * have the F0 0F bug, which lets nonpriviledged users lock up the system:
  */
 
-extern int pentium_f00f_bug;
 extern void trap_init_f00f_bug(void);
 
-
 __initfunc(static void check_pentium_f00f(void))
 {
        /*
         * Pentium and Pentium MMX
         */
-       pentium_f00f_bug = 0;
-       if (x86==5 && !memcmp(x86_vendor_id, "GenuineIntel", 12)) {
+       boot_cpu_data.f00f_bug = 0;
+       if (boot_cpu_data.x86 == 5 && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
                printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
-               pentium_f00f_bug = 1;
+               boot_cpu_data.f00f_bug = 1;
                trap_init_f00f_bug();
        }
 }
 
 __initfunc(static void check_bugs(void))
 {
+#ifndef __SMP__
+       identify_cpu(&boot_cpu_data);
+       printk("CPU: ");
+       print_cpu_info(&boot_cpu_data);
+#endif
        check_tlb();
        check_fpu();
        check_hlt();
        check_popad();
        check_amd_k6();
        check_pentium_f00f();
-       system_utsname.machine[1] = '0' + x86;
+       system_utsname.machine[1] = '0' + boot_cpu_data.x86;
 }
index 3ef940017a7c55c4cade7cfeab7ad7ebb96a1082..c67a92c04f957965754af36378c6e6096d667993 100644 (file)
 #include <asm/segment.h>
 
 /*
- * System setup and hardware bug flags..
- * [Note we don't test the 386 multiply bug or popad bug]
+ *  CPU type and hardware bug flags. Kept separately for each CPU.
+ *  Members of this structure are referenced in head.S, so think twice
+ *  before touching them. [mj]
  */
 
-extern char hard_math;
-extern char x86;               /* lower 4 bits */
-extern char x86_vendor_id[13];
-extern char x86_model;         /* lower 4 bits */
-extern char x86_mask;          /* lower 4 bits */
-extern int  x86_capability;    /* field of flags */
-extern int  fdiv_bug;          
+struct cpuinfo_x86 {
+       u8      x86;            /* CPU family */
+       u8      x86_vendor;     /* CPU vendor */
+       u8      x86_model;
+       u8      x86_mask;
+       char    wp_works_ok;    /* It doesn't on 386's */
+       char    hlt_works_ok;   /* Problems on some 486Dx4's and old 386's */
+       char    hard_math;
+       char    rfu;
+       int     cpuid_level;    /* Maximum supported CPUID level, -1=no CPUID */
+       u32     x86_capability;
+       char    x86_vendor_id[16];
+       char    x86_model_id[64];
+       int     fdiv_bug;
+       int     f00f_bug;
+       unsigned long loops_per_sec;
+};
+
+#define X86_VENDOR_INTEL 0
+#define X86_VENDOR_CYRIX 1
+#define X86_VENDOR_AMD 2
+#define X86_VENDOR_UMC 3
+#define X86_VENDOR_NEXGEN 4
+#define X86_VENDOR_CENTAUR 5
+#define X86_VENDOR_UNKNOWN 0xff
+
+extern struct cpuinfo_x86 boot_cpu_data;
+
+#ifdef __SMP__
+extern struct cpuinfo_x86 cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#else
+#define cpu_data &boot_cpu_data
+#define current_cpu_data boot_cpu_data
+#endif
+
 extern char ignore_irq13;
-extern char wp_works_ok;       /* doesn't work on a 386 */
-extern char hlt_works_ok;      /* problems on some 486Dx4's and old 386's */
-extern int  have_cpuid;                /* We have a CPUID */
+
+extern void identify_cpu(struct cpuinfo_x86 *);
+extern void print_cpu_info(struct cpuinfo_x86 *);
 
 /*
  * Bus types (default is ISA, but people can check others with these..)
index 0f7ae1224745f679a32ae5313f08a6f61af21bd6..8bad18d9047fb1079bcccfe5ae7647ea160f61c3 100644 (file)
@@ -148,28 +148,6 @@ struct mpc_config_intlocal
  *     7       2 CPU MCA+PCI
  */
 
-/*
- *     Per process x86 parameters
- */
-struct cpuinfo_x86
-{
-       char hard_math;
-       char x86;
-       char x86_model;
-       char x86_mask;
-       char x86_vendor_id[16];
-       int  x86_capability;
-       int  fdiv_bug;
-       int  have_cpuid;
-       char wp_works_ok;
-       char hlt_works_ok;
-       unsigned long udelay_val;
-};
-
-
-extern struct cpuinfo_x86 cpu_data[NR_CPUS];
-
 /*
  *     Private routines/data
  */
index d4d13be73703e5217284bb5be3cb11963e77224e..cc27f2e320454a828122389ec53d0e42b7ad8969 100644 (file)
@@ -35,4 +35,8 @@
 
 #define SO_BINDTODEVICE        25
 
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
+
 #endif /* _ASM_SOCKET_H */
index 0ac6380fda14f06262b156b8bbdadb6ff101cfc1..bca5229ee9645697ccfa703d79374ffb7e2a5617 100644 (file)
@@ -55,7 +55,7 @@ extern int __verify_write(const void *, unsigned long);
 #else
 #define __access_ok(type,addr,size) \
        (__kernel_ok || (__user_ok(addr,size) && \
-                        ((type) == VERIFY_READ || wp_works_ok || \
+                        ((type) == VERIFY_READ || boot_cpu_data.wp_works_ok || \
                          __verify_write((void *)(addr),(size)))))
 #endif /* CPU */
 
index 1ec2d6db67f11a2b4e0115bcdd4d7aebfec83086..9aea780b2ed7761f01cd9ae0683732fe0eb98b4f 100644 (file)
@@ -55,6 +55,10 @@ To add: #define SO_REUSEPORT 0x0200  /* Allow local address and port reuse.  */
 
 #define SO_BINDTODEVICE                25
 
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
+
 /* Types of sockets.  */
 #define SOCK_DGRAM 1           /* Connectionless, unreliable datagrams
                                   of fixed maximum length.  */
index 843c0ad8c487ec02ab0053b699d6628af209442a..dc427588b7ecfa5a1b8c4022c39839886fcfff7e 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Definitions for the ARCnet handlers.
  *
- * Version:    $Id: arcdevice.h,v 1.2 1997/09/05 08:57:56 mj Exp $
+ * Version:    $Id: arcdevice.h,v 1.3 1997/11/09 11:05:05 mj Exp $
  *
  * Authors:    Avery Pennarun <apenwarr@bond.net>
  *              David Woodhouse <dwmw2@cam.ac.uk>
@@ -74,7 +74,7 @@
 
 /* Display warnings about the driver being an ALPHA version.
  */
-#define ALPHA_WARNING
+#undef ALPHA_WARNING
 
 
 /* New debugging bitflags: each option can be enabled individually.
index 1e7005e6cc93d9f63cbfbc0bfd32612fa3a9170c..f53c9762d4a201bf9577a9c00d51db3448a96128 100644 (file)
@@ -72,4 +72,15 @@ extern int * max_readahead[MAX_BLKDEV];
 
 extern int * max_sectors[MAX_BLKDEV];
 
+#define MAX_SECTORS 244 /* 254 ? */
+
+#define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK)
+#if 0  /* small readahead */
+#define MAX_READAHEAD PageAlignSize(4096*7)
+#define MIN_READAHEAD PageAlignSize(4096*2)
+#else /* large readahead */
+#define MAX_READAHEAD PageAlignSize(4096*18)
+#define MIN_READAHEAD PageAlignSize(4096*3)
+#endif
+
 #endif
index 08e263925a69adf6c7bc32b7131a5bab834e9fde..f0da942911e003c1850fa88369c1978a27514ad2 100644 (file)
@@ -1,11 +1,3 @@
-/*
- * Venus interface for Coda.
- * Original version: (C) 1996 Peter Braam 
- * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon encourages users of this code to contribute improvements
- * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
- */
 
 /*
  *
 /* Catch new _KERNEL defn for NetBSD */
 #ifdef __NetBSD__
 #include <sys/types.h>
-#ifdef _KERNEL
-#define KERNEL
-#endif 
-#endif 
-
-#if 0
-#ifndef _SCALAR_T_
-#define _SCALAR_T_ 1
-typedef unsigned long  u_int32_t;
-typedef unsigned short u_int16_t;
-typedef unsigned char  u_int8_t;
-#endif 
 #endif 
 
 #ifdef __linux__
-#ifndef _UQUAD_T_
+#if !defined(_UQUAD_T_) && (!defined(__GLIBC__) || __GLIBC__ < 2)
 #define _UQUAD_T_ 1
-typedef unsigned long  u_quad_t;
+typedef unsigned long long u_quad_t;
 #endif 
-
-#ifdef __KERNEL__
-#define KERNEL
-#endif __KERNEL__
 #endif
 
+
 /*
  * Cfs constants
  */
-#define CFS_MAXNAMLEN 256
-#define CFS_MAXPATHLEN 256
-#define CODA_MAXSYMLINK 10
+#define CFS_MAXNAMLEN   255
+#define CFS_MAXPATHLEN  1024
+#define CFS_MAXSYMLINK  10
+
+/* these are Coda's version of O_RDONLY etc combinations
+ * to deal with VFS open modes
+ */
+#define        C_O_READ        0x001
+#define        C_O_WRITE       0x002
+#define C_O_TRUNC       0x010
+#define C_O_EXCL       0x100
+
+/* these are to find mode bits in Venus */ 
+#define C_M_READ  00400
+#define C_M_WRITE 00200
+
+/* for access Venus will use */
+#define C_A_R_OK    4               /* Test for read permission.  */
+#define C_A_W_OK    2               /* Test for write permission.  */
+#define C_A_X_OK    1               /* Test for execute permission.  */
+#define C_A_F_OK    0               /* Test for existence.  */
+
+
 
-/* types used in kernel and user mode */
 #ifndef _VENUS_DIRENT_T_
 #define _VENUS_DIRENT_T_ 1
 struct venus_dirent {
-        unsigned long d_fileno;             /* file number of entry */
-        unsigned short d_reclen;             /* length of this record */
-        char  d_type;               /* file type, see below */
-        char  d_namlen;             /* length of string in d_name */
-        char     d_name[CFS_MAXNAMLEN + 1];/* name must be no longer than this */
+        unsigned long  d_fileno;               /* file number of entry */
+        unsigned short d_reclen;               /* length of this record */
+        char           d_type;                 /* file type, see below */
+        char           d_namlen;               /* length of string in d_name */
+        char           d_name[CFS_MAXNAMLEN + 1];/* name must be no longer than this */
 };
 #undef DIRSIZ
 #define DIRSIZ(dp)      ((sizeof (struct venus_dirent) - (CFS_MAXNAMLEN+1)) + \
@@ -105,6 +101,16 @@ typedef struct ViceFid {
 } ViceFid;
 #endif /* VICEFID */
 
+static inline ino_t coda_f2i(struct ViceFid *fid)
+{
+      if ( fid ) {
+              return (fid->Unique + (fid->Vnode << 10) + (fid->Volume << 20));
+      } else { 
+              return 0;
+      }
+}
+
+
 #ifndef _VUID_T_
 #define _VUID_T_
 typedef u_long vuid_t;
@@ -113,11 +119,9 @@ typedef u_long vgid_t;
 
 #ifndef _CODACRED_T_
 #define _CODACRED_T_
-#define NGROUPS 32
-struct CodaCred {
+struct coda_cred {
     vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid; /* Real, efftve, set, fs uid*/
     vgid_t cr_gid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */
-    vgid_t cr_groups[NGROUPS];       /* Group membership for caller */
 };
 #endif 
 
@@ -126,7 +130,7 @@ struct CodaCred {
 /*
  * Vnode types.  VNON means no type.
  */
-enum coda_vtype        { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD };
+enum coda_vtype        { C_VNON, C_VREG, C_VDIR, C_VBLK, C_VCHR, C_VLNK, C_VSOCK, C_VFIFO, C_VBAD };
 
 struct coda_vattr {
        enum coda_vtype va_type;        /* vnode type (for create) */
@@ -134,7 +138,6 @@ struct coda_vattr {
        short           va_nlink;       /* number of references to file */
        vuid_t          va_uid;         /* owner user id */
        vgid_t          va_gid;         /* owner group id */
-       long            va_fsid;        /* file system id (dev for now) */
        long            va_fileid;      /* file id */
        u_quad_t        va_size;        /* file size in bytes */
        long            va_blocksize;   /* blocksize preferred for i/o */
@@ -146,17 +149,14 @@ struct coda_vattr {
        dev_t           va_rdev;        /* device the special file represents */
        u_quad_t        va_bytes;       /* bytes of disk space held by file */
        u_quad_t        va_filerev;     /* file modification number */
-       u_int           va_vaflags;     /* operations flags, see below */
-       long            va_spare;       /* remain quad aligned */
 };
-#define VREAD 00400
-#define VWRITE 00200
 
 #endif 
 
 /*
- * opcode constants
+ * Kernel <--> Venus communications.
  */
+
 #define CFS_ROOT       ((u_long) 2)
 #define CFS_SYNC       ((u_long) 3)
 #define CFS_OPEN       ((u_long) 4)
@@ -177,8 +177,8 @@ struct coda_vattr {
 #define CFS_READLINK   ((u_long) 19)
 #define CFS_FSYNC      ((u_long) 20)
 #define CFS_INACTIVE   ((u_long) 21)
-#define        CFS_VGET        ((u_long) 22)
-#define        CFS_SIGNAL      ((u_long) 23)
+#define CFS_VGET       ((u_long) 22)
+#define CFS_SIGNAL     ((u_long) 23)
 #define CFS_REPLACE    ((u_long) 24)
 #define CFS_FLUSH       ((u_long) 25)
 #define CFS_PURGEUSER   ((u_long) 26)
@@ -186,273 +186,423 @@ struct coda_vattr {
 #define CFS_ZAPDIR      ((u_long) 28)
 #define CFS_ZAPVNODE    ((u_long) 29)
 #define CFS_PURGEFID    ((u_long) 30)
-#define        CFS_RDWR        ((u_long) 31)
-#define ODY_MOUNT      ((u_long) 32) 
-#define ODY_LOOKUP     ((u_long) 33)
-#define ODY_EXPAND     ((u_long) 34)
+#define CFS_NCALLS 31
 
-#define CFS_NCALLS 35
 #define DOWNCALL(opcode) (opcode >= CFS_REPLACE && opcode <= CFS_PURGEFID)
 
+#define VC_MAXDATASIZE     8192
+#define VC_MAXMSGSIZE      sizeof(union inputArgs)+sizeof(union outputArgs) +\
+                            VC_MAXDATASIZE  
+
+
+
 /*
  *        Venus <-> Coda  RPC arguments
  */
+struct cfs_in_hdr {
+    unsigned long opcode;
+    unsigned long unique;          /* Keep multiple outstanding msgs distinct */
+    u_short pid;                   /* Common to all */
+    u_short pgid;                  /* Common to all */
+    u_short sid;                    /* Common to all */
+    struct coda_cred cred;         /* Common to all */
+};
 
-struct inputArgs {
-    u_long opcode;
-    u_long unique;     /* Keep multiple outstanding msgs distinct */
-    u_short pid;                /* Common to all */
-    u_short pgid;               /* Common to all */
-    struct CodaCred cred;       /* Common to all */
-    
-    union {
-       /* Nothing needed for cfs_root */
-       /* Nothing needed for cfs_sync */
-       struct cfs_open_in {
-           ViceFid     VFid;
-           int flags;
-       } cfs_open;
-       struct cfs_close_in {
-           ViceFid     VFid;
-           int flags;
-       } cfs_close;
-       struct cfs_ioctl_in {
-           ViceFid VFid;
-           int cmd;
-           int len;
-           int rwflag;
-           char *data;                 /* Place holder for data. */
-       } cfs_ioctl;
-       struct cfs_getattr_in {
-           ViceFid VFid;
-            struct coda_vattr attr;
-       } cfs_getattr;
-       struct cfs_setattr_in {
-           ViceFid VFid;
-           struct coda_vattr attr;
-       } cfs_setattr;
-       struct cfs_access_in {
-           ViceFid     VFid;
-           int flags;
-       } cfs_access;
-       struct  cfs_lookup_in {
-           ViceFid     VFid;
-           char        *name;          /* Place holder for data. */
-       } cfs_lookup;
-       struct cfs_create_in {
-           ViceFid VFid;
-           struct coda_vattr attr;
-           int excl;
-           int mode;
-           char        *name;          /* Place holder for data. */
-       } cfs_create;
-       struct cfs_remove_in {
-           ViceFid     VFid;
-           char        *name;          /* Place holder for data. */
-       } cfs_remove;
-       struct cfs_link_in {
-           ViceFid sourceFid;          /* cnode to link *to* */
-           ViceFid destFid;            /* Directory in which to place link */
-           char        *tname;         /* Place holder for data. */
-       } cfs_link;
-       struct cfs_rename_in {
-           ViceFid     sourceFid;
-           char        *srcname;
-           ViceFid destFid;
-           char        *destname;
-       } cfs_rename;
-       struct cfs_mkdir_in {
-           ViceFid     VFid;
-           struct coda_vattr attr;
-           char        *name;          /* Place holder for data. */
-       } cfs_mkdir;
-       struct cfs_rmdir_in {
-           ViceFid     VFid;
-           char        *name;          /* Place holder for data. */
-       } cfs_rmdir;
-       struct cfs_readdir_in {
-           ViceFid     VFid;
-           int count;
-           int offset;
-       } cfs_readdir;
-       struct cfs_symlink_in {
-           ViceFid     VFid;          /* Directory to put symlink in */
-           char        *srcname;
-           struct coda_vattr attr;
-           char        *tname;
-       } cfs_symlink;
-       struct cfs_readlink_in {
-           ViceFid VFid;
-       } cfs_readlink;
-       struct cfs_fsync_in {
-           ViceFid VFid;
-       } cfs_fsync;
-       struct cfs_inactive_in {
-           ViceFid VFid;
-       } cfs_inactive;
-       struct cfs_vget_in {
-           ViceFid VFid;
-       } cfs_vget;
-       /* CFS_SIGNAL is out-of-band, doesn't need data. */
-       /* CFS_INVALIDATE is a venus->kernel call */
-       /* CFS_FLUSH is a venus->kernel call */
-       /* CFS_PURGEUSER is a venus->kernel call */
-       /* CFS_ZAPFILE is a venus->kernel call */
-       /* CFS_ZAPDIR is a venus->kernel call */        
-       /* CFS_ZAPVNODE is a venus->kernel call */      
-       /* CFS_PURGEFID is a venus->kernel call */      
-       struct cfs_rdwr_in {
-           ViceFid     VFid;
-           int rwflag;
-           int count;
-           int offset;
-           int ioflag;
-           caddr_t     data;           /* Place holder for data. */    
-       } cfs_rdwr;
-       struct ody_mount_in {
-           char        *name;          /* Place holder for data. */
-       } ody_mount;
-       struct ody_lookup_in {
-           ViceFid     VFid;
-           char        *name;          /* Place holder for data. */
-       } ody_lookup;
-       struct ody_expand_in {
-           ViceFid VFid;
-           int size;                   /* Size of buffer to return. */
-       } ody_expand;
-       /* CFS_REPLACE is a venus->kernel call */       
-    } d;
-};
-    
-/*  Occasionally, don't cache the fid returned by CFS_LOOKUP. For
- * instance, if the fid is inconsistent. This case is handled by
- * setting the top bit of the return result parameter.  */
-#define CFS_NOCACHE          0x80000000
+/* Really important that opcode and unique are 1st two fields! */
+struct cfs_out_hdr {
+    unsigned long opcode;
+    unsigned long unique;      
+    unsigned long result;
+};
 
-#define INIT_OUT(out, opcode, result) \
-    out->opcode = (opcode); out->result = (result);
-
-/*  IMPORTANT: opcode and unique must be first two fields! */
-struct outputArgs {
-    u_long opcode;
-    u_long unique;      /* Keep multiple outstanding msgs distinct */
-    u_long result;
-    union {
-       struct cfs_root_out {
-           ViceFid VFid;
-       } cfs_root;
-       /* Nothing needed for cfs_sync */
-       struct cfs_open_out {
-           dev_t       dev;
-           ino_t       inode;
-       } cfs_open;
-       /* Nothing needed for cfs_close */
-       struct cfs_ioctl_out {
-           int len;
-           caddr_t     data;           /* Place holder for data. */
-       } cfs_ioctl;
-       struct cfs_getattr_out {
-           struct coda_vattr attr;
-       } cfs_getattr;
-       /* Nothing needed for cfs_setattr */
-       /* Nothing needed for cfs_access */
-       struct cfs_lookup_out {
-           ViceFid VFid;
-           int vtype;
-       } cfs_lookup;
-       struct cfs_create_out {
-           ViceFid VFid;
-           struct coda_vattr attr;
-       } cfs_create;
-       /* Nothing needed for cfs_remove */
-       /* Nothing needed for cfs_link */
-       /* Nothing needed for cfs_rename */
-       struct cfs_mkdir_out {
-           ViceFid VFid;
-           struct coda_vattr attr;
-       } cfs_mkdir;
-       /* Nothing needed for cfs_rmdir */
-       struct cfs_readdir_out {
-           int size;
-           caddr_t     data;           /* Place holder for data. */
-       } cfs_readdir;
-       /* Nothing needed for cfs_symlink */
-       struct cfs_readlink_out {
-           int count;
-           caddr_t     data;           /* Place holder for data. */
-       } cfs_readlink;
-       /* Nothing needed for cfs_fsync */
-       /* Nothing needed for cfs_inactive */
-       struct cfs_vget_out {
-           ViceFid VFid;
-           int vtype;
-       } cfs_vget;
-       /* CFS_SIGNAL is out-of-band, doesn't need data. */
-       /* CFS_INVALIDATE is a venus->kernel call */
-       /* CFS_FLUSH is a venus->kernel call */
-       struct cfs_purgeuser_out {/* CFS_PURGEUSER is a venus->kernel call */
-           struct CodaCred cred;
-       } cfs_purgeuser;
-       struct cfs_zapfile_out {  /* CFS_ZAPFILE is a venus->kernel call */
-           ViceFid CodaFid;
-       } cfs_zapfile;
-       struct cfs_zapdir_out {   /* CFS_ZAPDIR is a venus->kernel call */
-           ViceFid CodaFid;
-       } cfs_zapdir;
-       struct cfs_zapvnode_out { /* CFS_ZAPVNODE is a venus->kernel call */
-           struct CodaCred cred;
-           ViceFid VFid;
-       } cfs_zapvnode;
-       struct cfs_purgefid_out { /* CFS_PURGEFID is a venus->kernel call */
-           ViceFid CodaFid;
-       } cfs_purgefid;
-       struct cfs_rdwr_out {
-           int rwflag;
-           int count;
-           caddr_t     data;   /* Place holder for data. */
-       } cfs_rdwr;
-       struct ody_mount_out {
-           ViceFid VFid;
-       } ody_mount;
-       struct ody_lookup_out {
-           ViceFid VFid;
-       } ody_lookup;
-       struct ody_expand_out { /* Eventually it would be nice to get some */
-           char links[sizeof(int)];    /* Place holder for data. */
-       } ody_expand;
-       struct cfs_replace_out { /* cfs_replace is a venus->kernel call */
-           ViceFid NewFid;
-           ViceFid OldFid;
-       } cfs_replace;
-    } d;
-};    
-    
+/* cfs_root: NO_IN */
+struct cfs_root_out {
+    struct cfs_out_hdr oh;
+    ViceFid VFid;
+};
+
+struct cfs_root_in {
+    struct cfs_in_hdr in;
+};
+
+/* cfs_sync: */
+/* Nothing needed for cfs_sync */
+
+/* cfs_open: */
+struct cfs_open_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    int        flags;
+};
+
+struct cfs_open_out {
+    struct cfs_out_hdr oh;
+    dev_t      dev;
+    ino_t      inode;
+};
+
+
+/* cfs_close: */
+struct cfs_close_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    int        flags;
+};
+
+struct cfs_close_out {
+    struct cfs_out_hdr out;
+};
+
+/* cfs_ioctl: */
+struct cfs_ioctl_in {
+    struct cfs_in_hdr ih;
+    ViceFid VFid;
+    int        cmd;
+    int        len;
+    int        rwflag;
+    char *data;                        /* Place holder for data. */
+};
+
+struct cfs_ioctl_out {
+    struct cfs_out_hdr oh;
+    int        len;
+    caddr_t    data;           /* Place holder for data. */
+};
+
+
+/* cfs_getattr: */
+struct cfs_getattr_in {
+    struct cfs_in_hdr ih;
+    ViceFid VFid;
+};
+
+struct cfs_getattr_out {
+    struct cfs_out_hdr oh;
+    struct coda_vattr attr;
+};
+
+
+/* cfs_setattr: NO_OUT */
+struct cfs_setattr_in {
+    struct cfs_in_hdr ih;
+    ViceFid VFid;
+    struct coda_vattr attr;
+};
+
+struct cfs_setattr_out {
+    struct cfs_out_hdr out;
+};
+
+/* cfs_access: NO_OUT */
+struct cfs_access_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    int        flags;
+};
+
+struct cfs_access_out {
+    struct cfs_out_hdr out;
+};
+
+/* cfs_lookup: */
+struct  cfs_lookup_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    int         name;          /* Place holder for data. */
+};
+
+struct cfs_lookup_out {
+    struct cfs_out_hdr oh;
+    ViceFid VFid;
+    int        vtype;
+};
+
+
+/* cfs_create: */
+struct cfs_create_in {
+    struct cfs_in_hdr ih;
+    ViceFid VFid;
+    struct coda_vattr attr;
+    int excl;
+    int mode;
+    int        name;           /* Place holder for data. */
+};
+
+struct cfs_create_out {
+    struct cfs_out_hdr oh;
+    ViceFid VFid;
+    struct coda_vattr attr;
+};
+
+
+/* cfs_remove: NO_OUT */
+struct cfs_remove_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    int name;          /* Place holder for data. */
+};
+
+struct cfs_remove_out {
+    struct cfs_out_hdr out;
+};
+
+/* cfs_link: NO_OUT */
+struct cfs_link_in {
+    struct cfs_in_hdr ih;
+    ViceFid sourceFid;          /* cnode to link *to* */
+    ViceFid destFid;            /* Directory in which to place link */
+    int tname;         /* Place holder for data. */
+};
+
+struct cfs_link_out {
+    struct cfs_out_hdr out;
+};
+
+
+/* cfs_rename: NO_OUT */
+struct cfs_rename_in {
+    struct cfs_in_hdr ih;
+    ViceFid    sourceFid;
+    int        srcname;
+    ViceFid destFid;
+    int        destname;
+};
+
+struct cfs_rename_out {
+    struct cfs_out_hdr out;
+};
+
+/* cfs_mkdir: */
+struct cfs_mkdir_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    struct coda_vattr attr;
+    int           name;                /* Place holder for data. */
+};
+
+struct cfs_mkdir_out {
+    struct cfs_out_hdr oh;
+    ViceFid VFid;
+    struct coda_vattr attr;
+};
+
+
+/* cfs_rmdir: NO_OUT */
+struct cfs_rmdir_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    int name;          /* Place holder for data. */
+};
+
+struct cfs_rmdir_out {
+    struct cfs_out_hdr out;
+};
+
+/* cfs_readdir: */
+struct cfs_readdir_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    int        count;
+    int        offset;
+};
+
+struct cfs_readdir_out {
+    struct cfs_out_hdr oh;
+    int        size;
+    caddr_t    data;           /* Place holder for data. */
+};
+
+/* cfs_symlink: NO_OUT */
+struct cfs_symlink_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;          /* Directory to put symlink in */
+    int srcname;
+    struct coda_vattr attr;
+    int tname;
+};
+
+struct cfs_symlink_out {
+    struct cfs_out_hdr out;
+};
+
+/* cfs_readlink: */
+struct cfs_readlink_in {
+    struct cfs_in_hdr ih;
+    ViceFid VFid;
+};
+
+struct cfs_readlink_out {
+    struct cfs_out_hdr oh;
+    int        count;
+    caddr_t    data;           /* Place holder for data. */
+};
+
+
+/* cfs_fsync: NO_OUT */
+struct cfs_fsync_in {
+    struct cfs_in_hdr ih;
+    ViceFid VFid;
+};
+
+struct cfs_fsync_out {
+    struct cfs_out_hdr out;
+};
+
+/* cfs_inactive: NO_OUT */
+struct cfs_inactive_in {
+    struct cfs_in_hdr ih;
+    ViceFid VFid;
+};
+
+/* cfs_vget: */
+struct cfs_vget_in {
+    struct cfs_in_hdr ih;
+    ViceFid VFid;
+};
+
+struct cfs_vget_out {
+    struct cfs_out_hdr oh;
+    ViceFid VFid;
+    int        vtype;
+};
+
+
+/* CFS_SIGNAL is out-of-band, doesn't need data. */
+/* CFS_INVALIDATE is a venus->kernel call */
+/* CFS_FLUSH is a venus->kernel call */
+
+/* cfs_purgeuser: */
+/* CFS_PURGEUSER is a venus->kernel call */
+struct cfs_purgeuser_out {
+    struct cfs_out_hdr oh;
+    struct coda_cred cred;
+};
+
+/* cfs_zapfile: */
+/* CFS_ZAPFILE is a venus->kernel call */
+struct cfs_zapfile_out {  
+    struct cfs_out_hdr oh;
+    ViceFid CodaFid;
+};
+
+/* cfs_zapdir: */
+/* CFS_ZAPDIR is a venus->kernel call */       
+struct cfs_zapdir_out {          
+    struct cfs_out_hdr oh;
+    ViceFid CodaFid;
+};
+
+/* cfs_zapnode: */
+/* CFS_ZAPVNODE is a venus->kernel call */     
+struct cfs_zapvnode_out { 
+    struct cfs_out_hdr oh;
+    struct coda_cred cred;
+    ViceFid VFid;
+};
+
+/* cfs_purgefid: */
+/* CFS_PURGEFID is a venus->kernel call */     
+struct cfs_purgefid_out { 
+    struct cfs_out_hdr oh;
+    ViceFid CodaFid;
+};
+
+/* cfs_rdwr: */
+struct cfs_rdwr_in {
+    struct cfs_in_hdr ih;
+    ViceFid    VFid;
+    int        rwflag;
+    int        count;
+    int        offset;
+    int        ioflag;
+    caddr_t    data;           /* Place holder for data. */    
+};
+
+struct cfs_rdwr_out {
+    struct cfs_out_hdr oh;
+    int        rwflag;
+    int        count;
+    caddr_t    data;   /* Place holder for data. */
+};
+
+
+/* cfs_replace: */
+/* CFS_REPLACE is a venus->kernel call */      
+struct cfs_replace_out { /* cfs_replace is a venus->kernel call */
+    struct cfs_out_hdr oh;
+    ViceFid NewFid;
+    ViceFid OldFid;
+};
 
 /* 
- * how big are the inputArgs and outputArgs structures
- * for the varying types of calls?
+ * Occasionally, don't cache the fid returned by CFS_LOOKUP. For instance, if
+ * the fid is inconsistent. This case is handled by setting the top bit of the
+ * return result parameter.
  */
-#define        VC_IN_NO_DATA       (2 * (int)sizeof(u_long)    \
-                             + 2 * (int)sizeof(u_short) \
-                            + (int)sizeof(struct CodaCred))
-#define        VC_OUT_NO_DATA      (3 * (int)sizeof(u_long))
-#define VC_INSIZE(member)   (VC_IN_NO_DATA + (int)sizeof(struct member))
-#define VC_OUTSIZE(member)  (VC_OUT_NO_DATA + (int)sizeof(struct member))
-
-/* Now for venus. C++ doesn't know what struct foo means. */
-#define VC_SIZE(Thing, Member)   (VC_OUT_NO_DATA                    \
-                                  + (int)sizeof((Thing)->d.Member))
-
-#define VC_BIGGER_OF_IN_OR_OUT  (sizeof(struct outputArgs)   \
-                                  > sizeof(struct inputArgs) \
-                                ? sizeof(struct outputArgs)  \
-                                : sizeof(struct inputArgs))
-#define VC_DATASIZE        8192
-#define        VC_MAXMSGSIZE       (VC_DATASIZE + VC_BIGGER_OF_IN_OR_OUT)
+#define CFS_NOCACHE          0x80000000
+
+union inputArgs {
+    struct cfs_in_hdr ih;              /* NB: every struct below begins with an ih */
+    struct cfs_open_in cfs_open;
+    struct cfs_close_in cfs_close;
+    struct cfs_ioctl_in cfs_ioctl;
+    struct cfs_getattr_in cfs_getattr;
+    struct cfs_setattr_in cfs_setattr;
+    struct cfs_access_in cfs_access;
+    struct cfs_lookup_in cfs_lookup;
+    struct cfs_create_in cfs_create;
+    struct cfs_remove_in cfs_remove;
+    struct cfs_link_in cfs_link;
+    struct cfs_rename_in cfs_rename;
+    struct cfs_mkdir_in cfs_mkdir;
+    struct cfs_rmdir_in cfs_rmdir;
+    struct cfs_readdir_in cfs_readdir;
+    struct cfs_symlink_in cfs_symlink;
+    struct cfs_readlink_in cfs_readlink;
+    struct cfs_fsync_in cfs_fsync;
+    struct cfs_inactive_in cfs_inactive;
+    struct cfs_vget_in cfs_vget;
+    struct cfs_rdwr_in cfs_rdwr;
+};
+
+union outputArgs {
+    struct cfs_out_hdr oh;             /* NB: every struct below begins with an oh */
+    struct cfs_root_out cfs_root;
+    struct cfs_open_out cfs_open;
+    struct cfs_ioctl_out cfs_ioctl;
+    struct cfs_getattr_out cfs_getattr;
+    struct cfs_lookup_out cfs_lookup;
+    struct cfs_create_out cfs_create;
+    struct cfs_mkdir_out cfs_mkdir;
+    struct cfs_readdir_out cfs_readdir;
+    struct cfs_readlink_out cfs_readlink;
+    struct cfs_vget_out cfs_vget;
+    struct cfs_purgeuser_out cfs_purgeuser;
+    struct cfs_zapfile_out cfs_zapfile;
+    struct cfs_zapdir_out cfs_zapdir;
+    struct cfs_zapvnode_out cfs_zapvnode;
+    struct cfs_purgefid_out cfs_purgefid;
+    struct cfs_rdwr_out cfs_rdwr;
+    struct cfs_replace_out cfs_replace;
+};    
+
+union cfs_downcalls {
+    /* CFS_INVALIDATE is a venus->kernel call */
+    /* CFS_FLUSH is a venus->kernel call */
+    struct cfs_purgeuser_out purgeuser;
+    struct cfs_zapfile_out zapfile;
+    struct cfs_zapdir_out zapdir;
+    struct cfs_zapvnode_out zapvnode;
+    struct cfs_purgefid_out purgefid;
+    struct cfs_replace_out replace;
+};
+
 
 /*
  * Used for identifying usage of "Control" and pioctls
  */
+
+#define PIOCPARM_MASK 0x0000ffff
 struct ViceIoctl {
         caddr_t in, out;        /* Data to be transferred in, or out */
         short in_size;          /* Size of input buffer <= 2K */
@@ -465,25 +615,17 @@ struct PioctlData {
         struct ViceIoctl vi;
 };
 
-
-
-
-
-
 #define        CFS_CONTROL             ".CONTROL"
 #define CFS_CONTROLLEN           8
 #define        CTL_VOL                 -1
 #define        CTL_VNO                 -1
 #define        CTL_UNI                 -1
 #define CTL_INO                 -1
-#define        CTL_FILE    "/coda/.CONTROL"
-#define IOCPARM_MASK 0x0000ffff
+#define        CTL_FILE                "/coda/.CONTROL"
 
 
 #define        IS_CTL_FID(fidp)        ((fidp)->Volume == CTL_VOL &&\
                                 (fidp)->Vnode == CTL_VNO &&\
                                 (fidp)->Unique == CTL_UNI)
-     /*#define ISDIR(fid)              ((fid).Vnode & 0x1) */
-
 #endif 
 
index 43bf1b2cc960d8cb2fef90f9ad873c936ee6c009..2973be72399905be6a726945512f35d7dbef35b8 100644 (file)
@@ -7,8 +7,6 @@
  * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
  */
 
-/* revamped cnode.h file: platform dependent, kernel only! */
-
 
 #ifndef        _CNODE_H_
 #define        _CNODE_H_
 
 /* defintion of cnode, which combines ViceFid with inode information */
 struct cnode {
-        struct inode    *c_vnode;    /* linux inode associated with cnode */
-        ViceFid                 c_fid;      /* Coda identifier */
-        u_short                 c_flags;     /* flags (see below) */
-        int             c_magic;     /* to verify the data structure */
-        u_short                c_ocount;    /* count of openers */
-        u_short         c_owrite;    /* count of open for write */
-        u_short         c_mmcount;   /* count of mmappers */
-        struct inode    *c_ovp;             /* open vnode pointer */
-        struct dentry   c_odentry;
+        struct inode      *c_vnode;     /*  inode associated with cnode */
+        ViceFid                   c_fid;       /* Coda identifier */
+        u_short                   c_flags;     /* flags (see below) */
+        int                c_magic;     /* to verify the data structure */
+        u_short                   c_ocount;    /* count of openers */
+        u_short            c_owrite;    /* count of open for write */
+        u_short            c_mmcount;   /* count of mmappers */
+        struct inode      *c_ovp;       /* open vnode pointer */
+        struct list_head   c_cnhead;    /* head of cache entries */
 };
 
 /* flags */
 #define C_VATTR       0x1         /* Validity of vattr in the cnode */
 #define C_SYMLINK     0x2         /* Validity of symlink pointer in the cnode */
-#define C_DYING              0x4         /* Set for outstanding cnodes from venus (which died) */
+#define C_DYING       0x4        /* Set for outstanding cnodes from venus (which died) */
+#define C_ZAPFID      0x8
+#define C_ZAPDIR      0x10
 
+void coda_cnode_free(struct cnode *);
 struct cnode *coda_cnode_alloc(void);
-void coda_cnode_free(struct cnode *cinode);
-int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb);
-struct inode *coda_fid2inode(ViceFid *fid, struct super_block *sb);
+int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *);
 int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
-
-
+struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb);
+
+/* inode to cnode */
+static inline struct cnode *ITOC(struct inode *inode)
+{
+       return ((struct cnode *)inode->u.generic_ip);
+}
+
+/* cnode to inode */
+static inline struct inode *CTOI(struct cnode *cnode)
+{
+       return (cnode->c_vnode);
+}
 
 #endif 
 
index 35901883b92c5a4d43129edfb4f7c2042eb54356..63ba829de42e524ea8c27b9abe7509ee1beb3b52 100644 (file)
@@ -41,15 +41,19 @@ int coda_permission(struct inode *inode, int mask);
 extern int coda_debug;
 extern int coda_print_entry;
 extern int coda_access_cache;
-extern int cfsnc_use;
 
-
-/*   */
+/* this file:  heloers */
 char *coda_f2s(ViceFid *f, char *s);
 int coda_isroot(struct inode *i);
-void coda_load_creds(struct CodaCred *cred);
-
-
+int coda_iscontrol(const char *name, size_t length);
+void coda_load_creds(struct coda_cred *cred);
+int coda_mycred(struct coda_cred *);
+void coda_vattr_to_iattr(struct inode *, struct coda_vattr *);
+void coda_iattr_to_vattr(struct iattr *, struct coda_vattr *);
+unsigned short coda_flags_to_cflags(unsigned short);
+void print_vattr( struct coda_vattr *attr );
+int coda_cred_ok(struct coda_cred *cred);
+int coda_cred_eq(struct coda_cred *cred1, struct coda_cred *cred2);
 
 /* defined in  file.c */
 void coda_prepare_openfile(struct inode *coda_inode, struct file *coda_file, 
@@ -58,17 +62,8 @@ void coda_prepare_openfile(struct inode *coda_inode, struct file *coda_file,
 void coda_restore_codafile(struct inode *coda_inode, struct file *coda_file, 
                           struct inode *open_inode, struct file *open_file);
 int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind);
-struct super_block *coda_find_super(kdev_t device);
-
 
-#define INIT_IN(in, op) \
-         (in)->opcode = (op); \
-         (in)->pid = current->pid; \
-          (in)->pgid = current->gid; 
-
-/* debugging aids */
-
-#define coda_panic printk
+#define NB_SFS_SIZ 0x895440
 
 /* debugging masks */
 #define D_SUPER     1   /* print results returned by Venus */ 
@@ -81,8 +76,8 @@ struct super_block *coda_find_super(kdev_t device);
 #define D_PSDEV    128  
 #define D_PIOCTL   256
 #define D_SPECIAL  512
-/* until we are really good, ... */
-#define coda_panic printk
+#define D_TIMING  1024
+#define D_DOWNCALL 2048
  
 #define CDEBUG(mask, format, a...)                                \
   do {                                                            \
@@ -98,30 +93,21 @@ struct super_block *coda_find_super(kdev_t device);
     if(coda_print_entry) printk("Process %d leaving %s\n",current->pid,__FUNCTION__)
 
 
-/* inode to cnode */
-#define ITOC(the_inode)  ((struct cnode *)(the_inode)->u.generic_ip)
-/* cnode to inode */
-#define CTOI(the_cnode)  ((the_cnode)->c_vnode)
 
 #define CHECK_CNODE(c)                                                \
 do {                                                                  \
-  struct cnode *cnode = (c);                                          \
+  if ( coda_debug ) {\
+    struct cnode *cnode = (c);                                          \
   if (!cnode)                                                         \
-    coda_panic ("%s(%d): cnode is null\n", __FUNCTION__, __LINE__);        \
+    printk ("%s(%d): cnode is null\n", __FUNCTION__, __LINE__);        \
   if (cnode->c_magic != CODA_CNODE_MAGIC)                             \
-    coda_panic ("%s(%d): cnode magic wrong\n", __FUNCTION__, __LINE__);    \
+    printk ("%s(%d): cnode magic wrong\n", __FUNCTION__, __LINE__);    \
   if (!cnode->c_vnode)                                                \
-    coda_panic ("%s(%d): cnode has null inode\n", __FUNCTION__, __LINE__); \
+    printk ("%s(%d): cnode has null inode\n", __FUNCTION__, __LINE__); \
   if ( (struct cnode *)cnode->c_vnode->u.generic_ip != cnode )           \
-    coda_panic("AAooh, %s(%d) cnode doesn't link right!\n", __FUNCTION__,__LINE__);\
-} while (0);
-
+    printk("AAooh, %s(%d) cnode doesn't link right!\n", __FUNCTION__,__LINE__);\
+}} while (0);
 
-/* ioctl stuff */
-/* this needs to be sorted out XXXX */ 
-#ifdef __linux__
-#define IOCPARM_MASK 0x0000ffff
-#endif 
 
 #define CODA_ALLOC(ptr, cast, size)                                       \
 do {                                                                      \
@@ -132,7 +118,7 @@ do {                                                                      \
         ptr = (cast)vmalloc((unsigned long) size);                        \
        CDEBUG(D_MALLOC, "vmalloced: %x at %x.\n", (int) size, (int) ptr);}\
     if (ptr == 0) {                                                       \
-        coda_panic("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__);  \
+        printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__);  \
     }                                                                     \
     memset( ptr, 0, size );                                                   \
 } while (0)
@@ -140,48 +126,4 @@ do {                                                                      \
 
 #define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %x at %x.\n", (int) size, (int) ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %x at %x.\n", (int) size, (int) ptr);} } while (0)
 
-
-
-
-/*
- * Macros to manipulate the queue 
- */
-#define crfree(cred) CODA_FREE( (cred), sizeof(struct ucred))
-
-#ifndef INIT_QUEUE
-
-struct queue {
-    struct queue *forw, *back;
-};
-
-#define INIT_QUEUE(head)                     \
-do {                                         \
-    (head).forw = (struct queue *)&(head);   \
-    (head).back = (struct queue *)&(head);   \
-} while (0)
-
-#define GETNEXT(head) (head).forw
-
-#define EMPTY(head) ((head).forw == &(head))
-
-#define EOQ(el, head) ((struct queue *)(el) == (struct queue *)&(head))
-
-#define INSQUE(el, head)                             \
-do {                                                 \
-       (el).forw = ((head).back)->forw;             \
-       (el).back = (head).back;                     \
-       ((head).back)->forw = (struct queue *)&(el); \
-       (head).back = (struct queue *)&(el);         \
-} while (0)
-
-#define REMQUE(el)                         \
-do {                                       \
-       ((el).forw)->back = (el).back;     \
-       (el).back->forw = (el).forw;       \
-}  while (0)
-
-#endif INIT_QUEUE
-
-
-#endif _LINUX_CODA_FS
-
+#endif
diff --git a/include/linux/coda_namecache.h b/include/linux/coda_namecache.h
deleted file mode 100644 (file)
index 261adff..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/* 
- * Mach Operating System
- * Copyright (c) 1990 Carnegie-Mellon University
- * Copyright (c) 1989 Carnegie-Mellon University
- * All rights reserved.  The CMU software License Agreement specifies
- * the terms and conditions for use and redistribution.
- */
-
-/*
- * This code was written for the Coda file system at Carnegie Mellon University.
- * Contributers include David Steere, James Kistler, and M. Satyanarayanan.
- */
-
-/* 
- * HISTORY
- * cfsnc.h,v
- * Revision 1.2  1996/01/02 16:57:19  bnoble
- * Added support for Coda MiniCache and raw inode calls (final commit)
- *
- * Revision 1.1.2.1  1995/12/20 01:57:45  bnoble
- * Added CFS-specific files
- *
- * Revision 3.1.1.1  1995/03/04  19:08:22  bnoble
- * Branch for NetBSD port revisions
- *
- * Revision 3.1  1995/03/04  19:08:21  bnoble
- * Bump to major revision 3 to prepare for NetBSD port
- *
- * Revision 2.2  1994/08/28  19:37:39  luqi
- * Add a new CFS_REPLACE call to allow venus to replace a ViceFid in the
- * mini-cache.
- *
- * In "cfs.h":
- * Add CFS_REPLACE decl.
- *
- * In "cfs_namecache.c":
- * Add routine cfsnc_replace.
- *
- * In "cfs_subr.c":
- * Add case-statement to process CFS_REPLACE.
- *
- * In "cfsnc.h":
- * Add decl for CFSNC_REPLACE.
- *
- * Revision 2.1  94/07/21  16:25:27  satya
- * Conversion to C++ 3.0; start of Coda Release 2.0
- *
- * Revision 1.2  92/10/27  17:58:34  lily
- * merge kernel/latest and alpha/src/cfs
- * 
- * Revision 2.2  90/07/05  11:27:04  mrt
- *     Created for the Coda File System.
- *     [90/05/23            dcs]
- * 
- * Revision 1.4  90/05/31  17:02:12  dcs
- * Prepare for merge with facilities kernel.
- * 
- * 
- */
-#ifndef _CFSNC_HEADER_
-#define _CFSNC_HEADER_
-
-#include "coda.h"
-#include "coda_cnode.h"
-
-
-/*
- * Cfs constants
- */
-#define CFSNC_NAMELEN  15              /* longest name stored in cache */
-#define CFSNC_CACHESIZE 256            /* Default cache size */
-#define CFSNC_HASHSIZE 64              /* Must be multiple of 2 */
-/*
- * Structure for an element in the CFS Name Cache.
- */
-
-/* roughly 50 bytes per entry */
-struct cfscache {      
-       struct cfscache *hash_next,*hash_prev;  /* Hash list */
-       struct cfscache *lru_next, *lru_prev;   /* LRU list */
-       struct cnode    *cp;                    /* vnode of the file */
-       struct cnode    *dcp;                   /* parent's cnode */
-       struct CodaCred *cred;                  /* user credentials */
-       char            name[CFSNC_NAMELEN];    /* segment name */
-       int             namelen;                /* length of name */
-};
-
-
-
-/* exported */
-void cfsnc_init(void);
-void cfsnc_enter(struct cnode *dcp, register const char *name, int namelen, struct cnode *cp);
-struct cnode *cfsnc_lookup(struct cnode *dcp, register const char *name, int namelen);
-void cfsnc_zapParentfid(ViceFid *fid);
-void cfsnc_zapfid(ViceFid *fid);
-void cfsnc_zapfile(struct cnode *dcp, register const char *name, int length);
-void cfsnc_purge_user(struct CodaCred *cred);
-void cfsnc_flush(void);
-void cfsnc_replace(ViceFid *f1, ViceFid *f2);
-void print_cfsnc(void);
-void coda_print_ce(struct cfscache *);
-int cfsnc_resize(int hashsize, int heapsize);
-  
-
-/* #define CFSNC_VALID(cncp)   ( (cncp->dcp != (struct cnode *)0) && (cncp->cp->c_flags & C_VATTR) ) */
-#define CFSNC_VALID(cncp)          (cncp->dcp != (struct cnode *)0) 
-#define DATA_PART(cncp)                                (struct cfscache *) \
-                       ((char *)cncp + (4*sizeof(struct cfscache *)))
-#define DATA_SIZE      (sizeof(struct cfscache)-(4*sizeof(struct cfscache *)))
-
-/*
- * Structure to contain statistics on the cache usage
- */
-
-struct cfsnc_statistics {
-       unsigned        hits;
-       unsigned        misses;
-       unsigned        enters;
-       unsigned        dbl_enters;
-       unsigned        long_name_enters;
-       unsigned        long_name_lookups;
-       unsigned        long_remove;
-       unsigned        lru_rm;
-       unsigned        zapPfids;
-       unsigned        zapFids;
-       unsigned        zapFile;
-       unsigned        zapUsers;
-       unsigned        Flushes;
-       unsigned        Sum_bucket_len;
-       unsigned        Sum2_bucket_len;
-       unsigned        Max_bucket_len;
-       unsigned        Num_zero_len;
-       unsigned        Search_len;
-};
-
-/* 
- * Symbols to aid in debugging the namecache code. Assumes the existence
- * of the variable cfsnc_debug, which is defined in cfs_namecache.c
- */
-extern int cfsnc_debug;
-#define CFSNC_DEBUG(N, STMT)     { if (cfsnc_debug & (1 <<N)) { STMT } }
-
-#define CFSNC_FIND             ((u_long) 1)
-#define CFSNC_REMOVE           ((u_long) 2)
-#define CFSNC_INIT             ((u_long) 3)
-#define CFSNC_ENTER            ((u_long) 4)
-#define CFSNC_LOOKUP           ((u_long) 5)
-#define CFSNC_ZAPPFID          ((u_long) 6)
-#define CFSNC_ZAPFID           ((u_long) 7)
-#define CFSNC_ZAPVNODE         ((u_long) 8)
-#define CFSNC_ZAPFILE          ((u_long) 9)
-#define CFSNC_PURGEUSER                ((u_long) 10)
-#define CFSNC_FLUSH            ((u_long) 11)
-#define CFSNC_PRINTCFSNC       ((u_long) 12)
-#define CFSNC_PRINTSTATS       ((u_long) 13)
-#define CFSNC_REPLACE          ((u_long) 14)
-
-#endif _CFSNC_HEADER_
index 2c127e6e59270db55dee6fdf67363c9bf4004e43..f4087460e7bbc4c9527900c8195c16749e565906 100644 (file)
@@ -1,11 +1,36 @@
+#ifndef _BLURB_
+#define _BLURB_
 /*
- * Operations statistics for Coda.
- * Original version: (C) 1996 Peter Braam 
- * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon encourages users of this code to contribute improvements
- * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
- */
+
+            Coda: an Experimental Distributed File System
+                             Release 3.1
+
+          Copyright (c) 1987-1996 Carnegie Mellon University
+                         All Rights Reserved
+
+Permission  to  use, copy, modify and distribute this software and its
+documentation is hereby granted,  provided  that  both  the  copyright
+notice  and  this  permission  notice  appear  in  all  copies  of the
+software, derivative works or  modified  versions,  and  any  portions
+thereof, and that both notices appear in supporting documentation, and
+that credit is given to Carnegie Mellon University  in  all  documents
+and publicity pertaining to direct or indirect use of this code or its
+derivatives.
+
+CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
+SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
+FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
+DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
+RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
+ANY DERIVATIVE WORK.
+
+Carnegie  Mellon  encourages  users  of  this  software  to return any
+improvements or extensions that  they  make,  and  to  grant  Carnegie
+Mellon the rights to redistribute these changes without encumbrance.
+*/
+
+static char *rcsid = "$Header: /afs/cs/project/coda-src/cvs/coda/kernel-src/vfs/linux21/linux/coda_opstats.h,v 1.1 1997/12/02 05:35:02 braam Exp $";
+#endif /*_BLURB_*/
 
 
 /*
index ecd213f8b619c7bc9c2c37bdfd338451e2cc84b3..649234b3be0ad612a870c28a2869e911756d2fe9 100644 (file)
@@ -4,19 +4,49 @@
 #define CODA_PSDEV_MAJOR 67
 #define MAX_CODADEVS  5           /* how many do we allow */
 
+#include <linux/config.h>
+
 extern struct vcomm psdev_vcomm[];
 
+/* queue stuff; the rest is static to psdev.c */
+struct queue {
+    struct queue *forw, *back;
+};
+void coda_q_insert(struct queue *el, struct queue *q);
+void coda_q_remove(struct queue *q);
+
+
 #define CODA_SUPER_MAGIC       0x73757245
 
 struct coda_sb_info
 {
-  struct inode *      sbi_psdev;     /* /dev/cfs? Venus/kernel device */
-  struct inode *      sbi_ctlcp;     /* control magic file */
-  int                 sbi_refct;
-  struct vcomm *      sbi_vcomm;
-  struct inode *      sbi_root;
+       struct inode *      sbi_psdev;     /* /dev/cfs? Venus/kernel device */
+       struct inode *      sbi_ctlcp;     /* control magic file */
+       int                 sbi_refct;
+       struct vcomm *      sbi_vcomm;
+       struct inode *      sbi_root;
+       struct list_head    sbi_cchead;
 };
 
+/* communication pending/processing queues queues */
+struct vcomm {
+       u_long              vc_seq;
+       struct wait_queue  *vc_waitq; /* Venus wait queue */
+       struct queue        vc_pending;
+       struct queue        vc_processing;
+       struct super_block *vc_sb;
+       int                 vc_inuse;
+};
+
+static inline int vcomm_open(struct vcomm *vcp)
+{
+        return ((vcp)->vc_pending.forw != NULL);
+}
+
+static inline void mark_vcomm_closed(struct vcomm *vcp)
+{
+        (vcp)->vc_pending.forw = NULL;
+}
 
 static inline struct coda_sb_info *coda_sbp(struct super_block *sb)
 {
@@ -28,22 +58,6 @@ static inline struct coda_sb_info *coda_sbp(struct super_block *sb)
 extern void coda_psdev_detach(int unit);
 extern int  init_coda_psdev(void);
 
-/* to aid procedures make upcalls. They must have a 
-   declaration at the top containing:
-       struct inputArgs *inp;
-       struct outputArgs *outp;
-       int error=0;
-       int size;
-*/
-
-#define UPARG(bsize, op)\
-do {\
-       CODA_ALLOC(inp, struct inputArgs *, (bsize));\
-       outp = (struct outputArgs *) (inp);\
-       INIT_IN(inp, (op))\
-       coda_load_creds(&(inp->cred));\
-        size = (bsize);\
-} while (0)
 
 /* upcalls */
 int venus_rootfid(struct super_block *sb, ViceFid *fidp);
@@ -80,40 +94,27 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid,
 int venus_access(struct super_block *sb, struct ViceFid *fid, int mask);
 int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
                 unsigned int cmd, struct PioctlData *data);
-int coda_downcall(int opcode, struct outputArgs *out);
+int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
 int coda_upcall(struct coda_sb_info *mntinfo, int inSize, 
-               int *outSize, struct inputArgs *buffer);
+               int *outSize, union inputArgs *buffer);
+int venus_fsync(struct super_block *sb, struct ViceFid *fid);
 
 
 /* messages between coda filesystem in kernel and Venus */
+extern int coda_hard;
+extern unsigned long coda_timeout;
 struct vmsg {
-    struct queue        vm_chain;
-    caddr_t            vm_data;
-    u_short            vm_flags;
-    u_short             vm_inSize;  /* Size is at most 5000 bytes */
-    u_short            vm_outSize;
-    u_short            vm_opcode;  /* copied from data to save lookup */
-    int                        vm_unique;
-    struct wait_queue  *vm_sleep;   /* process' wait queue */
-};
-
-/* communication pending/processing queues queues */
-struct vcomm {
-       u_long              vc_seq;
-       struct wait_queue  *vc_waitq; /* Venus wait queue */
-       struct queue        vc_pending;
-       struct queue        vc_processing;
+       struct queue        vm_chain;
+       caddr_t         vm_data;
+       u_short         vm_flags;
+       u_short             vm_inSize;  /* Size is at most 5000 bytes */
+       u_short         vm_outSize;
+       u_short         vm_opcode;  /* copied from data to save lookup */
+       int                     vm_unique;
+       struct wait_queue  *vm_sleep;   /* process' wait queue */
+       unsigned long       vm_posttime;
 };
 
-static inline int vcomm_open(struct vcomm *vcp)
-{
-        return ((vcp)->vc_pending.forw != NULL);
-}
-
-static inline void mark_vcomm_closed(struct vcomm *vcp)
-{
-        (vcp)->vc_pending.forw = NULL;
-}
 
 /*
  * Statistics
index 2fe53ca3da2203de70408ff66663a4b901efab22..5c1cb05bd7d787f5409788ca3f7e08f34093fa42 100644 (file)
@@ -41,8 +41,8 @@ struct elf_prstatus
 #endif
        struct elf_siginfo pr_info;     /* Info associated with signal */
        short   pr_cursig;              /* Current signal */
-       sigset_t pr_sigpend;            /* Set of pending signals */
-       sigset_t pr_sighold;            /* Set of held signals */
+       unsigned long pr_sigpend;       /* Set of pending signals */
+       unsigned long pr_sighold;       /* Set of held signals */
 #if 0
        struct sigaltstack pr_altstack; /* Alternate stack info */
        struct sigaction pr_action;     /* Signal action for current sig */
diff --git a/include/linux/filter.h b/include/linux/filter.h
new file mode 100644 (file)
index 0000000..dcf3355
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Linux Socket Filter Data Structures
+ */
+
+#ifndef __LINUX_FILTER_H__
+#define __LINUX_FILTER_H__
+
+/*
+ * Current version of the filter code architecture.
+ */
+#define BPF_MAJOR_VERSION 1
+#define BPF_MINOR_VERSION 1
+
+/*
+ *     Try and keep these values and structures similar to BSD, especially
+ *     the BPF code definitions which need to match so you can share filters
+ */
+struct sock_filter     /* Filter block */
+{
+        u16    code;   /* Actual filter code */
+        u8     jt;     /* Jump true */
+        u8     jf;     /* Jump false */
+        u32    k;      /* Generic multiuse field */
+};
+
+struct sock_fprog      /* Required for SO_ATTACH_FILTER. */
+{
+        unsigned short         len;    /* Number of filter blocks */
+        struct sock_filter     *filter;
+};
+
+/*
+ * Instruction classes
+ */
+
+#define BPF_CLASS(code) ((code) & 0x07)
+#define         BPF_LD          0x00
+#define         BPF_LDX         0x01
+#define         BPF_ST          0x02
+#define         BPF_STX         0x03
+#define         BPF_ALU         0x04
+#define         BPF_JMP         0x05
+#define         BPF_RET         0x06
+#define         BPF_MISC        0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code)  ((code) & 0x18)
+#define         BPF_W           0x00
+#define         BPF_H           0x08
+#define         BPF_B           0x10
+#define BPF_MODE(code)  ((code) & 0xe0)
+#define         BPF_IMM         0x00
+#define         BPF_ABS         0x20
+#define         BPF_IND         0x40
+#define         BPF_MEM         0x60
+#define         BPF_LEN         0x80
+#define         BPF_MSH         0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code)    ((code) & 0xf0)
+#define         BPF_ADD         0x00
+#define         BPF_SUB         0x10
+#define         BPF_MUL         0x20
+#define         BPF_DIV         0x30
+#define         BPF_OR          0x40
+#define         BPF_AND         0x50
+#define         BPF_LSH         0x60
+#define         BPF_RSH         0x70
+#define         BPF_NEG         0x80
+#define         BPF_JA          0x00
+#define         BPF_JEQ         0x10
+#define         BPF_JGT         0x20
+#define         BPF_JGE         0x30
+#define         BPF_JSET        0x40
+#define BPF_SRC(code)   ((code) & 0x08)
+#define         BPF_K           0x00
+#define         BPF_X           0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code)  ((code) & 0x18)
+#define         BPF_A           0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define         BPF_TAX         0x00
+#define         BPF_TXA         0x80
+
+#define BPF_MAXINSNS 512
+
+/*
+ * Macros for filter block array initializers.
+ */
+#define BPF_STMT(code, k) { (unsigned short)(code), 0, 0, k }
+#define BPF_JUMP(code, k, jt, jf) { (unsigned short)(code), jt, jf, k }
+
+/*
+ * Number of scratch memory words for: BPF_ST and BPF_STX
+ */
+#define BPF_MEMWORDS 16
+
+#ifdef __KERNEL__
+extern int sk_run_filter(unsigned char *data, int len, struct sock_filter *filter, int flen);
+extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_FILTER_H__ */
index a3cabfbc1bee2f3f59e46b4d7033e1d2f4090ad4..619248316f6213c6e565a3d2ab3175fcfdd02557 100644 (file)
@@ -37,6 +37,7 @@ enum {
        SPECIALIX_BH,
        ESP_BH,
        NET_BH,
+       SCSI_BH,
        IMMEDIATE_BH,
        KEYBOARD_BH,
        CYCLADES_BH,
index cf21ecf7316623012b715f3bedf00c773edbf002..a5e6544f6169b74c0989fdf37d1e90ef0d8c5bfb 100644 (file)
@@ -64,12 +64,6 @@ asmlinkage int printk(const char * fmt, ...)
 #define pr_info(fmt,arg...) \
        printk(KERN_INFO fmt,##arg)
 
-/*
- * "suser()" checks against the effective user id, while "fsuser()"
- * is used for file permission checking and checks against the fsuid..
- */
-#define fsuser() (current->fsuid == 0)
-
 /*
  *      Display an IP address in readable format.
  */
index c8ea8ffdf632e0d3008376b3814bf317583f9171..2a6a4c080715857c5d269a14779cf0337ffd4c28 100644 (file)
@@ -33,6 +33,7 @@ enum nfs_stat {
        NFSERR_EAGAIN = 11,
        NFSERR_ACCES = 13,
        NFSERR_EXIST = 17,
+       NFSERR_XDEV = 18,
        NFSERR_NODEV = 19,
        NFSERR_NOTDIR = 20,
        NFSERR_ISDIR = 21,
index 3c869e38d9524603e7311c892145dca2114818c4..cf67ca5b4211b7a92022840c627a6e58d16ec839 100644 (file)
@@ -210,14 +210,7 @@ nfs_write_error(struct inode *inode)
 
 /* NFS root */
 
-#define NFS_ROOT               "/tftpboot/%s"
-#define NFS_ROOT_NAME_LEN      256
-#define NFS_ROOT_ADDRS_LEN     128
-
 extern int nfs_root_mount(struct super_block *sb);
-extern int nfs_root_init(char *nfsname, char *nfsaddrs);
-extern char nfs_root_name[];
-extern char nfs_root_addrs[];
 
 #endif /* __KERNEL__ */
 
index 61aad6e723a7908bfa18d2a3a7ab46526f5198c9..acbfc2939313243f89e68ee5c6c96d9f694e7ba8 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _LINUX_NTFS_FS_H
 #define _LINUX_NTFS_FS_H
 
-int init_ntfs_fs();
+int init_ntfs_fs(void);
 
 #endif
 
index 08161669bed83c4eb3ee17f8f498311c268e6118..c50ae37a99b29ace20924a5e1db45a03a459dd67 100644 (file)
@@ -926,5 +926,7 @@ extern const char *pci_strvendor (unsigned int vendor);
 extern const char *pci_strdev (unsigned int vendor, unsigned int device);
 
 extern int get_pci_list (char *buf);
+
+extern void pci_quirks_init (void);
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
index f2b34cb3161eb675179f71fe73fe20e81805af65..1bbc7c006abaae66833a2c907819670fd58f3b7d 100644 (file)
@@ -513,6 +513,11 @@ extern void free_irq(unsigned int irq, void *dev_id);
  * it returns true (to do BSD-style accounting where the process is flagged
  * if it uses root privs). The implication of this is that you should do
  * normal permissions checks first, and check suser() last.
+ *
+ * [Dec 1997 -- Chris Evans]
+ * For correctness, the above considerations need to be extended to
+ * fsuser(). This is done, along with moving fsuser() checks to be
+ * last.
  */
 extern inline int suser(void)
 {
@@ -523,6 +528,15 @@ extern inline int suser(void)
        return 0;
 }
 
+extern inline int fsuser(void)
+{
+       if (current->fsuid == 0) {
+               current->flags |= PF_SUPERPRIV;
+               return 1;
+       }
+       return 0;
+}
+
 /*
  * Routines for handling mm_structs
  */
index 00ae5082f2c810c2e57836841bf975d4fa5b0185..319546d05bf669ce43eb2235966bdd781d8cdd56 100644 (file)
@@ -23,8 +23,6 @@
  *
  * FLOPPY_TIMER                floppy disk timer (not used right now)
  * 
- * SCSI_TIMER          scsi.c timeout timer
- *
  * NET_TIMER           tcp/ip timeout timer
  *
  * COPRO_TIMER         387 timeout for buggy hardware..
@@ -44,7 +42,6 @@
 
 #define HD_TIMER       16
 #define FLOPPY_TIMER   17
-#define SCSI_TIMER     18
 #define NET_TIMER      19
 #define SOUND_TIMER    20
 #define COPRO_TIMER    21
index 4cf4d241f6274d99b3caf1a5e257b9898b727d2e..80ff5d91dea737b62141b6a109dec1e2db264c7d 100644 (file)
@@ -110,6 +110,7 @@ struct video_audio
 #define VIDEO_AUDIO_VOLUME     4
 #define VIDEO_AUDIO_BASS       8
 #define VIDEO_AUDIO_TREBLE     16      
+       char    name[16];
 };
 
 struct video_clip
@@ -164,6 +165,9 @@ struct video_key
 #define VIDIOCSAUDIO           _IOW('v',17, struct video_audio)        /* Audio source, mute etc */
 
 
+#define BASE_VIDIOCPRIVATE     192             /* 192-255 are private */
+
+
 #define VID_HARDWARE_BT848     1
 #define VID_HARDWARE_QCAM_BW   2
 #define VID_HARDWARE_PMS       3
index 8dd105485ecbbf9ea791dd0b580d7ee55680ab01..e46500a9566dc1fd820f40f982180b1c245c2f19 100644 (file)
 #include <net/dn.h>
 #endif
 
+#ifdef CONFIG_FILTER
+#include <linux/filter.h>
+#endif
+
 #include <asm/atomic.h>
 
 /*
@@ -452,10 +456,12 @@ struct sock
        unsigned char           localroute;     /* Route locally only */
        struct ucred            peercred;
 
-       /* What the user has tried to set with the security API */
-       short                   authentication;
-       short                   encryption;  
-       short                   encrypt_net;
+#ifdef CONFIG_FILTER
+       /* Socket Filtering Instructions */
+       int                     filter;
+       struct sock_filter      *filter_data;
+#endif /* CONFIG_FILTER */
+
 /*
  *     This is where all the private (optional) areas that don't
  *     overlap will eventually live. 
@@ -832,6 +838,26 @@ extern void sklist_remove_socket(struct sock **list, struct sock *sk);
 extern void sklist_insert_socket(struct sock **list, struct sock *sk);
 extern void sklist_destroy_socket(struct sock **list, struct sock *sk);
 
+#ifdef CONFIG_FILTER
+/*
+ * Run the filter code and then cut skb->data to correct size returned by
+ * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
+ * than pkt_len we keep whole skb->data.
+ */
+extern __inline__ int sk_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
+{
+       int pkt_len;
+
+        pkt_len = sk_run_filter(skb->data, skb->len, filter, flen);
+        if(!pkt_len)
+                return 1;      /* Toss Packet */
+        else
+                skb_trim(skb, pkt_len);
+
+       return 0;
+}
+#endif /* CONFIG_FILTER */
+
 /*
  *     Queue a received datagram if it will fit. Stream and sequenced
  *     protocols can't normally use this as they need to fit buffers in
@@ -859,8 +885,17 @@ extern __inline__ void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
 extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        if (atomic_read(&sk->rmem_alloc) + skb->truesize >= sk->rcvbuf)
-               return -ENOMEM;
-       skb_set_owner_r(skb, sk);
+                return -ENOMEM;
+        skb_set_owner_r(skb, sk);
+
+#ifdef CONFIG_FILTER
+       if (sk->filter)
+       {
+               if (sk_filter(skb, sk->filter_data, sk->filter))
+                       return -1;      /* Toss packet */
+       }
+#endif /* CONFIG_FILTER */
+
        skb_queue_tail(&sk->receive_queue,skb);
        if (!sk->dead)
                sk->data_ready(sk,skb->len);
index 562e09507d93d20e70e7a98dd21bd97b4d4f8806..a8e77e3ca35b24e37a330f6a9309434b3ccd1522 100644 (file)
@@ -33,9 +33,6 @@
 #include <linux/major.h>
 #include <linux/blk.h>
 #include <linux/init.h>
-#ifdef CONFIG_ROOT_NFS
-#include <linux/nfs_fs.h>
-#endif
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -76,6 +73,7 @@ extern long powermac_init(unsigned long, unsigned long);
 extern void sysctl_init(void);
 extern void filescache_init(void);
 extern void signals_init(void);
+extern void dquot_init(void);
 
 extern void smp_setup(char *str, int *ints);
 extern void no_scroll(char *str, int *ints);
@@ -88,6 +86,9 @@ extern void console_setup(char *str, int *ints);
 #ifdef CONFIG_PRINTER
 extern void lp_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_JOYSTICK
+extern void js_setup(char *str, int *ints);
+#endif
 extern void eth_setup(char *str, int *ints);
 #ifdef CONFIG_ARCNET_COM20020
 extern void com20020_setup(char *str, int *ints);
@@ -134,10 +135,8 @@ 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);
-#ifdef NOTDEF
-extern void ppa_setup(char *str, int *ints);
-#endif
 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);
 extern void reboot_setup(char *str, int *ints);
 extern void video_setup(char *str, int *ints);
@@ -259,6 +258,12 @@ extern void plip_setup(char *str, int *ints);
 #ifdef CONFIG_HFMODEM
 extern void hfmodem_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_IP_PNP
+extern void ip_auto_config_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_ROOT_NFS
+extern void nfs_root_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_FTAPE
 extern void ftape_setup(char *str, int *ints);
 #endif
@@ -297,13 +302,6 @@ kdev_t real_root_dev;
 int root_mountflags = MS_RDONLY;
 char *execute_command = NULL;
 
-#ifdef CONFIG_ROOT_NFS
-char nfs_root_name[NFS_ROOT_NAME_LEN] = { "default" };
-char nfs_root_addrs[NFS_ROOT_ADDRS_LEN] = { "" };
-#endif
-
-extern void dquot_init(void);
-
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
 static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
 
@@ -321,6 +319,7 @@ char *get_options(char *str, int *ints)
        return(cur);
 }
 
+#ifdef CONFIG_PROFILE
 __initfunc(static void profile_setup(char *str, int *ints))
 {
        if (ints[0] > 0)
@@ -332,13 +331,129 @@ __initfunc(static void profile_setup(char *str, int *ints))
                prof_shift = 2;
 #endif
 }
+#endif
+
+
+static struct dev_name_struct {
+       const char *name;
+       const int num;
+} root_dev_names[] __initdata = {
+#ifdef CONFIG_ROOT_NFS
+       { "nfs",     0x00ff },
+#endif
+#ifdef CONFIG_BLK_DEV_IDE
+       { "hda",     0x0300 },
+       { "hdb",     0x0340 },
+       { "hdc",     0x1600 },
+       { "hdd",     0x1640 },
+       { "hde",     0x2100 },
+       { "hdf",     0x2140 },
+       { "hdg",     0x2200 },
+       { "hdh",     0x2240 },
+#endif
+#ifdef CONFIG_BLK_DEV_SD
+       { "sda",     0x0800 },
+       { "sdb",     0x0810 },
+       { "sdc",     0x0820 },
+       { "sdd",     0x0830 },
+       { "sde",     0x0840 },
+#endif
+#ifdef CONFIG_ATARI_ACSI
+       { "ada",     0x1c00 },
+       { "adb",     0x1c10 },
+       { "adc",     0x1c20 },
+       { "add",     0x1c30 },
+       { "ade",     0x1c40 },
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+       { "fd",      0x0200 },
+#endif
+#ifdef CONFIG_BLK_DEV_XD
+       { "xda",     0x0d00 },
+       { "xdb",     0x0d40 },
+#endif
+#ifdef CONFIG_BLK_DEV_RAM
+       { "ram",     0x0100 },
+#endif
+#ifdef CONFIG_BLK_DEV_SR
+       { "scd",     0x0b00 },
+#endif
+#ifdef CONFIG_MCD
+       { "mcd",     0x1700 },
+#endif
+#ifdef CONFIG_CDU535
+       { "cdu535",  0x1800 },
+       { "sonycd",  0x1800 },
+#endif
+#ifdef CONFIG_AZTCD
+       { "aztcd",   0x1d00 },
+#endif
+#ifdef CONFIG_CM206
+       { "cm206cd", 0x2000 },
+#endif
+#ifdef CONFIG_GSCD
+       { "gscd",    0x1000 },
+#endif
+#ifdef CONFIG_SBPCD
+       { "sbpcd",   0x1900 },
+#endif
+#ifdef CONFIG_BLK_DEV_PS2
+       { "eda",     0x2400 },
+       { "eza",     0x2800 },
+#endif
+#ifdef CONFIG_BPCD
+       { "bpcd",    0x2900 },
+#endif
+#if CONFIG_APBLOCK
+       { "apblock", APBLOCK_MAJOR << 8},
+#endif
+#if CONFIG_DDV
+       { "ddv", DDV_MAJOR << 8},
+#endif
+       { NULL, 0 }
+};
+
+__initfunc(static void root_dev_setup(char *line, int *num))
+{
+       int base = 0;
+       if (strncmp(line,"/dev/",5) == 0) {
+               struct dev_name_struct *dev = root_dev_names;
+               line += 5;
+               do {
+                       int len = strlen(dev->name);
+                       if (strncmp(line,dev->name,len) == 0) {
+                               line += len;
+                               base = dev->num;
+                               break;
+                       }
+                       dev++;
+               } while (dev->name);
+       }
+       ROOT_DEV = to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
+}
 
-struct {
+/*
+ * List of kernel command line parameters. The first table lists parameters
+ * which are subject to values parsing (leading numbers are converted to
+ * an array of ints and chopped off the string), the second table contains
+ * the few exceptions which obey their own syntax rules.
+ */
+
+struct kernel_param {
        const char *str;
        void (*setup_func)(char *, int *);
-} bootsetups[] __initdata = {
+};
+
+static struct kernel_param cooked_params[] __initdata = {
+/* FIXME: make PNP just become reserve_setup */
+#ifndef CONFIG_KERNEL_PNP_RESOURCE
        { "reserve=", reserve_setup },
+#else
+       { "reserve=", pnp_reserve_setup },
+#endif
+#ifdef CONFIG_PROFILE
        { "profile=", profile_setup },
+#endif
 #ifdef __SMP__
        { "nosmp", smp_setup },
        { "maxcpus=", smp_setup },
@@ -389,8 +504,12 @@ struct {
 #ifdef CONFIG_PRINTER
         { "lp=", lp_setup },
 #endif
+#ifdef CONFIG_JOYSTICK
+       { "js=", js_setup },
+#endif
 #ifdef CONFIG_SCSI
        { "max_scsi_luns=", scsi_luns_setup },
+       { "scsi_logging=", scsi_logging_setup },
 #endif
 #ifdef CONFIG_SCSI_ADVANSYS
        { "advansys=", advansys_setup },
@@ -460,9 +579,6 @@ struct {
 #ifdef CONFIG_SCSI_7000FASST
        { "wd7000=", wd7000_setup},
 #endif
-#ifdef NOTDEF /* CONFIG_SCSI_PPA */
-        { "ppa=", ppa_setup },
-#endif
 #ifdef CONFIG_SCSI_IBMMCA
         { "ibmmcascsi=", ibmmca_scsi_setup },
 #endif
@@ -472,7 +588,7 @@ struct {
 #ifdef CONFIG_BLK_DEV_EZ
        { "ez=", ez_setup },
 #endif
-#ifdef CONFIG_BLK_DEV_FD
+#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
        { "floppy=", floppy_setup },
 #endif
 #ifdef CONFIG_BLK_DEV_PS2
@@ -599,6 +715,18 @@ struct {
        { 0, 0 }
 };
 
+static struct kernel_param raw_params[] __initdata = {
+       { "root=", root_dev_setup },
+#ifdef CONFIG_ROOT_NFS
+       { "nfsroot=", nfs_root_setup },
+       { "nfsaddrs=", ip_auto_config_setup },
+#endif
+#ifdef CONFIG_IP_PNP
+       { "ip=", ip_auto_config_setup },
+#endif
+       { 0, 0 }
+};
+
 #ifdef CONFIG_BLK_DEV_RAM
 __initfunc(static void ramdisk_start_setup(char *str, int *ints))
 {
@@ -623,13 +751,11 @@ __initfunc(static void ramdisk_size(char *str, int *ints))
        if (ints[0] > 0 && ints[1] >= 0)
                rd_size = ints[1];
 }
-
 #endif
 
 __initfunc(static int checksetup(char *line))
 {
-       int i = 0;
-       int ints[11];
+       int i, ints[11];
 
 #ifdef CONFIG_BLK_DEV_IDE
        /* ide driver needs the basic string, rather than pre-processed values */
@@ -638,13 +764,19 @@ __initfunc(static int checksetup(char *line))
                return 1;
        }
 #endif
-       while (bootsetups[i].str) {
-               int n = strlen(bootsetups[i].str);
-               if (!strncmp(line,bootsetups[i].str,n)) {
-                       bootsetups[i].setup_func(get_options(line+n,ints), ints);
+       for (i=0; raw_params[i].str; i++) {
+               int n = strlen(raw_params[i].str);
+               if (!strncmp(line,raw_params[i].str,n)) {
+                       raw_params[i].setup_func(line+n, NULL);
+                       return 1;
+               }
+       }
+       for (i=0; cooked_params[i].str; i++) {
+               int n = strlen(cooked_params[i].str);
+               if (!strncmp(line,cooked_params[i].str,n)) {
+                       cooked_params[i].setup_func(get_options(line+n, ints), ints);
                        return 1;
                }
-               i++;
        }
        return 0;
 }
@@ -665,7 +797,7 @@ __initfunc(void calibrate_delay(void))
 
        loops_per_sec = (1<<12);
 
-       printk("Calibrating delay loop.. ");
+       printk("Calibrating delay loop... ");
        while (loops_per_sec <<= 1) {
                /* wait for "start of" clock tick */
                ticks = jiffies;
@@ -696,84 +828,17 @@ __initfunc(void calibrate_delay(void))
 /* finally, adjust loops per second in terms of seconds instead of clocks */   
        loops_per_sec *= HZ;
 /* Round the value and print it */     
-       printk("ok - %lu.%02lu BogoMIPS\n",
+       printk("%lu.%02lu BogoMIPS\n",
                (loops_per_sec+2500)/500000,
                ((loops_per_sec+2500)/5000) % 100);
 }
 
-__initfunc(static void parse_root_dev(char * line))
-{
-       int base = 0;
-       static struct dev_name_struct {
-               const char *name;
-               const int num;
-       } devices[] = {
-               { "nfs",     0x00ff },
-               { "hda",     0x0300 },
-               { "hdb",     0x0340 },
-               { "hdc",     0x1600 },
-               { "hdd",     0x1640 },
-               { "hde",     0x2100 },
-               { "hdf",     0x2140 },
-               { "hdg",     0x2200 },
-               { "hdh",     0x2240 },
-               { "sda",     0x0800 },
-               { "sdb",     0x0810 },
-               { "sdc",     0x0820 },
-               { "sdd",     0x0830 },
-               { "sde",     0x0840 },
-               { "ada",     0x1c00 },
-               { "adb",     0x1c10 },
-               { "adc",     0x1c20 },
-               { "add",     0x1c30 },
-               { "ade",     0x1c40 },
-               { "fd",      0x0200 },
-               { "xda",     0x0d00 },
-               { "xdb",     0x0d40 },
-               { "ram",     0x0100 },
-               { "scd",     0x0b00 },
-               { "mcd",     0x1700 },
-               { "cdu535",  0x1800 },
-               { "aztcd",   0x1d00 },
-               { "cm206cd", 0x2000 },
-               { "gscd",    0x1000 },
-               { "sbpcd",   0x1900 },
-               { "sonycd",  0x1800 },
-               { "eda",     0x2400 },
-               { "eza",     0x2800 },
-               { "bpcd",    0x2900 },
-#if CONFIG_APBLOCK
-               { "apblock", APBLOCK_MAJOR << 8},
-#endif
-#if CONFIG_DDV
-               { "ddv", DDV_MAJOR << 8},
-#endif
-               { NULL, 0 }
-       };
-
-       if (strncmp(line,"/dev/",5) == 0) {
-               struct dev_name_struct *dev = devices;
-               line += 5;
-               do {
-                       int len = strlen(dev->name);
-                       if (strncmp(line,dev->name,len) == 0) {
-                               line += len;
-                               base = dev->num;
-                               break;
-                       }
-                       dev++;
-               } while (dev->name);
-       }
-       ROOT_DEV = to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
-}
-
 /*
  * This is a simple kernel command line parsing function: it parses
  * the command line, and fills in the arguments/environment to init
  * as appropriate. Any cmd-line option is taken to be an environment
  * variable if it contains the character '='.
  *
- *
  * This routine also checks for options meant for the kernel.
  * These options are not given to init - they are for internal kernel use only.
  */
@@ -793,33 +858,6 @@ __initfunc(static void parse_options(char *line))
                /*
                 * check for kernel options first..
                 */
-               if (!strncmp(line,"root=",5)) {
-                       parse_root_dev(line+5);
-                       continue;
-               }
-#ifdef CONFIG_ROOT_NFS
-               if (!strncmp(line, "nfsroot=", 8)) {
-                       int n;
-                       line += 8;
-                       ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
-                       if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
-                               strncpy(nfs_root_name, line, sizeof(nfs_root_name));
-                               nfs_root_name[sizeof(nfs_root_name)-1] = '\0';
-                               continue;
-                       }
-                       n = strlen(line) + strlen(NFS_ROOT);
-                       if (n >= sizeof(nfs_root_name))
-                               line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
-                       sprintf(nfs_root_name, NFS_ROOT, line);
-                       continue;
-               }
-               if (!strncmp(line, "nfsaddrs=", 9)) {
-                       line += 9;
-                       strncpy(nfs_root_addrs, line, sizeof(nfs_root_addrs));
-                       nfs_root_addrs[sizeof(nfs_root_addrs)-1] = '\0';
-                       continue;
-               }
-#endif
                if (!strcmp(line,"ro")) {
                        root_mountflags |= MS_RDONLY;
                        continue;
@@ -930,6 +968,7 @@ __initfunc(asmlinkage void start_kernel(void))
  * Interrupts are still disabled. Do necessary setups, then
  * enable them
  */
+       printk(linux_banner);
        setup_arch(&command_line, &memory_start, &memory_end);
        memory_start = paging_init(memory_start,memory_end);
        trap_init();
@@ -941,13 +980,6 @@ __initfunc(asmlinkage void start_kernel(void))
        init_modules();
 #endif
 #ifdef CONFIG_PROFILE
-       if (!prof_shift)
-#ifdef CONFIG_PROFILE_SHIFT
-               prof_shift = CONFIG_PROFILE_SHIFT;
-#else
-               prof_shift = 2;
-#endif
-#endif
        if (prof_shift) {
                prof_buffer = (unsigned int *) memory_start;
                /* only text is profiled */
@@ -956,14 +988,18 @@ __initfunc(asmlinkage void start_kernel(void))
                memory_start += prof_len * sizeof(unsigned int);
                memset(prof_buffer, 0, prof_len * sizeof(unsigned int));
        }
+#endif
 #ifdef CONFIG_SBUS
        memory_start = sbus_init(memory_start,memory_end);
 #endif
-#ifdef CONFIG_PMAC
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
        memory_start = powermac_init(memory_start, memory_end);
+#endif
+#if defined(CONFIG_PCI) && defined(CONFIG_PCI_CONSOLE)
+       memory_start = pci_init(memory_start,memory_end);
 #endif
        memory_start = console_init(memory_start,memory_end);
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && !defined(CONFIG_PCI_CONSOLE)
        memory_start = pci_init(memory_start,memory_end);
 #endif
 #ifdef CONFIG_MCA
@@ -997,10 +1033,8 @@ __initfunc(asmlinkage void start_kernel(void))
        ipc_init();
 #endif
        dquot_init();
-       sti();
        check_bugs();
 
-       printk(linux_banner);
        printk("POSIX conformance testing by UNIFIX\n");
 #ifdef __SMP__
        smp_init();
@@ -1130,7 +1164,7 @@ static int init(void * unused)
         * trying to recover a really broken machine.
         */
 
-       if(execute_command)
+       if (execute_command)
                execve(execute_command,argv_init,envp_init);
        execve("/sbin/init",argv_init,envp_init);
        execve("/etc/init",argv_init,envp_init);
index de7b2a2624bd98e7eabd603822411cb9cc81f255..8e5be61d291fff793e97a78369acc86bce87995f 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -403,19 +403,15 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
                        seminfo.semusz = used_semids;
                        seminfo.semaem = used_sems;
                }
-               err = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
-               if (err)
+               err = -EFAULT;
+               if (copy_to_user (tmp, &seminfo, sizeof(struct seminfo))) 
                        goto out;
-               copy_to_user (tmp, &seminfo, sizeof(struct seminfo));
                err = max_semid;
                goto out;
        }
 
        case SEM_STAT:
                buf = arg.buf;
-               err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
-               if (err)
-                       goto out;
                err = -EINVAL;
                if (semid > max_semid)
                        goto out;
@@ -430,8 +426,9 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
                tbuf.sem_otime  = sma->sem_otime;
                tbuf.sem_ctime  = sma->sem_ctime;
                tbuf.sem_nsems  = sma->sem_nsems;
-               copy_to_user (buf, &tbuf, sizeof(*buf));
-               err = id;
+               err = -EFAULT;
+               if (copy_to_user (buf, &tbuf, sizeof(*buf)) == 0)
+                       err = id;
                goto out;
        }
 
@@ -475,9 +472,7 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
                case GETZCNT: return count_semzcnt(sma,semnum);
                case GETALL:
                        array = arg.array;
-                       err = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
-                       if (err)
-                               goto out;
+                       break;
                }
                break;
        case SETVAL:
@@ -496,9 +491,10 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
                goto out;
        case SETALL: /* arg is a pointer to an array of ushort */
                array = arg.array;
-               if ((err = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
-                       goto out;
-               copy_from_user (sem_io, array, nsems*sizeof(ushort));
+               err = -EFAULT;
+               if (copy_from_user (sem_io, array, nsems*sizeof(ushort)))
+                      goto out;
+               err = 0;
                for (i = 0; i < nsems; i++)
                        if (sem_io[i] > SEMVMX) {
                                err = -ERANGE;
@@ -507,14 +503,12 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
                break;
        case IPC_STAT:
                buf = arg.buf;
-               if ((err = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
-                       goto out;
                break;
        case IPC_SET:
                buf = arg.buf;
-               if ((err = verify_area (VERIFY_READ, buf, sizeof (*buf))))
-                       goto out;
-               copy_from_user (&tbuf, buf, sizeof (*buf));
+               err = copy_from_user (&tbuf, buf, sizeof (*buf));
+               if (err)
+                       err = -EFAULT;
                break;
        }
 
@@ -531,7 +525,8 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
                        goto out;
                for (i = 0; i < sma->sem_nsems; i++)
                        sem_io[i] = sma->sem_base[i].semval;
-               copy_to_user (array, sem_io, nsems*sizeof(ushort));
+               if (copy_to_user (array, sem_io, nsems*sizeof(ushort)))
+                       err = -EFAULT;
                break;
        case SETVAL:
                err = -EACCES;
@@ -564,7 +559,8 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
                tbuf.sem_otime  = sma->sem_otime;
                tbuf.sem_ctime  = sma->sem_ctime;
                tbuf.sem_nsems  = sma->sem_nsems;
-               copy_to_user (buf, &tbuf, sizeof(*buf));
+               if (copy_to_user (buf, &tbuf, sizeof(*buf)))
+                       err = -EFAULT;
                break;
        case SETALL:
                err = -EACCES;
@@ -606,9 +602,8 @@ asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
        error = -EFAULT;
        if (!tsops)
                goto out;
-       if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
+       if (copy_from_user (sops, tsops, nsops * sizeof(*tsops)))
                goto out;
-       copy_from_user (sops, tsops, nsops * sizeof(*tsops));
        id = (unsigned int) semid % SEMMNI;
        error = -EINVAL;
        if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
index a66acd361d27ead2dca9ee44526a7bac7dd61c72..09de071beda6033acc4541d670b0613822fcecdf 100644 (file)
@@ -241,6 +241,7 @@ EXPORT_SYMBOL(tq_disk);
 EXPORT_SYMBOL(efind_buffer);
 EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL(max_sectors);
+EXPORT_SYMBOL(max_readahead);
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
index 91bc771f2b20d4dc8b6ec7c27d97b7b79be4d727..9bdf1f40750d96b30449fa470c2f267717f875a1 100644 (file)
@@ -324,6 +324,8 @@ void register_console(struct console * console)
         *      that registers here.
         */
        if (selected_console == 0) {
+               if (console->index < 0)
+                       console->index = 0;
                if (console->setup == NULL ||
                    console->setup(console, NULL) == 0) {
                        console->flags |= CON_ENABLED | CON_FIRST;
index 12abcefefb98914abd7725fde4d89ceb61d4cbbf..6a75e8c97eb43c8b7939ef80563d73a3b3ed0291 100644 (file)
@@ -160,12 +160,6 @@ static ctl_table kern_table[] = {
        {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
         0644, NULL, &proc_dointvec},
 #endif
-#ifdef CONFIG_ROOT_NFS
-       {KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
-        0644, NULL, &proc_dostring, &sysctl_string },
-       {KERN_NFSRADDRS, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
-        0644, NULL, &proc_dostring, &sysctl_string },
-#endif
 #ifdef CONFIG_BINFMT_JAVA
        {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
         64, 0644, NULL, &proc_dostring, &sysctl_string },
index 72dda956df982deae2105638355b9b7c2dc77807..db245d7b6abe740d1ee89bb7c7f7dd2998f72565 100644 (file)
@@ -436,16 +436,6 @@ static void profile_readahead(int async, struct file *filp)
  *   64k if defined (4K page size assumed).
  */
 
-#define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK)
-
-#if 0  /* small readahead */
-#define MAX_READAHEAD PageAlignSize(4096*7)
-#define MIN_READAHEAD PageAlignSize(4096*2)
-#else /* large readahead */
-#define MAX_READAHEAD PageAlignSize(4096*18)
-#define MIN_READAHEAD PageAlignSize(4096*3)
-#endif
-
 static inline int get_max_readahead(struct inode * inode)
 {
        if (!inode->i_dev || !max_readahead[MAJOR(inode->i_dev)])
index 5a5964e345895e5870eef8c56c16da6606541270..0beff300de0dd3b1c652e8cfb4ed1cd26b9adffc 100644 (file)
@@ -16,6 +16,7 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then
   fi
 fi
 bool 'Network aliasing'  CONFIG_NET_ALIAS
+bool 'Socket Filtering'  CONFIG_FILTER
 tristate 'Unix domain sockets' CONFIG_UNIX
 bool 'TCP/IP networking' CONFIG_INET
 if [ "$CONFIG_INET" = "y" ]; then
index 2ae7761573c6433dd054cf7db4081c7df0887bf3..1090e80cb0014df12a4cca940e000fb74d0c4198 100644 (file)
@@ -16,6 +16,10 @@ ifeq ($(CONFIG_SYSCTL),y)
 O_OBJS += sysctl_net_core.o
 endif
 
+ifdef CONFIG_FILTER
+O_OBJS += filter.o
+endif
+
 ifdef CONFIG_NET
 
 O_OBJS += dev.o dev_mcast.o
diff --git a/net/core/filter.c b/net/core/filter.c
new file mode 100644 (file)
index 0000000..6b32abb
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Linux Socket Filter - Kernel level socket filtering
+ *
+ * Author:
+ *     Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
+ *
+ * Based on the design of:
+ *     - The Berkely Packet Filter
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_FILTER)
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fcntl.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_packet.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/filter.h>
+
+/*
+ * Decode and apply filter instructions to the skb->data.
+ * Return length to keep, 0 for none. skb is the data we are
+ * filtering, filter is the array of filter instructions, and
+ * len is the number of filter blocks in the array.
+ */
+int sk_run_filter(unsigned char *data, int len, struct sock_filter *filter, int flen)
+{
+       struct sock_filter *fentry;     /* We walk down these */
+       u32 A = 0;                      /* Accumulator */
+       u32 X = 0;                      /* Index Register */
+       u32 mem[BPF_MEMWORDS];          /* Scratch Memory Store */
+       int k;
+       int pc;
+       int *t;
+
+       /*
+        * Process array of filter instructions.
+        */
+
+       for(pc = 0; pc < flen; pc++)
+       {
+               fentry = &filter[pc];
+               if(fentry->code & BPF_X)
+                       t=&X;
+               else
+                       t=&fentry->k;
+                       
+               switch(fentry->code)
+               {
+                       case BPF_ALU|BPF_ADD|BPF_X:
+                       case BPF_ALU|BPF_ADD|BPF_K:
+                               A += *t;
+                               continue;
+
+                       case BPF_ALU|BPF_SUB|BPF_X:
+                       case BPF_ALU|BPF_SUB|BPF_K:
+                               A -= *t;
+                               continue;
+
+                       case BPF_ALU|BPF_MUL|BPF_X:
+                       case BPF_ALU|BPF_MUL|BPF_K:
+                               A *= *t;
+                               continue;
+
+                       case BPF_ALU|BPF_DIV|BPF_X:
+                       case BPF_ALU|BPF_DIV|BPF_K:
+                               if(*t == 0)
+                                       return (0);
+                               A /= *t;
+                               continue;
+
+                       case BPF_ALU|BPF_AND|BPF_X:
+                       case BPF_ALU|BPF_AND|BPF_K:
+                               A &= *t;
+                               continue;
+
+                       case BPF_ALU|BPF_OR|BPF_X:
+                       case BPF_ALU|BPF_OR|BPF_K:
+                               A |= *t;
+                               continue;
+
+                       case BPF_ALU|BPF_LSH|BPF_X:
+                       case BPF_ALU|BPF_LSH|BPF_K:
+                               A <<= *t;
+                               continue;
+
+                       case BPF_ALU|BPF_RSH|BPF_X:
+                       case BPF_ALU|BPF_RSH|BPF_K:
+                               A >>= *t;
+                               continue;
+
+                       case BPF_ALU|BPF_NEG:
+                               A = -A;
+                               continue;
+
+                       case BPF_JMP|BPF_JA:
+                               pc += fentry->k;
+                               continue;
+
+                       case BPF_JMP|BPF_JGT|BPF_K:
+                               pc += (A > fentry->k) ? fentry->jt : fentry->jf;
+                               continue;
+
+                       case BPF_JMP|BPF_JGE|BPF_K:
+                               pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
+                               continue;
+
+                       case BPF_JMP|BPF_JEQ|BPF_K:
+                               pc += (A == fentry->k) ? fentry->jt : fentry->jf;
+                               continue;
+
+                       case BPF_JMP|BPF_JSET|BPF_K:
+                               pc += (A & fentry->k) ? fentry->jt : fentry->jf;
+                               continue;
+
+                       case BPF_JMP|BPF_JGT|BPF_X:
+                               pc += (A > X) ? fentry->jt : fentry->jf;
+                               continue;
+
+                       case BPF_JMP|BPF_JGE|BPF_X:
+                               pc += (A >= X) ? fentry->jt : fentry->jf;
+                               continue;
+
+                       case BPF_JMP|BPF_JEQ|BPF_X:
+                               pc += (A == X) ? fentry->jt : fentry->jf;
+                               continue;
+
+                       case BPF_JMP|BPF_JSET|BPF_X:
+                               pc += (A & X) ? fentry->jt : fentry->jf;
+                               continue;
+                       case BPF_LD|BPF_W|BPF_ABS:
+                               k = fentry->k;
+                               if(k + sizeof(long) > len)
+                                       return (0);
+                               A = ntohl(*(long*)&data[k]);
+                               continue;
+
+                       case BPF_LD|BPF_H|BPF_ABS:
+                               k = fentry->k;
+                               if(k + sizeof(short) > len)
+                                       return (0);
+                               A = ntohs(*(short*)&data[k]);
+                               continue;
+
+                       case BPF_LD|BPF_B|BPF_ABS:
+                               k = fentry->k;
+                               if(k >= len)
+                                       return (0);
+                               A = data[k];
+                               continue;
+
+                       case BPF_LD|BPF_W|BPF_LEN:
+                               A = len;
+                               continue;
+
+                       case BPF_LDX|BPF_W|BPF_LEN:
+                               X = len;
+                               continue;
+
+                      case BPF_LD|BPF_W|BPF_IND:
+                               k = X + fentry->k;
+                               if(k + sizeof(u32) > len)
+                                       return (0);
+                                A = ntohl(*(u32 *)&data[k]);
+                               continue;
+
+                       case BPF_LD|BPF_H|BPF_IND:
+                               k = X + fentry->k;
+                               if(k + sizeof(u16) > len)
+                                       return (0);
+                               A = ntohs(*(u16*)&data[k]);
+                               continue;
+
+                       case BPF_LD|BPF_B|BPF_IND:
+                               k = X + fentry->k;
+                               if(k >= len)
+                                       return (0);
+                               A = data[k];
+                               continue;
+
+                       case BPF_LDX|BPF_B|BPF_MSH:
+                               /*
+                                *      Hack for BPF to handle TOS etc
+                                */
+                               k = fentry->k;
+                               if(k >= len)
+                                       return (0);
+                               X = (data[fentry->k] & 0xf) << 2;
+                               continue;
+
+                       case BPF_LD|BPF_IMM:
+                               A = fentry->k;
+                               continue;
+
+                       case BPF_LDX|BPF_IMM:
+                               X = fentry->k;
+                               continue;
+
+                       case BPF_LD|BPF_MEM:
+                               A = mem[fentry->k];
+                               continue;
+
+                       case BPF_LDX|BPF_MEM:
+                               X = mem[fentry->k];
+                               continue;
+
+                       case BPF_MISC|BPF_TAX:
+                               X = A;
+                               continue;
+
+                       case BPF_MISC|BPF_TXA:
+                               A = X;
+                               continue;
+
+                       case BPF_RET|BPF_K:
+                               return ((unsigned int)fentry->k);
+
+                       case BPF_RET|BPF_A:
+                               return ((unsigned int)A);
+
+                       case BPF_ST:
+                               mem[fentry->k] = A;
+                               continue;
+
+                       case BPF_STX:
+                               mem[fentry->k] = X;
+                               continue;
+
+
+
+                       default:
+                               /* Invalid instruction counts as RET */
+                               return (0);
+               }
+       }
+
+       printk(KERN_ERR "Filter ruleset ran off the end.\n");
+       return (0);
+}
+
+/*
+ * Check the user's filter code. If we let some ugly
+ * filter code slip through kaboom!
+ */
+
+int sk_chk_filter(struct sock_filter *filter, int flen)
+{
+       struct sock_filter *ftest;
+        int pc;
+
+       /*
+        * Check the filter code now.
+        */
+       for(pc = 0; pc < flen; pc++)
+       {
+               /*
+                 *     All jumps are forward as they are not signed
+                 */
+                 
+                ftest = &filter[pc];
+               if(BPF_CLASS(ftest->code) == BPF_JMP)
+               {       
+                       /*
+                        *      But they mustn't jump off the end.
+                        */
+                       if(BPF_OP(ftest->code) == BPF_JA)
+                       {
+                               if(pc + ftest->k + 1>= (unsigned)flen)
+                                       return (-EINVAL);
+                       }
+                        else
+                       {
+                               /*
+                                *      For conditionals both must be safe
+                                */
+                               if(pc + ftest->jt +1 >= flen || pc + ftest->jf +1 >= flen)
+                                       return (-EINVAL);
+                       }
+                }
+
+                /*
+                 *     Check that memory operations use valid addresses.
+                 */
+                 
+                if(ftest->k <0 || ftest->k >= BPF_MEMWORDS)
+                {
+                       /*
+                        *      But it might not be a memory operation...
+                        */
+                        
+                       if (BPF_CLASS(ftest->code) == BPF_ST)
+                               return -EINVAL;
+                       if((BPF_CLASS(ftest->code) == BPF_LD) && 
+                               (BPF_MODE(ftest->code) == BPF_MEM))
+                                       return (-EINVAL);
+               }
+        }
+
+       /*
+        *      The program must end with a return. We don't care where they
+        *      jumped within the script (its always forwards) but in the
+        *      end they _will_ hit this.
+        */
+        
+        return (BPF_CLASS(filter[flen - 1].code) == BPF_RET);
+}
+
+/*
+ * Attach the user's filter code. We first run some sanity checks on
+ * it to make sure it does not explode on us later.
+ */
+
+int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
+{
+       struct sock_filter *fp, *old_filter; 
+       int fsize = sizeof(struct sock_filter) * fprog->len;
+       int err;
+
+       /* Make sure new filter is there and in the right amounts. */
+        if(fprog->filter == NULL || fprog->len == 0 || fsize > BPF_MAXINSNS)
+                return (-EINVAL);
+
+       if((err = sk_chk_filter(fprog->filter, fprog->len)))
+       {
+               /* If existing filter, remove it first */
+               if(sk->filter)
+               {
+                       old_filter = sk->filter_data;
+                       kfree_s(old_filter, (sizeof(old_filter) * sk->filter));
+                       sk->filter_data = NULL;
+               }
+
+               fp = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+               if(fp == NULL)
+                       return (-ENOMEM);
+
+               memset(fp,0,sizeof(*fp));
+               memcpy(fp, fprog->filter, fsize);       /* Copy instructions */
+
+               sk->filter = fprog->len;        /* Number of filter blocks */
+               sk->filter_data = fp;           /* Filter instructions */
+       }
+
+       return (err);
+}
+#endif /* CONFIG_FILTER */
index 7254748875ab2d18096446208f56abedfcebaa8b..56f28cdf24fccfffaf15a88558ec4a0a43a7052a 100644 (file)
@@ -76,6 +76,7 @@
  *              Steve Whitehouse:       Added various other default routines
  *                                      common to several socket families.
  *              Chris Evans     :       Call suser() check last on F_SETOWN
+ *             Jay Schulist    :       Added SO_ATTACH_FILTER and SO_DETACH_FILTER.
  *
  * To Fix:
  *
 #include <net/icmp.h>
 #include <linux/ipsec.h>
 
+#ifdef CONFIG_FILTER
+#include <linux/filter.h>
+#endif
+
 #define min(a,b)       ((a)<(b)?(a):(b))
 
 /* Run time adjustable parameters. */
@@ -147,6 +152,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
        struct linger ling;
        struct ifreq req;
        int ret = 0;
+
+#ifdef CONFIG_FILTER
+       struct sock_fprog fprog;
+#endif
        
        /*
         *      Options without arguments
@@ -278,48 +287,6 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        break;
                        
                        
-#ifdef CONFIG_NET_SECURITY                     
-               /*
-                *      FIXME: make these error things that are not
-                *      available!
-                */
-                
-               case SO_SECURITY_AUTHENTICATION:
-                       if(val<=IPSEC_LEVEL_DEFAULT)
-                       {
-                               sk->authentication=val;
-                               return 0;
-                       }
-                       if(net_families[sock->ops->family]->authentication)
-                               sk->authentication=val;
-                       else
-                               return -EINVAL;
-                       break;
-                       
-               case SO_SECURITY_ENCRYPTION_TRANSPORT:
-                       if(val<=IPSEC_LEVEL_DEFAULT)
-                       {
-                               sk->encryption=val;
-                               return 0;
-                       }
-                       if(net_families[sock->ops->family]->encryption)
-                               sk->encryption = val;
-                       else
-                               return -EINVAL;
-                       break;
-                       
-               case SO_SECURITY_ENCRYPTION_NETWORK:
-                       if(val<=IPSEC_LEVEL_DEFAULT)
-                       {
-                               sk->encrypt_net=val;
-                               return 0;
-                       }
-                       if(net_families[sock->ops->family]->encrypt_net)
-                               sk->encrypt_net = val;
-                       else
-                               return -EINVAL;
-                       break;
-#endif
                case SO_BINDTODEVICE:
                        /* Bind this socket to a particular device like "eth0",
                         * as specified in an ifreq structure. If the device
@@ -359,6 +326,33 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        }
                        return 0;
 
+#ifdef CONFIG_FILTER
+               case SO_ATTACH_FILTER:
+                       if(optlen < sizeof(struct sock_fprog))
+                               return -EINVAL;
+
+                       if(copy_from_user(&fprog, optval, sizeof(fprog)))
+                       {
+                               ret = -EFAULT;
+                               break;
+                       }
+
+                       ret = sk_attach_filter(&fprog, sk);
+                       break;
+
+               case SO_DETACH_FILTER:
+                        if(sk->filter)
+                       {
+                               fprog.filter = sk->filter_data;
+                               kfree_s(fprog.filter, (sizeof(fprog.filter) * sk->filter));
+                               sk->filter_data = NULL;
+                               sk->filter = 0;
+                               return 0;
+                       }
+                       else
+                               return -EINVAL;
+                       break;
+#endif
 
                /* We implement the SO_SNDLOWAT etc to
                   not be settable (1003.1g 5.3) */
index 8f3e70cad34387fb5c688ad24b89a984ddbc1b71..de0a3225fdbd74bfabbd83ecd5e822f85a38fe1f 100644 (file)
@@ -120,6 +120,7 @@ extern __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *
        for_nexthops(fi) {
                if (nh->nh_oif != onh->nh_oif ||
                    nh->nh_gw  != onh->nh_gw ||
+                   nh->nh_scope != onh->nh_scope ||
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
                    nh->nh_weight != onh->nh_weight ||
 #endif
index 040c45a29d6eeb8cd30158c22a7c926c748fe144..947f0d352c1d2d566a2dc5bb08e1fc1b93d14957 100644 (file)
@@ -184,7 +184,8 @@ int ip_forward(struct sk_buff *skb)
                                {
 #endif
                                maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
-                               if (fw_res = ip_fw_masq_icmp(&skb, maddr) < 0) {
+                               fw_res = ip_fw_masq_icmp(&skb, maddr);
+                               if (fw_res < 0) {
                                        kfree_skb(skb, FREE_READ);
                                        return -1;
                                }
index 81c53edda4d94ecef7456f984aa6b3309b5b3e11..d9f24006d6d7d1882e626f4328d6eec05a9bc213 100644 (file)
@@ -315,7 +315,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
                return -EINVAL;
 
        /* Only superuser is allowed to send multicasts */
-       if (!suser() && nladdr->nl_groups)
+       if (nladdr->nl_groups && !suser())
                return -EPERM;
 
        sk->protinfo.af_netlink.dst_pid = nladdr->nl_pid;
index dfc3c9db1ae63dac32a27d7f158f746206e4deef..2b380937d4704b54bd289b48f7ba6c49a5641185 100644 (file)
@@ -44,6 +44,8 @@ extern struct net_proto_family inet_family_ops;
 
 #endif
 
+#include <linux/filter.h>
+
 #include <linux/rtnetlink.h>
 
 #include <net/scm.h>
@@ -78,6 +80,13 @@ EXPORT_SYMBOL(sock_register);
 EXPORT_SYMBOL(sock_unregister);
 
 /* Socket layer support routines */
+EXPORT_SYMBOL(sk_alloc);
+EXPORT_SYMBOL(sk_free);
+
+#ifdef CONFIG_FILTER
+EXPORT_SYMBOL(sk_run_filter);
+#endif
+
 EXPORT_SYMBOL(memcpy_fromiovec);
 EXPORT_SYMBOL(sock_create);
 EXPORT_SYMBOL(sock_alloc);
@@ -86,8 +95,6 @@ EXPORT_SYMBOL(sock_setsockopt);
 EXPORT_SYMBOL(sock_getsockopt);
 EXPORT_SYMBOL(sock_sendmsg);
 EXPORT_SYMBOL(sock_recvmsg);
-EXPORT_SYMBOL(sk_alloc);
-EXPORT_SYMBOL(sk_free);
 EXPORT_SYMBOL(sock_wake_async);
 EXPORT_SYMBOL(sock_alloc_send_skb);
 EXPORT_SYMBOL(sock_init_data);
index 42babf6bb3cf4aeeddc82edb059e76b2839707e3..246239fb31c52cb76095ae4e57be16d7a16c0607 100644 (file)
@@ -395,7 +395,7 @@ __rpc_execute(struct rpc_task *task)
 
                        /* When the task received a signal, remove from
                         * any queues etc, and make runnable again. */
-                       if (signalled())
+                       if (0 && signalled())
                                __rpc_wake_up(task);
 
                        dprintk("RPC: %4d sync task resuming\n",
@@ -521,6 +521,7 @@ rpc_allocate(unsigned int flags, unsigned int size)
                if (flags & RPC_TASK_ASYNC)
                        return NULL;
                current->timeout = jiffies + (HZ >> 4);
+               current->state = TASK_INTERRUPTIBLE;
                schedule();
        } while (!signalled());
 
index 2897643ce9397f12e29d577053bba8488441f847..3b893bbb7b6d187b551be254145248f21e4376ef 100644 (file)
@@ -445,7 +445,7 @@ function l_int () {
 
                        # Semantics of + and ? in GNU expr changed, so
                        # we avoid them:
-                       if expr "$answer" : '0$\|\(-[1-9]\|[1-9]\)[0-9]*$' >/dev/null
+                       if expr "$answer" : '0$\|\(-[1-9]\|[0-9]\)[0-9]*$' >/dev/null
                        then
                                eval $2="$answer"
                        else
index 41b370f434d31b17a53c3873c3f9b90731ab32ff..7b160b8dc147900bd7beb7c30932a54e807da57b 100644 (file)
@@ -101,7 +101,7 @@ void fix_choice_cond()
   struct condition * cond;
   struct condition * cond2;
   struct kconfig * cfg;
-  char tmpbuf[10];
+  char tmpbuf[255];
 
   for(cfg = config;cfg != NULL; cfg = cfg->next)
     {